8763
|
1
|
|
2 /*
|
|
3 * Copyright (C) Nginx, Inc.
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9 #include <ngx_event.h>
|
|
10 #include <ngx_event_quic_connection.h>
|
|
11
|
|
12
|
|
13 static ngx_int_t ngx_quic_create_temp_socket(ngx_connection_t *c,
|
|
14 ngx_quic_connection_t *qc, ngx_str_t *dcid, ngx_quic_path_t *path,
|
|
15 ngx_quic_client_id_t *cid);
|
|
16
|
|
17 static void ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path);
|
|
18
|
|
19
|
|
20 ngx_int_t
|
|
21 ngx_quic_open_sockets(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
|
22 ngx_quic_header_t *pkt)
|
|
23 {
|
|
24 ngx_quic_path_t *path;
|
|
25 ngx_quic_socket_t *qsock;
|
|
26 ngx_quic_client_id_t *cid;
|
|
27
|
|
28 /*
|
|
29 * qc->nclient_ids = 0
|
|
30 * qc->nsockets = 0
|
|
31 * qc->max_retired_seqnum = 0
|
|
32 * qc->client_seqnum = 0
|
|
33 */
|
|
34
|
|
35 ngx_queue_init(&qc->sockets);
|
|
36 ngx_queue_init(&qc->free_sockets);
|
|
37
|
|
38 ngx_queue_init(&qc->paths);
|
|
39 ngx_queue_init(&qc->free_paths);
|
|
40
|
|
41 ngx_queue_init(&qc->client_ids);
|
|
42 ngx_queue_init(&qc->free_client_ids);
|
|
43
|
|
44 qc->tp.original_dcid.len = pkt->odcid.len;
|
|
45 qc->tp.original_dcid.data = ngx_pstrdup(c->pool, &pkt->odcid);
|
|
46 if (qc->tp.original_dcid.data == NULL) {
|
|
47 return NGX_ERROR;
|
|
48 }
|
|
49
|
|
50 /* socket to use for further processing */
|
|
51 qsock = ngx_quic_alloc_socket(c, qc);
|
|
52 if (qsock == NULL) {
|
|
53 return NGX_ERROR;
|
|
54 }
|
|
55
|
|
56 /* socket is listening at new server id (autogenerated) */
|
|
57 if (ngx_quic_listen(c, qc, qsock) != NGX_OK) {
|
|
58 return NGX_ERROR;
|
|
59 }
|
|
60
|
|
61 qc->tp.initial_scid.len = qsock->sid.len;
|
|
62 qc->tp.initial_scid.data = ngx_pnalloc(c->pool, qsock->sid.len);
|
|
63 if (qc->tp.initial_scid.data == NULL) {
|
|
64 goto failed;
|
|
65 }
|
|
66 ngx_memcpy(qc->tp.initial_scid.data, qsock->sid.id, qsock->sid.len);
|
|
67
|
|
68 /* for all packets except first, this is set at udp layer */
|
|
69 c->udp = &qsock->udp;
|
|
70
|
|
71 /* ngx_quic_get_connection(c) macro is now usable */
|
|
72
|
|
73 /* we have a client identified by scid */
|
|
74 cid = ngx_quic_create_client_id(c, &pkt->scid, 0, NULL);
|
|
75 if (cid == NULL) {
|
|
76 goto failed;
|
|
77 }
|
|
78
|
|
79 /* the client arrived from this path */
|
|
80 path = ngx_quic_add_path(c, c->sockaddr, c->socklen);
|
|
81 if (path == NULL) {
|
|
82 goto failed;
|
|
83 }
|
|
84
|
|
85 if (pkt->validated) {
|
|
86 path->state = NGX_QUIC_PATH_VALIDATED;
|
|
87 path->validated_at = ngx_time();
|
|
88 }
|
|
89
|
|
90 /* now bind socket to client and path */
|
|
91 ngx_quic_connect(c, qsock, path, cid);
|
|
92
|
|
93 if (ngx_quic_create_temp_socket(c, qc, &pkt->odcid, path, cid) != NGX_OK) {
|
|
94 goto failed;
|
|
95 }
|
|
96
|
|
97 /* use this socket as default destination */
|
|
98 qc->socket = qsock;
|
|
99
|
|
100 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
101 "quic active socket is #%uL:%uL:%uL (%s)",
|
|
102 qsock->sid.seqnum, qsock->cid->seqnum, qsock->path->seqnum,
|
|
103 ngx_quic_path_state_str(qsock->path));
|
|
104
|
|
105 return NGX_OK;
|
|
106
|
|
107 failed:
|
|
108
|
|
109 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node);
|
|
110 c->udp = NULL;
|
|
111
|
|
112 return NGX_ERROR;
|
|
113 }
|
|
114
|
|
115
|
|
116 static ngx_int_t
|
|
117 ngx_quic_create_temp_socket(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
|
118 ngx_str_t *dcid, ngx_quic_path_t *path, ngx_quic_client_id_t *cid)
|
|
119 {
|
|
120 ngx_str_t id;
|
|
121 ngx_quic_socket_t *qsock;
|
|
122 ngx_quic_server_id_t *sid;
|
|
123
|
|
124 qsock = ngx_quic_alloc_socket(c, qc);
|
|
125 if (qsock == NULL) {
|
|
126 return NGX_ERROR;
|
|
127 }
|
|
128
|
|
129 sid = &qsock->sid;
|
|
130
|
|
131 sid->seqnum = NGX_QUIC_UNSET_PN; /* mark socket as temporary */
|
|
132
|
|
133 sid->len = dcid->len;
|
|
134 ngx_memcpy(sid->id, dcid->data, dcid->len);
|
|
135
|
|
136 id.len = sid->len;
|
|
137 id.data = sid->id;
|
|
138
|
|
139 ngx_insert_udp_connection(c, &qsock->udp, &id);
|
|
140
|
|
141 ngx_queue_insert_tail(&qc->sockets, &qsock->queue);
|
|
142
|
|
143 qc->nsockets++;
|
|
144 qsock->quic = qc;
|
|
145
|
|
146 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
147 "quic socket #%L listening at sid:%xV nsock:%ui",
|
|
148 (int64_t) sid->seqnum, &id, qc->nsockets);
|
|
149
|
|
150 ngx_quic_connect(c, qsock, path, cid);
|
|
151
|
|
152 return NGX_OK;
|
|
153 }
|
|
154
|
|
155
|
|
156 ngx_quic_socket_t *
|
|
157 ngx_quic_alloc_socket(ngx_connection_t *c, ngx_quic_connection_t *qc)
|
|
158 {
|
|
159 ngx_queue_t *q;
|
|
160 ngx_quic_socket_t *sock;
|
|
161
|
|
162 if (!ngx_queue_empty(&qc->free_sockets)) {
|
|
163
|
|
164 q = ngx_queue_head(&qc->free_sockets);
|
|
165 sock = ngx_queue_data(q, ngx_quic_socket_t, queue);
|
|
166
|
|
167 ngx_queue_remove(&sock->queue);
|
|
168
|
|
169 ngx_memzero(sock, sizeof(ngx_quic_socket_t));
|
|
170
|
|
171 } else {
|
|
172
|
|
173 sock = ngx_pcalloc(c->pool, sizeof(ngx_quic_socket_t));
|
|
174 if (sock == NULL) {
|
|
175 return NULL;
|
|
176 }
|
|
177 }
|
|
178
|
|
179 return sock;
|
|
180 }
|
|
181
|
|
182
|
|
183 void
|
|
184 ngx_quic_close_socket(ngx_connection_t *c, ngx_quic_socket_t *qsock)
|
|
185 {
|
|
186 ngx_quic_connection_t *qc;
|
|
187
|
|
188 qc = ngx_quic_get_connection(c);
|
|
189
|
|
190 ngx_queue_remove(&qsock->queue);
|
|
191 ngx_queue_insert_head(&qc->free_sockets, &qsock->queue);
|
|
192
|
|
193 ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node);
|
|
194 qc->nsockets--;
|
|
195
|
|
196 if (qsock->path) {
|
|
197 ngx_quic_unref_path(c, qsock->path);
|
|
198 }
|
|
199
|
|
200 if (qsock->cid) {
|
|
201 ngx_quic_unref_client_id(c, qsock->cid);
|
|
202 }
|
|
203
|
|
204 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
205 "quic socket #%L closed nsock:%ui",
|
|
206 (int64_t) qsock->sid.seqnum, qc->nsockets);
|
|
207 }
|
|
208
|
|
209
|
|
210 static void
|
|
211 ngx_quic_unref_path(ngx_connection_t *c, ngx_quic_path_t *path)
|
|
212 {
|
|
213 ngx_quic_connection_t *qc;
|
|
214
|
|
215 path->refcnt--;
|
|
216
|
|
217 if (path->refcnt) {
|
|
218 return;
|
|
219 }
|
|
220
|
|
221 qc = ngx_quic_get_connection(c);
|
|
222
|
|
223 ngx_queue_remove(&path->queue);
|
|
224 ngx_queue_insert_head(&qc->free_paths, &path->queue);
|
|
225
|
|
226 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
227 "quic path #%uL addr:%V removed",
|
|
228 path->seqnum, &path->addr_text);
|
|
229 }
|
|
230
|
|
231
|
|
232 ngx_int_t
|
|
233 ngx_quic_listen(ngx_connection_t *c, ngx_quic_connection_t *qc,
|
|
234 ngx_quic_socket_t *qsock)
|
|
235 {
|
|
236 ngx_str_t id;
|
|
237 ngx_quic_server_id_t *sid;
|
|
238
|
|
239 sid = &qsock->sid;
|
|
240
|
|
241 sid->len = NGX_QUIC_SERVER_CID_LEN;
|
|
242
|
|
243 if (ngx_quic_create_server_id(c, sid->id) != NGX_OK) {
|
|
244 return NGX_ERROR;
|
|
245 }
|
|
246
|
|
247 sid->seqnum = qc->server_seqnum++;
|
|
248
|
|
249 id.data = sid->id;
|
|
250 id.len = sid->len;
|
|
251
|
|
252 ngx_insert_udp_connection(c, &qsock->udp, &id);
|
|
253
|
|
254 ngx_queue_insert_tail(&qc->sockets, &qsock->queue);
|
|
255
|
|
256 qc->nsockets++;
|
|
257 qsock->quic = qc;
|
|
258
|
|
259 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
260 "quic socket #%uL listening at sid:%xV nsock:%ui",
|
|
261 sid->seqnum, &id, qc->nsockets);
|
|
262
|
|
263 return NGX_OK;
|
|
264 }
|
|
265
|
|
266
|
|
267 void
|
|
268 ngx_quic_connect(ngx_connection_t *c, ngx_quic_socket_t *sock,
|
|
269 ngx_quic_path_t *path, ngx_quic_client_id_t *cid)
|
|
270 {
|
|
271 sock->path = path;
|
|
272 path->refcnt++;
|
|
273
|
|
274 sock->cid = cid;
|
|
275 cid->refcnt++;
|
|
276
|
|
277 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
|
278 "quic socket #%L connected to cid #%uL path:%uL",
|
|
279 (int64_t) sock->sid.seqnum,
|
|
280 sock->cid->seqnum, path->seqnum);
|
|
281 }
|
|
282
|
|
283
|
|
284 void
|
|
285 ngx_quic_close_sockets(ngx_connection_t *c)
|
|
286 {
|
|
287 ngx_queue_t *q;
|
|
288 ngx_quic_socket_t *qsock;
|
|
289 ngx_quic_connection_t *qc;
|
|
290
|
|
291 qc = ngx_quic_get_connection(c);
|
|
292
|
|
293 ngx_quic_close_socket(c, qc->socket);
|
|
294
|
|
295 if (qc->backup) {
|
|
296 ngx_quic_close_socket(c, qc->backup);
|
|
297 }
|
|
298
|
|
299 while (!ngx_queue_empty(&qc->sockets)) {
|
|
300 q = ngx_queue_head(&qc->sockets);
|
|
301 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue);
|
|
302
|
|
303 ngx_quic_close_socket(c, qsock);
|
|
304 }
|
|
305 }
|
|
306
|
|
307
|
|
308 ngx_quic_socket_t *
|
|
309 ngx_quic_find_socket(ngx_connection_t *c, uint64_t seqnum)
|
|
310 {
|
|
311 ngx_queue_t *q;
|
|
312 ngx_quic_socket_t *qsock;
|
|
313 ngx_quic_connection_t *qc;
|
|
314
|
|
315 qc = ngx_quic_get_connection(c);
|
|
316
|
|
317 for (q = ngx_queue_head(&qc->sockets);
|
|
318 q != ngx_queue_sentinel(&qc->sockets);
|
|
319 q = ngx_queue_next(q))
|
|
320 {
|
|
321 qsock = ngx_queue_data(q, ngx_quic_socket_t, queue);
|
|
322
|
|
323 if (qsock->sid.seqnum == seqnum) {
|
|
324 return qsock;
|
|
325 }
|
|
326 }
|
|
327
|
|
328 return NULL;
|
|
329 }
|
|
330
|
|
331
|
|
332 ngx_quic_socket_t *
|
|
333 ngx_quic_get_unconnected_socket(ngx_connection_t *c)
|
|
334 {
|
|
335 ngx_queue_t *q;
|
|
336 ngx_quic_socket_t *sock;
|
|
337 ngx_quic_connection_t *qc;
|
|
338
|
|
339 qc = ngx_quic_get_connection(c);
|
|
340
|
|
341 for (q = ngx_queue_head(&qc->sockets);
|
|
342 q != ngx_queue_sentinel(&qc->sockets);
|
|
343 q = ngx_queue_next(q))
|
|
344 {
|
|
345 sock = ngx_queue_data(q, ngx_quic_socket_t, queue);
|
|
346
|
|
347 if (sock->cid == NULL) {
|
|
348 return sock;
|
|
349 }
|
|
350 }
|
|
351
|
|
352 return NULL;
|
8888
|
353 }
|