@@ -239,39 +239,83 @@ func (l *Listener) listen() {
239
239
func (l * Listener ) handleDatagram (m * datagram , conns map [string ]* Conn ) {
240
240
dstConnID , ok := dstConnIDForDatagram (m .b )
241
241
if ! ok {
242
+ m .recycle ()
242
243
return
243
244
}
244
245
c := conns [string (dstConnID )]
245
246
if c == nil {
246
- if getPacketType (m .b ) != packetTypeInitial {
247
- // This packet isn't trying to create a new connection.
248
- // It might be associated with some connection we've lost state for.
249
- // TODO: Send a stateless reset when appropriate.
250
- // https://www.rfc-editor.org/rfc/rfc9000.html#section-10.3
251
- return
252
- }
253
- var now time.Time
254
- if l .testHooks != nil {
255
- now = l .testHooks .timeNow ()
256
- } else {
257
- now = time .Now ()
258
- }
259
- var err error
260
- c , err = l .newConn (now , serverSide , dstConnID , m .addr )
261
- if err != nil {
262
- // The accept queue is probably full.
263
- // We could send a CONNECTION_CLOSE to the peer to reject the connection.
264
- // Currently, we just drop the datagram.
265
- // https://www.rfc-editor.org/rfc/rfc9000.html#section-5.2.2-5
266
- return
267
- }
247
+ // TODO: Move this branch into a separate goroutine to avoid blocking
248
+ // the listener while processing packets.
249
+ l .handleUnknownDestinationDatagram (m )
250
+ return
268
251
}
269
252
270
253
// TODO: This can block the listener while waiting for the conn to accept the dgram.
271
254
// Think about buffering between the receive loop and the conn.
272
255
c .sendMsg (m )
273
256
}
274
257
258
+ func (l * Listener ) handleUnknownDestinationDatagram (m * datagram ) {
259
+ defer func () {
260
+ if m != nil {
261
+ m .recycle ()
262
+ }
263
+ }()
264
+ if len (m .b ) < minimumClientInitialDatagramSize {
265
+ return
266
+ }
267
+ p , ok := parseGenericLongHeaderPacket (m .b )
268
+ if ! ok {
269
+ // Not a long header packet, or not parseable.
270
+ // Short header (1-RTT) packets don't contain enough information
271
+ // to do anything useful with if we don't recognize the
272
+ // connection ID.
273
+ return
274
+ }
275
+
276
+ switch p .version {
277
+ case quicVersion1 :
278
+ case 0 :
279
+ // Version Negotiation for an unknown connection.
280
+ return
281
+ default :
282
+ // Unknown version.
283
+ l .sendVersionNegotiation (p , m .addr )
284
+ return
285
+ }
286
+ if getPacketType (m .b ) != packetTypeInitial {
287
+ // This packet isn't trying to create a new connection.
288
+ // It might be associated with some connection we've lost state for.
289
+ // TODO: Send a stateless reset when appropriate.
290
+ // https://www.rfc-editor.org/rfc/rfc9000.html#section-10.3
291
+ return
292
+ }
293
+ var now time.Time
294
+ if l .testHooks != nil {
295
+ now = l .testHooks .timeNow ()
296
+ } else {
297
+ now = time .Now ()
298
+ }
299
+ var err error
300
+ c , err := l .newConn (now , serverSide , p .dstConnID , m .addr )
301
+ if err != nil {
302
+ // The accept queue is probably full.
303
+ // We could send a CONNECTION_CLOSE to the peer to reject the connection.
304
+ // Currently, we just drop the datagram.
305
+ // https://www.rfc-editor.org/rfc/rfc9000.html#section-5.2.2-5
306
+ return
307
+ }
308
+ c .sendMsg (m )
309
+ m = nil // don't recycle, sendMsg takes ownership
310
+ }
311
+
312
+ func (l * Listener ) sendVersionNegotiation (p genericLongPacket , addr netip.AddrPort ) {
313
+ m := newDatagram ()
314
+ m .b = appendVersionNegotiation (m .b [:0 ], p .srcConnID , p .dstConnID , quicVersion1 )
315
+ l .sendDatagram (m .b , addr )
316
+ m .recycle ()
317
+ }
318
+
275
319
func (l * Listener ) sendDatagram (p []byte , addr netip.AddrPort ) error {
276
320
_ , err := l .udpConn .WriteToUDPAddrPort (p , addr )
277
321
return err
0 commit comments