Repository navigation
Expand file tree
/
Copy pathNativeTransferTest.java
More file actions
165 lines (154 loc) Β· 6.88 KB
/
Copy pathNativeTransferTest.java
File metadata and controls
165 lines (154 loc) Β· 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import dev.elide.bemo.transport.*;
import io.netty.bootstrap.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import java.net.InetSocketAddress;
import java.nio.file.*;
import java.util.concurrent.*;
public final class NativeTransferTest {
public static void main(String[] args) throws Exception {
TransportNative api = new BackendTransport(new FfmTransportNative(Path.of(args[0])));
verify(api, Files.readAllBytes(Path.of(args[1])), Files.readAllBytes(Path.of(args[2])));
}
public static void verify(TransportNative api, byte[] cert, byte[] key) throws Exception {
verify(api, cert, key, null);
}
public static void verify(
TransportNative api, byte[] cert, byte[] key, RecvByteBufAllocator allocator)
throws Exception {
try (NativeTlsContext serverTls = NativeTlsContext.server(api, cert, key, "http/1.1");
NativeTlsContext clientTls = NativeTlsContext.client(api, cert, "http/1.1")) {
transfer(api, null, null, allocator);
transfer(api, serverTls, clientTls, allocator);
}
}
private static byte payloadByte(int offset) {
return (byte) ((offset * 31) ^ (offset >>> 8) ^ (offset >>> 16));
}
private static void transfer(
TransportNative api,
NativeTlsContext serverTls,
NativeTlsContext clientTls,
RecvByteBufAllocator allocator)
throws Exception {
EventLoopGroup group =
new MultiThreadIoEventLoopGroup(
2, NativeIoHandler.newFactory(api, 0, 128, 16 * 1024 * 1024));
Channel server = null, client = null;
ByteBuf retained = null;
final int size = 2 * 1024 * 1024 + 17;
CompletableFuture<Void> complete = new CompletableFuture<>();
try {
server =
new ServerBootstrap()
.group(group)
.channel(NativeServerSocketChannel.class)
.childOption(ChannelOption.AUTO_READ, false)
.childOption(ChannelOption.RCVBUF_ALLOCATOR, allocator)
.childHandler(
new ChannelInitializer<NativeSocketChannel>() {
@Override
protected void initChannel(NativeSocketChannel channel) {
if (serverTls != null) channel.tls(serverTls, null);
channel
.pipeline()
.addLast(
new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext context) {
context.read();
}
@Override
public void channelRead(
ChannelHandlerContext context, Object message) {
context.writeAndFlush(message);
}
@Override
public void channelReadComplete(ChannelHandlerContext context) {
context.read();
}
@Override
public void exceptionCaught(
ChannelHandlerContext context, Throwable error) {
complete.completeExceptionally(error);
context.close();
}
});
}
})
.bind(new InetSocketAddress("127.0.0.1", 0))
.sync()
.channel();
client =
new Bootstrap()
.option(ChannelOption.RCVBUF_ALLOCATOR, allocator)
.group(group)
.channelFactory(
() -> {
NativeSocketChannel channel = new NativeSocketChannel();
if (clientTls != null) channel.tls(clientTls, "localhost");
return channel;
})
.handler(
new ChannelInboundHandlerAdapter() {
int offset;
@Override
public void channelRead(ChannelHandlerContext context, Object message) {
ByteBuf bytes = (ByteBuf) message;
try {
while (bytes.isReadable()) {
if (offset >= size || bytes.readByte() != payloadByte(offset++))
throw new AssertionError("Payload corruption at " + (offset - 1));
}
if (offset == size) complete.complete(null);
} catch (Throwable error) {
complete.completeExceptionally(error);
} finally {
bytes.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext context, Throwable error) {
complete.completeExceptionally(error);
context.close();
}
})
.connect(server.localAddress())
.sync()
.channel();
if (clientTls != null) ((NativeSocketChannel) client).handshakeFuture().sync();
ByteBuf payload;
if (clientTls == null) {
// More components than one gathered send may expose; do not count omitted views.
io.netty.buffer.CompositeByteBuf composite = client.alloc().compositeDirectBuffer(97);
for (int i = 0; i < 96; i++)
composite.addComponent(true, client.alloc().directBuffer(1, 1).writeByte(payloadByte(i)));
ByteBuf tail = client.alloc().directBuffer(size - 96, size - 96);
for (int i = 96; i < size; i++) tail.writeByte(payloadByte(i));
composite.addComponent(true, tail);
payload = composite;
} else {
payload = client.alloc().directBuffer(size, size);
for (int i = 0; i < size; i++) payload.writeByte(payloadByte(i));
}
retained = payload.retainedSlice(0, 17);
client.writeAndFlush(payload).sync();
complete.get(15, TimeUnit.SECONDS);
client.close().sync();
if (retained.refCnt() != 1)
throw new AssertionError("completed send retained native storage");
for (int i = 0; i < 17; i++) {
if (retained.getByte(i) != payloadByte(i))
throw new AssertionError("retained send storage corrupted");
}
System.out.println(
"Native multi-record transfer and manual read checks passed: "
+ (clientTls == null ? "TCP" : "TLS"));
} finally {
if (retained != null) retained.release();
if (client != null) client.close().syncUninterruptibly();
if (server != null) server.close().syncUninterruptibly();
group.shutdownGracefully(0, 5, TimeUnit.SECONDS).syncUninterruptibly();
}
}
}