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