@@ -239,39 +239,83 @@ func (l *Listener) listen() {
239239func (l * Listener ) handleDatagram (m * datagram , conns map [string ]* Conn ) {
240240 dstConnID , ok := dstConnIDForDatagram (m .b )
241241 if ! ok {
242+ m .recycle ()
242243 return
243244 }
244245 c := conns [string (dstConnID )]
245246 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
268251 }
269252
270253 // TODO: This can block the listener while waiting for the conn to accept the dgram.
271254 // Think about buffering between the receive loop and the conn.
272255 c .sendMsg (m )
273256}
274257
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+
275319func (l * Listener ) sendDatagram (p []byte , addr netip.AddrPort ) error {
276320 _ , err := l .udpConn .WriteToUDPAddrPort (p , addr )
277321 return err
0 commit comments