@@ -22,11 +22,11 @@ import (
22
22
//
23
23
// Multiple goroutines may invoke methods on an Endpoint simultaneously.
24
24
type Endpoint struct {
25
- config * Config
26
- udpConn udpConn
27
- testHooks endpointTestHooks
28
- resetGen statelessResetTokenGenerator
29
- retry retryState
25
+ config * Config
26
+ packetConn packetConn
27
+ testHooks endpointTestHooks
28
+ resetGen statelessResetTokenGenerator
29
+ retry retryState
30
30
31
31
acceptQueue queue [* Conn ] // new inbound connections
32
32
connsMap connsMap // only accessed by the listen loop
@@ -42,13 +42,12 @@ type endpointTestHooks interface {
42
42
newConn (c * Conn )
43
43
}
44
44
45
- // A udpConn is a UDP connection.
46
- // It is implemented by net.UDPConn.
47
- type udpConn interface {
45
+ // A packetConn is the interface to sending and receiving UDP packets.
46
+ type packetConn interface {
48
47
Close () error
49
- LocalAddr () net. Addr
50
- ReadMsgUDPAddrPort ( b , control [] byte ) ( n , controln , flags int , _ netip. AddrPort , _ error )
51
- WriteToUDPAddrPort ( b [] byte , addr netip. AddrPort ) ( int , error )
48
+ LocalAddr () netip. AddrPort
49
+ Read ( f func ( * datagram ) )
50
+ Write ( datagram ) error
52
51
}
53
52
54
53
// Listen listens on a local network address.
@@ -65,13 +64,17 @@ func Listen(network, address string, config *Config) (*Endpoint, error) {
65
64
if err != nil {
66
65
return nil , err
67
66
}
68
- return newEndpoint (udpConn , config , nil )
67
+ pc , err := newNetUDPConn (udpConn )
68
+ if err != nil {
69
+ return nil , err
70
+ }
71
+ return newEndpoint (pc , config , nil )
69
72
}
70
73
71
- func newEndpoint (udpConn udpConn , config * Config , hooks endpointTestHooks ) (* Endpoint , error ) {
74
+ func newEndpoint (pc packetConn , config * Config , hooks endpointTestHooks ) (* Endpoint , error ) {
72
75
e := & Endpoint {
73
76
config : config ,
74
- udpConn : udpConn ,
77
+ packetConn : pc ,
75
78
testHooks : hooks ,
76
79
conns : make (map [* Conn ]struct {}),
77
80
acceptQueue : newQueue [* Conn ](),
@@ -90,8 +93,7 @@ func newEndpoint(udpConn udpConn, config *Config, hooks endpointTestHooks) (*End
90
93
91
94
// LocalAddr returns the local network address.
92
95
func (e * Endpoint ) LocalAddr () netip.AddrPort {
93
- a , _ := e .udpConn .LocalAddr ().(* net.UDPAddr )
94
- return a .AddrPort ()
96
+ return e .packetConn .LocalAddr ()
95
97
}
96
98
97
99
// Close closes the Endpoint.
@@ -114,7 +116,7 @@ func (e *Endpoint) Close(ctx context.Context) error {
114
116
conns = append (conns , c )
115
117
}
116
118
if len (e .conns ) == 0 {
117
- e .udpConn .Close ()
119
+ e .packetConn .Close ()
118
120
}
119
121
}
120
122
e .connsMu .Unlock ()
@@ -200,34 +202,18 @@ func (e *Endpoint) connDrained(c *Conn) {
200
202
defer e .connsMu .Unlock ()
201
203
delete (e .conns , c )
202
204
if e .closing && len (e .conns ) == 0 {
203
- e .udpConn .Close ()
205
+ e .packetConn .Close ()
204
206
}
205
207
}
206
208
207
209
func (e * Endpoint ) listen () {
208
210
defer close (e .closec )
209
- for {
210
- m := newDatagram ()
211
- // TODO: Read and process the ECN (explicit congestion notification) field.
212
- // https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-13.4
213
- n , _ , _ , addr , err := e .udpConn .ReadMsgUDPAddrPort (m .b , nil )
214
- if err != nil {
215
- // The user has probably closed the endpoint.
216
- // We currently don't surface errors from other causes;
217
- // we could check to see if the endpoint has been closed and
218
- // record the unexpected error if it has not.
219
- return
220
- }
221
- if n == 0 {
222
- continue
223
- }
211
+ e .packetConn .Read (func (m * datagram ) {
224
212
if e .connsMap .updateNeeded .Load () {
225
213
e .connsMap .applyUpdates ()
226
214
}
227
- m .addr = addr
228
- m .b = m .b [:n ]
229
215
e .handleDatagram (m )
230
- }
216
+ })
231
217
}
232
218
233
219
func (e * Endpoint ) handleDatagram (m * datagram ) {
@@ -277,7 +263,7 @@ func (e *Endpoint) handleUnknownDestinationDatagram(m *datagram) {
277
263
// If this is a 1-RTT packet, there's nothing productive we can do with it.
278
264
// Send a stateless reset if possible.
279
265
if ! isLongHeader (m .b [0 ]) {
280
- e .maybeSendStatelessReset (m .b , m .addr )
266
+ e .maybeSendStatelessReset (m .b , m .peerAddr )
281
267
return
282
268
}
283
269
p , ok := parseGenericLongHeaderPacket (m .b )
@@ -291,7 +277,7 @@ func (e *Endpoint) handleUnknownDestinationDatagram(m *datagram) {
291
277
return
292
278
default :
293
279
// Unknown version.
294
- e .sendVersionNegotiation (p , m .addr )
280
+ e .sendVersionNegotiation (p , m .peerAddr )
295
281
return
296
282
}
297
283
if getPacketType (m .b ) != packetTypeInitial {
@@ -309,15 +295,15 @@ func (e *Endpoint) handleUnknownDestinationDatagram(m *datagram) {
309
295
if e .config .RequireAddressValidation {
310
296
var ok bool
311
297
cids .retrySrcConnID = p .dstConnID
312
- cids .originalDstConnID , ok = e .validateInitialAddress (now , p , m .addr )
298
+ cids .originalDstConnID , ok = e .validateInitialAddress (now , p , m .peerAddr )
313
299
if ! ok {
314
300
return
315
301
}
316
302
} else {
317
303
cids .originalDstConnID = p .dstConnID
318
304
}
319
305
var err error
320
- c , err := e .newConn (now , serverSide , cids , m .addr )
306
+ c , err := e .newConn (now , serverSide , cids , m .peerAddr )
321
307
if err != nil {
322
308
// The accept queue is probably full.
323
309
// We could send a CONNECTION_CLOSE to the peer to reject the connection.
@@ -329,7 +315,7 @@ func (e *Endpoint) handleUnknownDestinationDatagram(m *datagram) {
329
315
m = nil // don't recycle, sendMsg takes ownership
330
316
}
331
317
332
- func (e * Endpoint ) maybeSendStatelessReset (b []byte , addr netip.AddrPort ) {
318
+ func (e * Endpoint ) maybeSendStatelessReset (b []byte , peerAddr netip.AddrPort ) {
333
319
if ! e .resetGen .canReset {
334
320
// Config.StatelessResetKey isn't set, so we don't send stateless resets.
335
321
return
@@ -370,17 +356,21 @@ func (e *Endpoint) maybeSendStatelessReset(b []byte, addr netip.AddrPort) {
370
356
b [0 ] &^= headerFormLong // clear long header bit
371
357
b [0 ] |= fixedBit // set fixed bit
372
358
copy (b [len (b )- statelessResetTokenLen :], token [:])
373
- e .sendDatagram (b , addr )
359
+ e .sendDatagram (datagram {
360
+ b : b ,
361
+ peerAddr : peerAddr ,
362
+ })
374
363
}
375
364
376
- func (e * Endpoint ) sendVersionNegotiation (p genericLongPacket , addr netip.AddrPort ) {
365
+ func (e * Endpoint ) sendVersionNegotiation (p genericLongPacket , peerAddr netip.AddrPort ) {
377
366
m := newDatagram ()
378
367
m .b = appendVersionNegotiation (m .b [:0 ], p .srcConnID , p .dstConnID , quicVersion1 )
379
- e .sendDatagram (m .b , addr )
368
+ m .peerAddr = peerAddr
369
+ e .sendDatagram (* m )
380
370
m .recycle ()
381
371
}
382
372
383
- func (e * Endpoint ) sendConnectionClose (in genericLongPacket , addr netip.AddrPort , code transportError ) {
373
+ func (e * Endpoint ) sendConnectionClose (in genericLongPacket , peerAddr netip.AddrPort , code transportError ) {
384
374
keys := initialKeys (in .dstConnID , serverSide )
385
375
var w packetWriter
386
376
p := longPacket {
@@ -399,12 +389,14 @@ func (e *Endpoint) sendConnectionClose(in genericLongPacket, addr netip.AddrPort
399
389
if len (buf ) == 0 {
400
390
return
401
391
}
402
- e .sendDatagram (buf , addr )
392
+ e .sendDatagram (datagram {
393
+ b : buf ,
394
+ peerAddr : peerAddr ,
395
+ })
403
396
}
404
397
405
- func (e * Endpoint ) sendDatagram (p []byte , addr netip.AddrPort ) error {
406
- _ , err := e .udpConn .WriteToUDPAddrPort (p , addr )
407
- return err
398
+ func (e * Endpoint ) sendDatagram (dgram datagram ) error {
399
+ return e .packetConn .Write (dgram )
408
400
}
409
401
410
402
// A connsMap is an endpoint's mapping of conn ids and reset tokens to conns.
0 commit comments