@@ -19,6 +19,8 @@ type DatagramConn interface {
19
19
DatagramWriter
20
20
// Serve provides a server interface to process and handle incoming QUIC datagrams and demux their datagram v3 payloads.
21
21
Serve (context.Context ) error
22
+ // ID indicates connection index identifier
23
+ ID () uint8
22
24
}
23
25
24
26
// DatagramWriter provides the Muxer interface to create proper Datagrams when sending over a connection.
@@ -41,24 +43,30 @@ type QuicConnection interface {
41
43
42
44
type datagramConn struct {
43
45
conn QuicConnection
46
+ index uint8
44
47
sessionManager SessionManager
45
48
logger * zerolog.Logger
46
49
47
50
datagrams chan []byte
48
51
readErrors chan error
49
52
}
50
53
51
- func NewDatagramConn (conn QuicConnection , sessionManager SessionManager , logger * zerolog.Logger ) DatagramConn {
54
+ func NewDatagramConn (conn QuicConnection , sessionManager SessionManager , index uint8 , logger * zerolog.Logger ) DatagramConn {
52
55
log := logger .With ().Uint8 ("datagramVersion" , 3 ).Logger ()
53
56
return & datagramConn {
54
57
conn : conn ,
58
+ index : index ,
55
59
sessionManager : sessionManager ,
56
60
logger : & log ,
57
61
datagrams : make (chan []byte , demuxChanCapacity ),
58
62
readErrors : make (chan error , 2 ),
59
63
}
60
64
}
61
65
66
+ func (c datagramConn ) ID () uint8 {
67
+ return c .index
68
+ }
69
+
62
70
func (c * datagramConn ) SendUDPSessionDatagram (datagram []byte ) error {
63
71
return c .conn .SendDatagram (datagram )
64
72
}
@@ -163,9 +171,20 @@ func (c *datagramConn) Serve(ctx context.Context) error {
163
171
// This method handles new registrations of a session and the serve loop for the session.
164
172
func (c * datagramConn ) handleSessionRegistrationDatagram (ctx context.Context , datagram * UDPSessionRegistrationDatagram ) {
165
173
session , err := c .sessionManager .RegisterSession (datagram , c )
166
- if err != nil {
174
+ switch err {
175
+ case nil :
176
+ // Continue as normal
177
+ case ErrSessionAlreadyRegistered :
178
+ // Session is already registered and likely the response got lost
179
+ c .handleSessionAlreadyRegistered (datagram .RequestID )
180
+ return
181
+ case ErrSessionBoundToOtherConn :
182
+ // Session is already registered but to a different connection
183
+ c .handleSessionMigration (datagram .RequestID )
184
+ return
185
+ default :
167
186
c .logger .Err (err ).Msgf ("session registration failure" )
168
- c .handleSessionRegistrationFailure (datagram .RequestID , err )
187
+ c .handleSessionRegistrationFailure (datagram .RequestID )
169
188
return
170
189
}
171
190
// Make sure to eventually remove the session from the session manager when the session is closed
@@ -197,17 +216,49 @@ func (c *datagramConn) handleSessionRegistrationDatagram(ctx context.Context, da
197
216
c .logger .Err (err ).Msgf ("session was closed with an error" )
198
217
}
199
218
200
- func (c * datagramConn ) handleSessionRegistrationFailure (requestID RequestID , regErr error ) {
201
- var errResp SessionRegistrationResp
202
- switch regErr {
203
- case ErrSessionBoundToOtherConn :
204
- errResp = ResponseSessionAlreadyConnected
205
- default :
206
- errResp = ResponseUnableToBindSocket
219
+ func (c * datagramConn ) handleSessionAlreadyRegistered (requestID RequestID ) {
220
+ // Send another registration response since the session is already active
221
+ err := c .SendUDPSessionResponse (requestID , ResponseOk )
222
+ if err != nil {
223
+ c .logger .Err (err ).Msgf ("session registration failure: unable to send an additional session registration response" )
224
+ return
207
225
}
208
- err := c .SendUDPSessionResponse (requestID , errResp )
226
+
227
+ session , err := c .sessionManager .GetSession (requestID )
228
+ if err != nil {
229
+ // If for some reason we can not find the session after attempting to register it, we can just return
230
+ // instead of trying to reset the idle timer for it.
231
+ return
232
+ }
233
+ // The session is already running in another routine so we want to restart the idle timeout since no proxied
234
+ // packets have come down yet.
235
+ session .ResetIdleTimer ()
236
+ }
237
+
238
+ func (c * datagramConn ) handleSessionMigration (requestID RequestID ) {
239
+ // We need to migrate the currently running session to this edge connection.
240
+ session , err := c .sessionManager .GetSession (requestID )
241
+ if err != nil {
242
+ // If for some reason we can not find the session after attempting to register it, we can just return
243
+ // instead of trying to reset the idle timer for it.
244
+ return
245
+ }
246
+
247
+ // Migrate the session to use this edge connection instead of the currently running one.
248
+ session .Migrate (c )
249
+
250
+ // Send another registration response since the session is already active
251
+ err = c .SendUDPSessionResponse (requestID , ResponseOk )
252
+ if err != nil {
253
+ c .logger .Err (err ).Msgf ("session registration failure: unable to send an additional session registration response" )
254
+ return
255
+ }
256
+ }
257
+
258
+ func (c * datagramConn ) handleSessionRegistrationFailure (requestID RequestID ) {
259
+ err := c .SendUDPSessionResponse (requestID , ResponseUnableToBindSocket )
209
260
if err != nil {
210
- c .logger .Err (err ).Msgf ("unable to send session registration error response (%d)" , errResp )
261
+ c .logger .Err (err ).Msgf ("unable to send session registration error response (%d)" , ResponseUnableToBindSocket )
211
262
}
212
263
}
213
264
0 commit comments