VirtualBox

source: vbox/trunk/src/libs/curl-7.87.0/lib/vquic/msh3.c@ 98341

最後變更 在這個檔案從98341是 98326,由 vboxsync 提交於 2 年 前

curl-7.87.0: Applied and adjusted our curl changes to 7.83.1. bugref:10356

  • 屬性 svn:eol-style 設為 native
檔案大小: 16.6 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#ifdef USE_MSH3
28
29#include "urldata.h"
30#include "timeval.h"
31#include "multiif.h"
32#include "sendf.h"
33#include "connect.h"
34#include "h2h3.h"
35#include "msh3.h"
36
37/* The last 3 #include files should be in this order */
38#include "curl_printf.h"
39#include "curl_memory.h"
40#include "memdebug.h"
41
42/* #define DEBUG_HTTP3 1 */
43#ifdef DEBUG_HTTP3
44#define H3BUGF(x) x
45#else
46#define H3BUGF(x) do { } while(0)
47#endif
48
49#define MSH3_REQ_INIT_BUF_LEN 8192
50
51static CURLcode msh3_do_it(struct Curl_easy *data, bool *done);
52static int msh3_getsock(struct Curl_easy *data,
53 struct connectdata *conn, curl_socket_t *socks);
54static CURLcode msh3_disconnect(struct Curl_easy *data,
55 struct connectdata *conn,
56 bool dead_connection);
57static unsigned int msh3_conncheck(struct Curl_easy *data,
58 struct connectdata *conn,
59 unsigned int checks_to_perform);
60static Curl_recv msh3_stream_recv;
61static Curl_send msh3_stream_send;
62static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
63 void *IfContext,
64 const MSH3_HEADER *Header);
65static void MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
66 void *IfContext, uint32_t Length,
67 const uint8_t *Data);
68static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
69 bool Aborted, uint64_t AbortError);
70static void MSH3_CALL msh3_shutdown(MSH3_REQUEST *Request, void *IfContext);
71
72static const struct Curl_handler msh3_curl_handler_http3 = {
73 "HTTPS", /* scheme */
74 ZERO_NULL, /* setup_connection */
75 msh3_do_it, /* do_it */
76 Curl_http_done, /* done */
77 ZERO_NULL, /* do_more */
78 ZERO_NULL, /* connect_it */
79 ZERO_NULL, /* connecting */
80 ZERO_NULL, /* doing */
81 msh3_getsock, /* proto_getsock */
82 msh3_getsock, /* doing_getsock */
83 ZERO_NULL, /* domore_getsock */
84 msh3_getsock, /* perform_getsock */
85 msh3_disconnect, /* disconnect */
86 ZERO_NULL, /* readwrite */
87 msh3_conncheck, /* connection_check */
88 ZERO_NULL, /* attach connection */
89 PORT_HTTP, /* defport */
90 CURLPROTO_HTTPS, /* protocol */
91 CURLPROTO_HTTP, /* family */
92 PROTOPT_SSL | PROTOPT_STREAM /* flags */
93};
94
95static const MSH3_REQUEST_IF msh3_request_if = {
96 msh3_header_received,
97 msh3_data_received,
98 msh3_complete,
99 msh3_shutdown
100};
101
102void Curl_quic_ver(char *p, size_t len)
103{
104 uint32_t v[4];
105 MsH3Version(v);
106 (void)msnprintf(p, len, "msh3/%d.%d.%d.%d", v[0], v[1], v[2], v[3]);
107}
108
109CURLcode Curl_quic_connect(struct Curl_easy *data,
110 struct connectdata *conn,
111 curl_socket_t sockfd,
112 int sockindex,
113 const struct sockaddr *addr,
114 socklen_t addrlen)
115{
116 struct quicsocket *qs = &conn->hequic[sockindex];
117 bool insecure = !conn->ssl_config.verifypeer;
118 memset(qs, 0, sizeof(*qs));
119
120 (void)sockfd;
121 (void)addr; /* TODO - Pass address along */
122 (void)addrlen;
123
124 H3BUGF(infof(data, "creating new api/connection"));
125
126 qs->api = MsH3ApiOpen();
127 if(!qs->api) {
128 failf(data, "can't create msh3 api");
129 return CURLE_FAILED_INIT;
130 }
131
132 qs->conn = MsH3ConnectionOpen(qs->api,
133 conn->host.name,
134 (uint16_t)conn->remote_port,
135 insecure);
136 if(!qs->conn) {
137 failf(data, "can't create msh3 connection");
138 if(qs->api) {
139 MsH3ApiClose(qs->api);
140 }
141 return CURLE_FAILED_INIT;
142 }
143
144 return CURLE_OK;
145}
146
147CURLcode Curl_quic_is_connected(struct Curl_easy *data,
148 struct connectdata *conn,
149 int sockindex,
150 bool *connected)
151{
152 struct quicsocket *qs = &conn->hequic[sockindex];
153 MSH3_CONNECTION_STATE state;
154
155 state = MsH3ConnectionGetState(qs->conn, false);
156 if(state == MSH3_CONN_HANDSHAKE_FAILED || state == MSH3_CONN_DISCONNECTED) {
157 failf(data, "failed to connect, state=%u", (uint32_t)state);
158 return CURLE_COULDNT_CONNECT;
159 }
160
161 if(state == MSH3_CONN_CONNECTED) {
162 H3BUGF(infof(data, "connection connected"));
163 *connected = true;
164 conn->quic = qs;
165 conn->recv[sockindex] = msh3_stream_recv;
166 conn->send[sockindex] = msh3_stream_send;
167 conn->handler = &msh3_curl_handler_http3;
168 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
169 conn->httpversion = 30;
170 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
171 /* TODO - Clean up other happy-eyeballs connection(s)? */
172 }
173
174 return CURLE_OK;
175}
176
177static int msh3_getsock(struct Curl_easy *data,
178 struct connectdata *conn, curl_socket_t *socks)
179{
180 struct HTTP *stream = data->req.p.http;
181 int bitmap = GETSOCK_BLANK;
182
183 socks[0] = conn->sock[FIRSTSOCKET];
184
185 if(stream->recv_error) {
186 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
187 data->state.drain++;
188 }
189 else if(stream->recv_header_len || stream->recv_data_len) {
190 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
191 data->state.drain++;
192 }
193
194 H3BUGF(infof(data, "msh3_getsock %u", (uint32_t)data->state.drain));
195
196 return bitmap;
197}
198
199static CURLcode msh3_do_it(struct Curl_easy *data, bool *done)
200{
201 struct HTTP *stream = data->req.p.http;
202 H3BUGF(infof(data, "msh3_do_it"));
203 stream->recv_buf = malloc(MSH3_REQ_INIT_BUF_LEN);
204 if(!stream->recv_buf) {
205 return CURLE_OUT_OF_MEMORY;
206 }
207 stream->req = ZERO_NULL;
208 msh3_lock_initialize(&stream->recv_lock);
209 stream->recv_buf_alloc = MSH3_REQ_INIT_BUF_LEN;
210 stream->recv_header_len = 0;
211 stream->recv_header_complete = false;
212 stream->recv_data_len = 0;
213 stream->recv_data_complete = false;
214 stream->recv_error = CURLE_OK;
215 return Curl_http(data, done);
216}
217
218static unsigned int msh3_conncheck(struct Curl_easy *data,
219 struct connectdata *conn,
220 unsigned int checks_to_perform)
221{
222 (void)data;
223 (void)conn;
224 (void)checks_to_perform;
225 H3BUGF(infof(data, "msh3_conncheck"));
226 return CONNRESULT_NONE;
227}
228
229static void disconnect(struct quicsocket *qs)
230{
231 if(qs->conn) {
232 MsH3ConnectionClose(qs->conn);
233 qs->conn = ZERO_NULL;
234 }
235 if(qs->api) {
236 MsH3ApiClose(qs->api);
237 qs->api = ZERO_NULL;
238 }
239}
240
241static CURLcode msh3_disconnect(struct Curl_easy *data,
242 struct connectdata *conn, bool dead_connection)
243{
244 (void)data;
245 (void)dead_connection;
246 H3BUGF(infof(data, "disconnecting (msh3)"));
247 disconnect(conn->quic);
248 return CURLE_OK;
249}
250
251void Curl_quic_disconnect(struct Curl_easy *data, struct connectdata *conn,
252 int tempindex)
253{
254 (void)data;
255 if(conn->transport == TRNSPRT_QUIC) {
256 H3BUGF(infof(data, "disconnecting QUIC index %u", tempindex));
257 disconnect(&conn->hequic[tempindex]);
258 }
259}
260
261/* Requires stream->recv_lock to be held */
262static bool msh3request_ensure_room(struct HTTP *stream, size_t len)
263{
264 uint8_t *new_recv_buf;
265 const size_t cur_recv_len = stream->recv_header_len + stream->recv_data_len;
266 if(cur_recv_len + len > stream->recv_buf_alloc) {
267 size_t new_recv_buf_alloc_len = stream->recv_buf_alloc;
268 do {
269 new_recv_buf_alloc_len <<= 1; /* TODO - handle overflow */
270 } while(cur_recv_len + len > new_recv_buf_alloc_len);
271 new_recv_buf = malloc(new_recv_buf_alloc_len);
272 if(!new_recv_buf) {
273 return false;
274 }
275 if(cur_recv_len) {
276 memcpy(new_recv_buf, stream->recv_buf, cur_recv_len);
277 }
278 stream->recv_buf_alloc = new_recv_buf_alloc_len;
279 free(stream->recv_buf);
280 stream->recv_buf = new_recv_buf;
281 }
282 return true;
283}
284
285static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
286 void *IfContext,
287 const MSH3_HEADER *Header)
288{
289 struct HTTP *stream = IfContext;
290 size_t total_len;
291 (void)Request;
292
293 if(stream->recv_header_complete) {
294 H3BUGF(printf("* ignoring header after data\n"));
295 return;
296 }
297
298 msh3_lock_acquire(&stream->recv_lock);
299
300 if((Header->NameLength == 7) &&
301 !strncmp(H2H3_PSEUDO_STATUS, (char *)Header->Name, 7)) {
302 total_len = 9 + Header->ValueLength;
303 if(!msh3request_ensure_room(stream, total_len)) {
304 /* TODO - handle error */
305 goto release_lock;
306 }
307 msnprintf((char *)stream->recv_buf + stream->recv_header_len,
308 stream->recv_buf_alloc - stream->recv_header_len,
309 "HTTP/3 %.*s\n", (int)Header->ValueLength, Header->Value);
310 }
311 else {
312 total_len = Header->NameLength + 4 + Header->ValueLength;
313 if(!msh3request_ensure_room(stream, total_len)) {
314 /* TODO - handle error */
315 goto release_lock;
316 }
317 msnprintf((char *)stream->recv_buf + stream->recv_header_len,
318 stream->recv_buf_alloc - stream->recv_header_len,
319 "%.*s: %.*s\n",
320 (int)Header->NameLength, Header->Name,
321 (int)Header->ValueLength, Header->Value);
322 }
323
324 stream->recv_header_len += total_len - 1; /* don't include null-terminator */
325
326release_lock:
327 msh3_lock_release(&stream->recv_lock);
328}
329
330static void MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
331 void *IfContext, uint32_t Length,
332 const uint8_t *Data)
333{
334 struct HTTP *stream = IfContext;
335 size_t cur_recv_len = stream->recv_header_len + stream->recv_data_len;
336 (void)Request;
337 H3BUGF(printf("* msh3_data_received %u. %zu buffered, %zu allocated\n",
338 Length, cur_recv_len, stream->recv_buf_alloc));
339 msh3_lock_acquire(&stream->recv_lock);
340 if(!stream->recv_header_complete) {
341 H3BUGF(printf("* Headers complete!\n"));
342 if(!msh3request_ensure_room(stream, 2)) {
343 /* TODO - handle error */
344 goto release_lock;
345 }
346 stream->recv_buf[stream->recv_header_len++] = '\r';
347 stream->recv_buf[stream->recv_header_len++] = '\n';
348 stream->recv_header_complete = true;
349 cur_recv_len += 2;
350 }
351 if(!msh3request_ensure_room(stream, Length)) {
352 /* TODO - handle error */
353 goto release_lock;
354 }
355 memcpy(stream->recv_buf + cur_recv_len, Data, Length);
356 stream->recv_data_len += (size_t)Length;
357release_lock:
358 msh3_lock_release(&stream->recv_lock);
359}
360
361static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
362 bool Aborted, uint64_t AbortError)
363{
364 struct HTTP *stream = IfContext;
365 (void)Request;
366 (void)AbortError;
367 H3BUGF(printf("* msh3_complete, aborted=%s\n", Aborted ? "true" : "false"));
368 msh3_lock_acquire(&stream->recv_lock);
369 if(Aborted) {
370 stream->recv_error = CURLE_HTTP3; /* TODO - how do we pass AbortError? */
371 }
372 stream->recv_header_complete = true;
373 stream->recv_data_complete = true;
374 msh3_lock_release(&stream->recv_lock);
375}
376
377static void MSH3_CALL msh3_shutdown(MSH3_REQUEST *Request, void *IfContext)
378{
379 struct HTTP *stream = IfContext;
380 (void)Request;
381 (void)stream;
382}
383
384static ssize_t msh3_stream_send(struct Curl_easy *data,
385 int sockindex,
386 const void *mem,
387 size_t len,
388 CURLcode *curlcode)
389{
390 struct connectdata *conn = data->conn;
391 struct HTTP *stream = data->req.p.http;
392 struct quicsocket *qs = conn->quic;
393 struct h2h3req *hreq;
394
395 (void)sockindex;
396 /* Sizes must match for cast below to work" */
397 DEBUGASSERT(sizeof(MSH3_HEADER) == sizeof(struct h2h3pseudo));
398
399 H3BUGF(infof(data, "msh3_stream_send %zu", len));
400
401 if(!stream->req) {
402 *curlcode = Curl_pseudo_headers(data, mem, len, &hreq);
403 if(*curlcode) {
404 failf(data, "Curl_pseudo_headers failed");
405 return -1;
406 }
407 H3BUGF(infof(data, "starting request with %zu headers", hreq->entries));
408 stream->req = MsH3RequestOpen(qs->conn, &msh3_request_if, stream,
409 (MSH3_HEADER*)hreq->header, hreq->entries);
410 Curl_pseudo_free(hreq);
411 if(!stream->req) {
412 failf(data, "request open failed");
413 *curlcode = CURLE_SEND_ERROR;
414 return -1;
415 }
416 *curlcode = CURLE_OK;
417 return len;
418 }
419 H3BUGF(infof(data, "send %zd body bytes on request %p", len,
420 (void *)stream->req));
421 *curlcode = CURLE_SEND_ERROR;
422 return -1;
423}
424
425static ssize_t msh3_stream_recv(struct Curl_easy *data,
426 int sockindex,
427 char *buf,
428 size_t buffersize,
429 CURLcode *curlcode)
430{
431 struct HTTP *stream = data->req.p.http;
432 size_t outsize = 0;
433 (void)sockindex;
434 H3BUGF(infof(data, "msh3_stream_recv %zu", buffersize));
435
436 if(stream->recv_error) {
437 failf(data, "request aborted");
438 *curlcode = stream->recv_error;
439 return -1;
440 }
441
442 msh3_lock_acquire(&stream->recv_lock);
443
444 if(stream->recv_header_len) {
445 outsize = buffersize;
446 if(stream->recv_header_len < outsize) {
447 outsize = stream->recv_header_len;
448 }
449 memcpy(buf, stream->recv_buf, outsize);
450 if(outsize < stream->recv_header_len + stream->recv_data_len) {
451 memmove(stream->recv_buf, stream->recv_buf + outsize,
452 stream->recv_header_len + stream->recv_data_len - outsize);
453 }
454 stream->recv_header_len -= outsize;
455 H3BUGF(infof(data, "returned %zu bytes of headers", outsize));
456 }
457 else if(stream->recv_data_len) {
458 outsize = buffersize;
459 if(stream->recv_data_len < outsize) {
460 outsize = stream->recv_data_len;
461 }
462 memcpy(buf, stream->recv_buf, outsize);
463 if(outsize < stream->recv_data_len) {
464 memmove(stream->recv_buf, stream->recv_buf + outsize,
465 stream->recv_data_len - outsize);
466 }
467 stream->recv_data_len -= outsize;
468 H3BUGF(infof(data, "returned %zu bytes of data", outsize));
469 }
470 else if(stream->recv_data_complete) {
471 H3BUGF(infof(data, "receive complete"));
472 }
473
474 msh3_lock_release(&stream->recv_lock);
475
476 return (ssize_t)outsize;
477}
478
479CURLcode Curl_quic_done_sending(struct Curl_easy *data)
480{
481 struct connectdata *conn = data->conn;
482 H3BUGF(infof(data, "Curl_quic_done_sending"));
483 if(conn->handler == &msh3_curl_handler_http3) {
484 struct HTTP *stream = data->req.p.http;
485 stream->upload_done = TRUE;
486 }
487
488 return CURLE_OK;
489}
490
491void Curl_quic_done(struct Curl_easy *data, bool premature)
492{
493 struct HTTP *stream = data->req.p.http;
494 (void)premature;
495 H3BUGF(infof(data, "Curl_quic_done"));
496 if(stream) {
497 if(stream->recv_buf) {
498 Curl_safefree(stream->recv_buf);
499 msh3_lock_uninitialize(&stream->recv_lock);
500 }
501 if(stream->req) {
502 MsH3RequestClose(stream->req);
503 stream->req = ZERO_NULL;
504 }
505 }
506}
507
508bool Curl_quic_data_pending(const struct Curl_easy *data)
509{
510 struct HTTP *stream = data->req.p.http;
511 H3BUGF(infof((struct Curl_easy *)data, "Curl_quic_data_pending"));
512 return stream->recv_header_len || stream->recv_data_len;
513}
514
515/*
516 * Called from transfer.c:Curl_readwrite when neither HTTP level read
517 * nor write is performed. It is a good place to handle timer expiry
518 * for QUIC transport.
519 */
520CURLcode Curl_quic_idle(struct Curl_easy *data)
521{
522 (void)data;
523 H3BUGF(infof(data, "Curl_quic_idle"));
524 return CURLE_OK;
525}
526
527#endif /* USE_MSH3 */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette