1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.Unpooled;
20 import io.netty.channel.ChannelHandler;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.channel.ChannelOption;
23 import io.netty.channel.ChannelPromise;
24 import io.netty.channel.socket.DatagramPacket;
25 import io.netty.util.AttributeKey;
26 import io.netty.util.CharsetUtil;
27 import io.netty.util.internal.logging.InternalLogger;
28 import io.netty.util.internal.logging.InternalLoggerFactory;
29 import org.jetbrains.annotations.Nullable;
30
31 import java.net.InetSocketAddress;
32 import java.net.SocketAddress;
33 import java.nio.ByteBuffer;
34 import java.util.Map;
35 import java.util.concurrent.Executor;
36 import java.util.function.Consumer;
37 import java.util.function.Function;
38
39
40
41
42 final class QuicheQuicServerCodec extends QuicheQuicCodec {
43 private static final InternalLogger LOGGER = InternalLoggerFactory.getInstance(QuicheQuicServerCodec.class);
44 private final Function<QuicChannel, ? extends QuicSslEngine> sslEngineProvider;
45 private final Executor sslTaskExecutor;
46 private final QuicConnectionIdGenerator connectionIdAddressGenerator;
47 private final QuicResetTokenGenerator resetTokenGenerator;
48 private final QuicTokenHandler tokenHandler;
49 private final ChannelHandler handler;
50 private final Map.Entry<ChannelOption<?>, Object>[] optionsArray;
51 private final Map.Entry<AttributeKey<?>, Object>[] attrsArray;
52 private final ChannelHandler streamHandler;
53 private final Map.Entry<ChannelOption<?>, Object>[] streamOptionsArray;
54 private final Map.Entry<AttributeKey<?>, Object>[] streamAttrsArray;
55 private ByteBuf mintTokenBuffer;
56 private ByteBuf connIdBuffer;
57
58 QuicheQuicServerCodec(QuicheConfig config,
59 int localConnIdLength,
60 QuicTokenHandler tokenHandler,
61 QuicConnectionIdGenerator connectionIdAddressGenerator,
62 QuicResetTokenGenerator resetTokenGenerator,
63 FlushStrategy flushStrategy,
64 Function<QuicChannel, ? extends QuicSslEngine> sslEngineProvider,
65 Executor sslTaskExecutor,
66 ChannelHandler handler,
67 Map.Entry<ChannelOption<?>, Object>[] optionsArray,
68 Map.Entry<AttributeKey<?>, Object>[] attrsArray,
69 ChannelHandler streamHandler,
70 Map.Entry<ChannelOption<?>, Object>[] streamOptionsArray,
71 Map.Entry<AttributeKey<?>, Object>[] streamAttrsArray) {
72 super(config, localConnIdLength, flushStrategy);
73 this.tokenHandler = tokenHandler;
74 this.connectionIdAddressGenerator = connectionIdAddressGenerator;
75 this.resetTokenGenerator = resetTokenGenerator;
76 this.sslEngineProvider = sslEngineProvider;
77 this.sslTaskExecutor = sslTaskExecutor;
78 this.handler = handler;
79 this.optionsArray = optionsArray;
80 this.attrsArray = attrsArray;
81 this.streamHandler = streamHandler;
82 this.streamOptionsArray = streamOptionsArray;
83 this.streamAttrsArray = streamAttrsArray;
84 }
85
86 @Override
87 protected void handlerAdded(ChannelHandlerContext ctx, int localConnIdLength) {
88 connIdBuffer = Quiche.allocateNativeOrder(localConnIdLength);
89 mintTokenBuffer = Unpooled.directBuffer(tokenHandler.maxTokenLength());
90 }
91
92 @Override
93 public void handlerRemoved(ChannelHandlerContext ctx) {
94 super.handlerRemoved(ctx);
95 if (connIdBuffer != null) {
96 connIdBuffer.release();
97 }
98 if (mintTokenBuffer != null) {
99 mintTokenBuffer.release();
100 }
101 }
102
103 @Override
104 @Nullable
105 protected QuicheQuicChannel quicPacketRead(ChannelHandlerContext ctx, InetSocketAddress sender,
106 InetSocketAddress recipient, QuicPacketType type, long version,
107 ByteBuf scid, ByteBuf dcid, ByteBuf token,
108 ByteBuf senderSockaddrMemory, ByteBuf recipientSockaddrMemory,
109 Consumer<QuicheQuicChannel> freeTask, int localConnIdLength,
110 QuicheConfig config)
111 throws Exception {
112 ByteBuffer dcidByteBuffer = dcid.internalNioBuffer(dcid.readerIndex(), dcid.readableBytes());
113 QuicheQuicChannel channel = getChannel(dcidByteBuffer);
114 if (channel == null && type == QuicPacketType.INITIAL) {
115
116
117 return handleServer(ctx, sender, recipient, type, version, scid, dcid, token,
118 senderSockaddrMemory, recipientSockaddrMemory, freeTask, localConnIdLength, config);
119 }
120 return channel;
121 }
122
123 private static void writePacket(ChannelHandlerContext ctx, int res, ByteBuf buffer, InetSocketAddress sender)
124 throws Exception {
125 if (res < 0) {
126 buffer.release();
127 if (res != Quiche.QUICHE_ERR_DONE) {
128 throw Quiche.convertToException(res);
129 }
130 } else {
131 ctx.writeAndFlush(new DatagramPacket(buffer.writerIndex(buffer.writerIndex() + res), sender));
132 }
133 }
134
135 @Nullable
136 private QuicheQuicChannel handleServer(ChannelHandlerContext ctx, InetSocketAddress sender,
137 InetSocketAddress recipient,
138 @SuppressWarnings("unused") QuicPacketType type, long version,
139 ByteBuf scid, ByteBuf dcid, ByteBuf token,
140 ByteBuf senderSockaddrMemory, ByteBuf recipientSockaddrMemory,
141 Consumer<QuicheQuicChannel> freeTask, int localConnIdLength,
142 QuicheConfig config) throws Exception {
143
144 if (!Quiche.quiche_version_is_supported((int) version)) {
145
146 ByteBuf out = ctx.alloc().directBuffer(Quic.MAX_DATAGRAM_SIZE);
147
148 int res = Quiche.quiche_negotiate_version(
149 Quiche.readerMemoryAddress(scid), scid.readableBytes(),
150 Quiche.readerMemoryAddress(dcid), dcid.readableBytes(),
151 Quiche.writerMemoryAddress(out), out.writableBytes());
152 writePacket(ctx, res, out, sender);
153 return null;
154 }
155
156 final int offset;
157 boolean noToken = false;
158 if (!token.isReadable()) {
159
160 mintTokenBuffer.clear();
161 connIdBuffer.clear();
162
163
164 if (tokenHandler.writeToken(mintTokenBuffer, dcid, sender)) {
165 ByteBuffer connId = connectionIdAddressGenerator.newId(
166 scid.internalNioBuffer(scid.readerIndex(), scid.readableBytes()),
167 dcid.internalNioBuffer(dcid.readerIndex(), dcid.readableBytes()),
168 localConnIdLength);
169 connIdBuffer.writeBytes(connId);
170
171 ByteBuf out = ctx.alloc().directBuffer(Quic.MAX_DATAGRAM_SIZE);
172 int written = Quiche.quiche_retry(
173 Quiche.readerMemoryAddress(scid), scid.readableBytes(),
174 Quiche.readerMemoryAddress(dcid), dcid.readableBytes(),
175 Quiche.readerMemoryAddress(connIdBuffer), connIdBuffer.readableBytes(),
176 Quiche.readerMemoryAddress(mintTokenBuffer), mintTokenBuffer.readableBytes(),
177
178 (int) version,
179 Quiche.writerMemoryAddress(out), out.writableBytes());
180
181 writePacket(ctx, written, out, sender);
182 return null;
183 }
184 offset = 0;
185 noToken = true;
186 } else {
187
188
189
190 offset = tokenHandler.validateToken(token.slice(), sender);
191 if (offset == -1) {
192 if (LOGGER.isDebugEnabled()) {
193 LOGGER.debug("invalid token: {}", token.toString(CharsetUtil.US_ASCII));
194 }
195 return null;
196 }
197 }
198
199 final ByteBuffer key;
200 final long scidAddr;
201 final int scidLen;
202 final long ocidAddr;
203 final int ocidLen;
204
205 if (noToken) {
206 connIdBuffer.clear();
207 key = connectionIdAddressGenerator.newId(
208 scid.internalNioBuffer(scid.readerIndex(), scid.readableBytes()),
209 dcid.internalNioBuffer(dcid.readerIndex(), dcid.readableBytes()),
210 localConnIdLength);
211 connIdBuffer.writeBytes(key.duplicate());
212 scidAddr = Quiche.readerMemoryAddress(connIdBuffer);
213 scidLen = localConnIdLength;
214 ocidAddr = -1;
215 ocidLen = -1;
216
217 QuicheQuicChannel existingChannel = getChannel(key);
218 if (existingChannel != null) {
219 return existingChannel;
220 }
221 } else {
222 scidAddr = Quiche.readerMemoryAddress(dcid);
223 scidLen = localConnIdLength;
224 ocidLen = token.readableBytes() - offset;
225 ocidAddr = Quiche.memoryAddress(token, offset, ocidLen);
226
227 byte[] bytes = new byte[localConnIdLength];
228 dcid.getBytes(dcid.readerIndex(), bytes);
229 key = ByteBuffer.wrap(bytes);
230 }
231 QuicheQuicChannel channel = QuicheQuicChannel.forServer(
232 ctx.channel(), key, recipient, sender, config.isDatagramSupported(),
233 streamHandler, streamOptionsArray, streamAttrsArray, freeTask, sslTaskExecutor,
234 connectionIdAddressGenerator, resetTokenGenerator);
235
236
237 byte[] originalId = new byte[dcid.readableBytes()];
238 dcid.getBytes(dcid.readerIndex(), originalId);
239 channel.sourceConnectionIds().add(ByteBuffer.wrap(originalId));
240
241 Quic.setupChannel(channel, optionsArray, attrsArray, handler, LOGGER);
242 QuicSslEngine engine = sslEngineProvider.apply(channel);
243 if (!(engine instanceof QuicheQuicSslEngine)) {
244 channel.unsafe().closeForcibly();
245 throw new IllegalArgumentException("QuicSslEngine is not of type "
246 + QuicheQuicSslEngine.class.getSimpleName());
247 }
248 if (engine.getUseClientMode()) {
249 channel.unsafe().closeForcibly();
250 throw new IllegalArgumentException("QuicSslEngine is not created in server mode");
251 }
252
253 QuicheQuicSslEngine quicSslEngine = (QuicheQuicSslEngine) engine;
254 QuicheQuicConnection connection = quicSslEngine.createConnection(ssl -> {
255 ByteBuffer localAddrMemory =
256 recipientSockaddrMemory.internalNioBuffer(0, recipientSockaddrMemory.capacity());
257 int localLen = SockaddrIn.setAddress(localAddrMemory, recipient);
258
259 ByteBuffer peerAddrMemory = senderSockaddrMemory.internalNioBuffer(0, senderSockaddrMemory.capacity());
260 int peerLen = SockaddrIn.setAddress(peerAddrMemory, sender);
261 return Quiche.quiche_conn_new_with_tls(scidAddr, scidLen, ocidAddr, ocidLen,
262 Quiche.memoryAddressWithPosition(localAddrMemory), localLen,
263 Quiche.memoryAddressWithPosition(peerAddrMemory), peerLen,
264 config.nativeAddress(), ssl, true);
265 });
266 if (connection == null) {
267 channel.unsafe().closeForcibly();
268 LOGGER.debug("quiche_accept failed");
269 return null;
270 }
271
272 channel.attachQuicheConnection(connection);
273
274 addChannel(channel);
275
276 ctx.channel().eventLoop().register(channel);
277 return channel;
278 }
279
280 @Override
281 protected void connectQuicChannel(QuicheQuicChannel channel, SocketAddress remoteAddress,
282 SocketAddress localAddress, ByteBuf senderSockaddrMemory,
283 ByteBuf recipientSockaddrMemory, Consumer<QuicheQuicChannel> freeTask,
284 int localConnIdLength, QuicheConfig config, ChannelPromise promise) {
285 promise.setFailure(new UnsupportedOperationException());
286 }
287 }