curl_quiche.c 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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. #include "curl_setup.h"
  25. #ifdef USE_QUICHE
  26. #include <quiche.h>
  27. #include <openssl/err.h>
  28. #include <openssl/ssl.h>
  29. #include "bufq.h"
  30. #include "hash.h"
  31. #include "urldata.h"
  32. #include "cfilters.h"
  33. #include "cf-socket.h"
  34. #include "sendf.h"
  35. #include "strdup.h"
  36. #include "rand.h"
  37. #include "strcase.h"
  38. #include "multiif.h"
  39. #include "connect.h"
  40. #include "progress.h"
  41. #include "strerror.h"
  42. #include "http1.h"
  43. #include "vquic.h"
  44. #include "vquic_int.h"
  45. #include "vquic-tls.h"
  46. #include "curl_quiche.h"
  47. #include "transfer.h"
  48. #include "inet_pton.h"
  49. #include "vtls/openssl.h"
  50. #include "vtls/keylog.h"
  51. #include "vtls/vtls.h"
  52. /* The last 3 #include files should be in this order */
  53. #include "curl_printf.h"
  54. #include "curl_memory.h"
  55. #include "memdebug.h"
  56. /* HTTP/3 error values defined in RFC 9114, ch. 8.1 */
  57. #define CURL_H3_NO_ERROR (0x0100)
  58. #define QUIC_MAX_STREAMS (100)
  59. #define H3_STREAM_WINDOW_SIZE (128 * 1024)
  60. #define H3_STREAM_CHUNK_SIZE (16 * 1024)
  61. /* The pool keeps spares around and half of a full stream windows seems good.
  62. * More does not seem to improve performance. The benefit of the pool is that
  63. * stream buffer to not keep spares. Memory consumption goes down when streams
  64. * run empty, have a large upload done, etc. */
  65. #define H3_STREAM_POOL_SPARES \
  66. (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
  67. /* Receive and Send max number of chunks just follows from the
  68. * chunk size and window size */
  69. #define H3_STREAM_RECV_CHUNKS \
  70. (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
  71. #define H3_STREAM_SEND_CHUNKS \
  72. (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
  73. /*
  74. * Store quiche version info in this buffer.
  75. */
  76. void Curl_quiche_ver(char *p, size_t len)
  77. {
  78. (void)msnprintf(p, len, "quiche/%s", quiche_version());
  79. }
  80. struct cf_quiche_ctx {
  81. struct cf_quic_ctx q;
  82. struct ssl_peer peer;
  83. struct curl_tls_ctx tls;
  84. quiche_conn *qconn;
  85. quiche_config *cfg;
  86. quiche_h3_conn *h3c;
  87. quiche_h3_config *h3config;
  88. uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
  89. struct curltime started_at; /* time the current attempt started */
  90. struct curltime handshake_at; /* time connect handshake finished */
  91. struct bufc_pool stream_bufcp; /* chunk pool for streams */
  92. struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */
  93. curl_off_t data_recvd;
  94. BIT(initialized);
  95. BIT(goaway); /* got GOAWAY from server */
  96. BIT(x509_store_setup); /* if x509 store has been set up */
  97. BIT(shutdown_started); /* queued shutdown packets */
  98. };
  99. #ifdef DEBUG_QUICHE
  100. /* initialize debug log callback only once */
  101. static int debug_log_init = 0;
  102. static void quiche_debug_log(const char *line, void *argp)
  103. {
  104. (void)argp;
  105. fprintf(stderr, "%s\n", line);
  106. }
  107. #endif
  108. static void h3_stream_hash_free(void *stream);
  109. static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
  110. {
  111. DEBUGASSERT(!ctx->initialized);
  112. #ifdef DEBUG_QUICHE
  113. if(!debug_log_init) {
  114. quiche_enable_debug_logging(quiche_debug_log, NULL);
  115. debug_log_init = 1;
  116. }
  117. #endif
  118. Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
  119. H3_STREAM_POOL_SPARES);
  120. Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
  121. ctx->data_recvd = 0;
  122. ctx->initialized = TRUE;
  123. }
  124. static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
  125. {
  126. if(ctx && ctx->initialized) {
  127. /* quiche just freed it */
  128. ctx->tls.ossl.ssl = NULL;
  129. Curl_vquic_tls_cleanup(&ctx->tls);
  130. Curl_ssl_peer_cleanup(&ctx->peer);
  131. vquic_ctx_free(&ctx->q);
  132. Curl_bufcp_free(&ctx->stream_bufcp);
  133. Curl_hash_clean(&ctx->streams);
  134. Curl_hash_destroy(&ctx->streams);
  135. }
  136. free(ctx);
  137. }
  138. static void cf_quiche_ctx_close(struct cf_quiche_ctx *ctx)
  139. {
  140. if(ctx->h3c)
  141. quiche_h3_conn_free(ctx->h3c);
  142. if(ctx->h3config)
  143. quiche_h3_config_free(ctx->h3config);
  144. if(ctx->qconn)
  145. quiche_conn_free(ctx->qconn);
  146. if(ctx->cfg)
  147. quiche_config_free(ctx->cfg);
  148. }
  149. static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
  150. struct Curl_easy *data);
  151. /**
  152. * All about the H3 internals of a stream
  153. */
  154. struct stream_ctx {
  155. curl_uint64_t id; /* HTTP/3 protocol stream identifier */
  156. struct bufq recvbuf; /* h3 response */
  157. struct h1_req_parser h1; /* h1 request parsing */
  158. curl_uint64_t error3; /* HTTP/3 stream error code */
  159. BIT(opened); /* TRUE after stream has been opened */
  160. BIT(closed); /* TRUE on stream close */
  161. BIT(reset); /* TRUE on stream reset */
  162. BIT(send_closed); /* stream is locally closed */
  163. BIT(resp_hds_complete); /* final response has been received */
  164. BIT(resp_got_header); /* TRUE when h3 stream has recvd some HEADER */
  165. BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
  166. };
  167. #define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)(\
  168. data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
  169. static void h3_stream_ctx_free(struct stream_ctx *stream)
  170. {
  171. Curl_bufq_free(&stream->recvbuf);
  172. Curl_h1_req_parse_free(&stream->h1);
  173. free(stream);
  174. }
  175. static void h3_stream_hash_free(void *stream)
  176. {
  177. DEBUGASSERT(stream);
  178. h3_stream_ctx_free((struct stream_ctx *)stream);
  179. }
  180. static void check_resumes(struct Curl_cfilter *cf,
  181. struct Curl_easy *data)
  182. {
  183. struct cf_quiche_ctx *ctx = cf->ctx;
  184. struct Curl_llist_node *e;
  185. DEBUGASSERT(data->multi);
  186. for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
  187. struct Curl_easy *sdata = Curl_node_elem(e);
  188. if(sdata->conn == data->conn) {
  189. struct stream_ctx *stream = H3_STREAM_CTX(ctx, sdata);
  190. if(stream && stream->quic_flow_blocked) {
  191. stream->quic_flow_blocked = FALSE;
  192. Curl_expire(data, 0, EXPIRE_RUN_NOW);
  193. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] unblock", stream->id);
  194. }
  195. }
  196. }
  197. }
  198. static CURLcode h3_data_setup(struct Curl_cfilter *cf,
  199. struct Curl_easy *data)
  200. {
  201. struct cf_quiche_ctx *ctx = cf->ctx;
  202. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  203. if(stream)
  204. return CURLE_OK;
  205. stream = calloc(1, sizeof(*stream));
  206. if(!stream)
  207. return CURLE_OUT_OF_MEMORY;
  208. stream->id = -1;
  209. Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
  210. H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
  211. Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
  212. if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
  213. h3_stream_ctx_free(stream);
  214. return CURLE_OUT_OF_MEMORY;
  215. }
  216. return CURLE_OK;
  217. }
  218. static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
  219. {
  220. struct cf_quiche_ctx *ctx = cf->ctx;
  221. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  222. CURLcode result;
  223. (void)cf;
  224. if(stream) {
  225. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] easy handle is done", stream->id);
  226. if(ctx->qconn && !stream->closed) {
  227. quiche_conn_stream_shutdown(ctx->qconn, stream->id,
  228. QUICHE_SHUTDOWN_READ, CURL_H3_NO_ERROR);
  229. if(!stream->send_closed) {
  230. quiche_conn_stream_shutdown(ctx->qconn, stream->id,
  231. QUICHE_SHUTDOWN_WRITE, CURL_H3_NO_ERROR);
  232. stream->send_closed = TRUE;
  233. }
  234. stream->closed = TRUE;
  235. result = cf_flush_egress(cf, data);
  236. if(result)
  237. CURL_TRC_CF(data, cf, "data_done, flush egress -> %d", result);
  238. }
  239. Curl_hash_offt_remove(&ctx->streams, data->mid);
  240. }
  241. }
  242. static void h3_drain_stream(struct Curl_cfilter *cf,
  243. struct Curl_easy *data)
  244. {
  245. struct cf_quiche_ctx *ctx = cf->ctx;
  246. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  247. unsigned char bits;
  248. (void)cf;
  249. bits = CURL_CSELECT_IN;
  250. if(stream && !stream->send_closed)
  251. bits |= CURL_CSELECT_OUT;
  252. if(data->state.select_bits != bits) {
  253. data->state.select_bits = bits;
  254. Curl_expire(data, 0, EXPIRE_RUN_NOW);
  255. }
  256. }
  257. static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
  258. struct Curl_easy *data,
  259. curl_uint64_t stream_id,
  260. struct stream_ctx **pstream)
  261. {
  262. struct cf_quiche_ctx *ctx = cf->ctx;
  263. struct stream_ctx *stream;
  264. (void)cf;
  265. stream = H3_STREAM_CTX(ctx, data);
  266. if(stream && stream->id == stream_id) {
  267. *pstream = stream;
  268. return data;
  269. }
  270. else {
  271. struct Curl_llist_node *e;
  272. DEBUGASSERT(data->multi);
  273. for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
  274. struct Curl_easy *sdata = Curl_node_elem(e);
  275. if(sdata->conn != data->conn)
  276. continue;
  277. stream = H3_STREAM_CTX(ctx, sdata);
  278. if(stream && stream->id == stream_id) {
  279. *pstream = stream;
  280. return sdata;
  281. }
  282. }
  283. }
  284. *pstream = NULL;
  285. return NULL;
  286. }
  287. static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf,
  288. struct Curl_easy *data)
  289. {
  290. struct Curl_llist_node *e;
  291. DEBUGASSERT(data->multi);
  292. CURL_TRC_CF(data, cf, "conn closed, expire all transfers");
  293. for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
  294. struct Curl_easy *sdata = Curl_node_elem(e);
  295. if(sdata == data || sdata->conn != data->conn)
  296. continue;
  297. CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");
  298. Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
  299. }
  300. }
  301. /*
  302. * write_resp_raw() copies response data in raw format to the `data`'s
  303. * receive buffer. If not enough space is available, it appends to the
  304. * `data`'s overflow buffer.
  305. */
  306. static CURLcode write_resp_raw(struct Curl_cfilter *cf,
  307. struct Curl_easy *data,
  308. const void *mem, size_t memlen)
  309. {
  310. struct cf_quiche_ctx *ctx = cf->ctx;
  311. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  312. CURLcode result = CURLE_OK;
  313. ssize_t nwritten;
  314. (void)cf;
  315. if(!stream)
  316. return CURLE_RECV_ERROR;
  317. nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
  318. if(nwritten < 0)
  319. return result;
  320. if((size_t)nwritten < memlen) {
  321. /* This MUST not happen. Our recbuf is dimensioned to hold the
  322. * full max_stream_window and then some for this very reason. */
  323. DEBUGASSERT(0);
  324. return CURLE_RECV_ERROR;
  325. }
  326. return result;
  327. }
  328. struct cb_ctx {
  329. struct Curl_cfilter *cf;
  330. struct Curl_easy *data;
  331. };
  332. static int cb_each_header(uint8_t *name, size_t name_len,
  333. uint8_t *value, size_t value_len,
  334. void *argp)
  335. {
  336. struct cb_ctx *x = argp;
  337. struct cf_quiche_ctx *ctx = x->cf->ctx;
  338. struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
  339. CURLcode result;
  340. if(!stream)
  341. return CURLE_OK;
  342. if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7)) {
  343. CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRIu64 "] status: %.*s",
  344. stream->id, (int)value_len, value);
  345. result = write_resp_raw(x->cf, x->data, "HTTP/3 ", sizeof("HTTP/3 ") - 1);
  346. if(!result)
  347. result = write_resp_raw(x->cf, x->data, value, value_len);
  348. if(!result)
  349. result = write_resp_raw(x->cf, x->data, " \r\n", 3);
  350. }
  351. else {
  352. CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRIu64 "] header: %.*s: %.*s",
  353. stream->id, (int)name_len, name,
  354. (int)value_len, value);
  355. result = write_resp_raw(x->cf, x->data, name, name_len);
  356. if(!result)
  357. result = write_resp_raw(x->cf, x->data, ": ", 2);
  358. if(!result)
  359. result = write_resp_raw(x->cf, x->data, value, value_len);
  360. if(!result)
  361. result = write_resp_raw(x->cf, x->data, "\r\n", 2);
  362. }
  363. if(result) {
  364. CURL_TRC_CF(x->data, x->cf, "[%"FMT_PRIu64"] on header error %d",
  365. stream->id, result);
  366. }
  367. return result;
  368. }
  369. static ssize_t stream_resp_read(void *reader_ctx,
  370. unsigned char *buf, size_t len,
  371. CURLcode *err)
  372. {
  373. struct cb_ctx *x = reader_ctx;
  374. struct cf_quiche_ctx *ctx = x->cf->ctx;
  375. struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
  376. ssize_t nread;
  377. if(!stream) {
  378. *err = CURLE_RECV_ERROR;
  379. return -1;
  380. }
  381. nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id,
  382. buf, len);
  383. if(nread >= 0) {
  384. *err = CURLE_OK;
  385. return nread;
  386. }
  387. else {
  388. *err = CURLE_AGAIN;
  389. return -1;
  390. }
  391. }
  392. static CURLcode cf_recv_body(struct Curl_cfilter *cf,
  393. struct Curl_easy *data)
  394. {
  395. struct cf_quiche_ctx *ctx = cf->ctx;
  396. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  397. ssize_t nwritten;
  398. struct cb_ctx cb_ctx;
  399. CURLcode result = CURLE_OK;
  400. if(!stream)
  401. return CURLE_RECV_ERROR;
  402. if(!stream->resp_hds_complete) {
  403. result = write_resp_raw(cf, data, "\r\n", 2);
  404. if(result)
  405. return result;
  406. stream->resp_hds_complete = TRUE;
  407. }
  408. cb_ctx.cf = cf;
  409. cb_ctx.data = data;
  410. nwritten = Curl_bufq_slurp(&stream->recvbuf,
  411. stream_resp_read, &cb_ctx, &result);
  412. if(nwritten < 0 && result != CURLE_AGAIN) {
  413. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zd",
  414. stream->id, nwritten);
  415. failf(data, "Error %d in HTTP/3 response body for stream[%"FMT_PRIu64"]",
  416. result, stream->id);
  417. stream->closed = TRUE;
  418. stream->reset = TRUE;
  419. stream->send_closed = TRUE;
  420. streamclose(cf->conn, "Reset of stream");
  421. return result;
  422. }
  423. return CURLE_OK;
  424. }
  425. #ifdef DEBUGBUILD
  426. static const char *cf_ev_name(quiche_h3_event *ev)
  427. {
  428. switch(quiche_h3_event_type(ev)) {
  429. case QUICHE_H3_EVENT_HEADERS:
  430. return "HEADERS";
  431. case QUICHE_H3_EVENT_DATA:
  432. return "DATA";
  433. case QUICHE_H3_EVENT_RESET:
  434. return "RESET";
  435. case QUICHE_H3_EVENT_FINISHED:
  436. return "FINISHED";
  437. case QUICHE_H3_EVENT_GOAWAY:
  438. return "GOAWAY";
  439. default:
  440. return "Unknown";
  441. }
  442. }
  443. #else
  444. #define cf_ev_name(x) ""
  445. #endif
  446. static CURLcode h3_process_event(struct Curl_cfilter *cf,
  447. struct Curl_easy *data,
  448. struct stream_ctx *stream,
  449. quiche_h3_event *ev)
  450. {
  451. struct cb_ctx cb_ctx;
  452. CURLcode result = CURLE_OK;
  453. int rc;
  454. if(!stream)
  455. return CURLE_OK;
  456. switch(quiche_h3_event_type(ev)) {
  457. case QUICHE_H3_EVENT_HEADERS:
  458. stream->resp_got_header = TRUE;
  459. cb_ctx.cf = cf;
  460. cb_ctx.data = data;
  461. rc = quiche_h3_event_for_each_header(ev, cb_each_header, &cb_ctx);
  462. if(rc) {
  463. failf(data, "Error %d in HTTP/3 response header for stream[%"
  464. FMT_PRIu64"]", rc, stream->id);
  465. return CURLE_RECV_ERROR;
  466. }
  467. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] <- [HEADERS]", stream->id);
  468. break;
  469. case QUICHE_H3_EVENT_DATA:
  470. if(!stream->closed) {
  471. result = cf_recv_body(cf, data);
  472. }
  473. break;
  474. case QUICHE_H3_EVENT_RESET:
  475. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] RESET", stream->id);
  476. stream->closed = TRUE;
  477. stream->reset = TRUE;
  478. stream->send_closed = TRUE;
  479. streamclose(cf->conn, "Reset of stream");
  480. break;
  481. case QUICHE_H3_EVENT_FINISHED:
  482. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] CLOSED", stream->id);
  483. if(!stream->resp_hds_complete) {
  484. result = write_resp_raw(cf, data, "\r\n", 2);
  485. if(result)
  486. return result;
  487. stream->resp_hds_complete = TRUE;
  488. }
  489. stream->closed = TRUE;
  490. streamclose(cf->conn, "End of stream");
  491. break;
  492. case QUICHE_H3_EVENT_GOAWAY:
  493. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] <- [GOAWAY]", stream->id);
  494. break;
  495. default:
  496. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv, unhandled event %d",
  497. stream->id, quiche_h3_event_type(ev));
  498. break;
  499. }
  500. return result;
  501. }
  502. static CURLcode cf_poll_events(struct Curl_cfilter *cf,
  503. struct Curl_easy *data)
  504. {
  505. struct cf_quiche_ctx *ctx = cf->ctx;
  506. struct stream_ctx *stream = NULL;
  507. struct Curl_easy *sdata;
  508. quiche_h3_event *ev;
  509. CURLcode result;
  510. /* Take in the events and distribute them to the transfers. */
  511. while(ctx->h3c) {
  512. curl_int64_t stream3_id = quiche_h3_conn_poll(ctx->h3c, ctx->qconn, &ev);
  513. if(stream3_id == QUICHE_H3_ERR_DONE) {
  514. break;
  515. }
  516. else if(stream3_id < 0) {
  517. CURL_TRC_CF(data, cf, "error poll: %"FMT_PRId64, stream3_id);
  518. return CURLE_HTTP3;
  519. }
  520. sdata = get_stream_easy(cf, data, stream3_id, &stream);
  521. if(!sdata || !stream) {
  522. CURL_TRC_CF(data, cf, "discard event %s for unknown [%"FMT_PRId64"]",
  523. cf_ev_name(ev), stream3_id);
  524. }
  525. else {
  526. result = h3_process_event(cf, sdata, stream, ev);
  527. h3_drain_stream(cf, sdata);
  528. if(result) {
  529. CURL_TRC_CF(data, cf, "error processing event %s "
  530. "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
  531. stream3_id, result);
  532. if(data == sdata) {
  533. /* Only report this error to the caller if it is about the
  534. * transfer we were called with. Otherwise we fail a transfer
  535. * due to a problem in another one. */
  536. quiche_h3_event_free(ev);
  537. return result;
  538. }
  539. }
  540. quiche_h3_event_free(ev);
  541. }
  542. }
  543. return CURLE_OK;
  544. }
  545. struct recv_ctx {
  546. struct Curl_cfilter *cf;
  547. struct Curl_easy *data;
  548. int pkts;
  549. };
  550. static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
  551. struct sockaddr_storage *remote_addr,
  552. socklen_t remote_addrlen, int ecn,
  553. void *userp)
  554. {
  555. struct recv_ctx *r = userp;
  556. struct cf_quiche_ctx *ctx = r->cf->ctx;
  557. quiche_recv_info recv_info;
  558. ssize_t nread;
  559. (void)ecn;
  560. ++r->pkts;
  561. recv_info.to = (struct sockaddr *)&ctx->q.local_addr;
  562. recv_info.to_len = ctx->q.local_addrlen;
  563. recv_info.from = (struct sockaddr *)remote_addr;
  564. recv_info.from_len = remote_addrlen;
  565. nread = quiche_conn_recv(ctx->qconn, (unsigned char *)pkt, pktlen,
  566. &recv_info);
  567. if(nread < 0) {
  568. if(QUICHE_ERR_DONE == nread) {
  569. if(quiche_conn_is_draining(ctx->qconn)) {
  570. CURL_TRC_CF(r->data, r->cf, "ingress, connection is draining");
  571. return CURLE_RECV_ERROR;
  572. }
  573. if(quiche_conn_is_closed(ctx->qconn)) {
  574. CURL_TRC_CF(r->data, r->cf, "ingress, connection is closed");
  575. return CURLE_RECV_ERROR;
  576. }
  577. CURL_TRC_CF(r->data, r->cf, "ingress, quiche is DONE");
  578. return CURLE_OK;
  579. }
  580. else if(QUICHE_ERR_TLS_FAIL == nread) {
  581. long verify_ok = SSL_get_verify_result(ctx->tls.ossl.ssl);
  582. if(verify_ok != X509_V_OK) {
  583. failf(r->data, "SSL certificate problem: %s",
  584. X509_verify_cert_error_string(verify_ok));
  585. return CURLE_PEER_FAILED_VERIFICATION;
  586. }
  587. }
  588. else {
  589. failf(r->data, "quiche_conn_recv() == %zd", nread);
  590. return CURLE_RECV_ERROR;
  591. }
  592. }
  593. else if((size_t)nread < pktlen) {
  594. CURL_TRC_CF(r->data, r->cf, "ingress, quiche only read %zd/%zu bytes",
  595. nread, pktlen);
  596. }
  597. return CURLE_OK;
  598. }
  599. static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
  600. struct Curl_easy *data)
  601. {
  602. struct cf_quiche_ctx *ctx = cf->ctx;
  603. struct recv_ctx rctx;
  604. CURLcode result;
  605. DEBUGASSERT(ctx->qconn);
  606. result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
  607. if(result)
  608. return result;
  609. rctx.cf = cf;
  610. rctx.data = data;
  611. rctx.pkts = 0;
  612. result = vquic_recv_packets(cf, data, &ctx->q, 1000, recv_pkt, &rctx);
  613. if(result)
  614. return result;
  615. if(rctx.pkts > 0) {
  616. /* quiche digested ingress packets. It might have opened flow control
  617. * windows again. */
  618. check_resumes(cf, data);
  619. }
  620. return cf_poll_events(cf, data);
  621. }
  622. struct read_ctx {
  623. struct Curl_cfilter *cf;
  624. struct Curl_easy *data;
  625. quiche_send_info send_info;
  626. };
  627. static ssize_t read_pkt_to_send(void *userp,
  628. unsigned char *buf, size_t buflen,
  629. CURLcode *err)
  630. {
  631. struct read_ctx *x = userp;
  632. struct cf_quiche_ctx *ctx = x->cf->ctx;
  633. ssize_t nwritten;
  634. nwritten = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info);
  635. if(nwritten == QUICHE_ERR_DONE) {
  636. *err = CURLE_AGAIN;
  637. return -1;
  638. }
  639. if(nwritten < 0) {
  640. failf(x->data, "quiche_conn_send returned %zd", nwritten);
  641. *err = CURLE_SEND_ERROR;
  642. return -1;
  643. }
  644. *err = CURLE_OK;
  645. return nwritten;
  646. }
  647. /*
  648. * flush_egress drains the buffers and sends off data.
  649. * Calls failf() on errors.
  650. */
  651. static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
  652. struct Curl_easy *data)
  653. {
  654. struct cf_quiche_ctx *ctx = cf->ctx;
  655. ssize_t nread;
  656. CURLcode result;
  657. curl_int64_t expiry_ns;
  658. curl_int64_t timeout_ns;
  659. struct read_ctx readx;
  660. size_t pkt_count, gsolen;
  661. expiry_ns = quiche_conn_timeout_as_nanos(ctx->qconn);
  662. if(!expiry_ns) {
  663. quiche_conn_on_timeout(ctx->qconn);
  664. if(quiche_conn_is_closed(ctx->qconn)) {
  665. if(quiche_conn_is_timed_out(ctx->qconn))
  666. failf(data, "connection closed by idle timeout");
  667. else
  668. failf(data, "connection closed by server");
  669. /* Connection timed out, expire all transfers belonging to it
  670. * as will not get any more POLL events here. */
  671. cf_quiche_expire_conn_closed(cf, data);
  672. return CURLE_SEND_ERROR;
  673. }
  674. }
  675. result = vquic_flush(cf, data, &ctx->q);
  676. if(result) {
  677. if(result == CURLE_AGAIN) {
  678. Curl_expire(data, 1, EXPIRE_QUIC);
  679. return CURLE_OK;
  680. }
  681. return result;
  682. }
  683. readx.cf = cf;
  684. readx.data = data;
  685. memset(&readx.send_info, 0, sizeof(readx.send_info));
  686. pkt_count = 0;
  687. gsolen = quiche_conn_max_send_udp_payload_size(ctx->qconn);
  688. for(;;) {
  689. /* add the next packet to send, if any, to our buffer */
  690. nread = Curl_bufq_sipn(&ctx->q.sendbuf, 0,
  691. read_pkt_to_send, &readx, &result);
  692. if(nread < 0) {
  693. if(result != CURLE_AGAIN)
  694. return result;
  695. /* Nothing more to add, flush and leave */
  696. result = vquic_send(cf, data, &ctx->q, gsolen);
  697. if(result) {
  698. if(result == CURLE_AGAIN) {
  699. Curl_expire(data, 1, EXPIRE_QUIC);
  700. return CURLE_OK;
  701. }
  702. return result;
  703. }
  704. goto out;
  705. }
  706. ++pkt_count;
  707. if((size_t)nread < gsolen || pkt_count >= MAX_PKT_BURST) {
  708. result = vquic_send(cf, data, &ctx->q, gsolen);
  709. if(result) {
  710. if(result == CURLE_AGAIN) {
  711. Curl_expire(data, 1, EXPIRE_QUIC);
  712. return CURLE_OK;
  713. }
  714. goto out;
  715. }
  716. pkt_count = 0;
  717. }
  718. }
  719. out:
  720. timeout_ns = quiche_conn_timeout_as_nanos(ctx->qconn);
  721. if(timeout_ns % 1000000)
  722. timeout_ns += 1000000;
  723. /* expire resolution is milliseconds */
  724. Curl_expire(data, (timeout_ns / 1000000), EXPIRE_QUIC);
  725. return result;
  726. }
  727. static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
  728. struct Curl_easy *data,
  729. CURLcode *err)
  730. {
  731. struct cf_quiche_ctx *ctx = cf->ctx;
  732. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  733. ssize_t nread = -1;
  734. DEBUGASSERT(stream);
  735. if(stream->reset) {
  736. failf(data,
  737. "HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id);
  738. *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
  739. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d",
  740. stream->id, *err);
  741. }
  742. else if(!stream->resp_got_header) {
  743. failf(data,
  744. "HTTP/3 stream %" FMT_PRIu64 " was closed cleanly, but before "
  745. "getting all response header fields, treated as error",
  746. stream->id);
  747. /* *err = CURLE_PARTIAL_FILE; */
  748. *err = CURLE_HTTP3;
  749. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, closed incomplete"
  750. " -> %d", stream->id, *err);
  751. }
  752. else {
  753. *err = CURLE_OK;
  754. nread = 0;
  755. }
  756. return nread;
  757. }
  758. static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
  759. char *buf, size_t len, CURLcode *err)
  760. {
  761. struct cf_quiche_ctx *ctx = cf->ctx;
  762. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  763. ssize_t nread = -1;
  764. CURLcode result;
  765. vquic_ctx_update_time(&ctx->q);
  766. if(!stream) {
  767. *err = CURLE_RECV_ERROR;
  768. return -1;
  769. }
  770. if(!Curl_bufq_is_empty(&stream->recvbuf)) {
  771. nread = Curl_bufq_read(&stream->recvbuf,
  772. (unsigned char *)buf, len, err);
  773. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
  774. "-> %zd, %d", stream->id, len, nread, *err);
  775. if(nread < 0)
  776. goto out;
  777. }
  778. if(cf_process_ingress(cf, data)) {
  779. CURL_TRC_CF(data, cf, "cf_recv, error on ingress");
  780. *err = CURLE_RECV_ERROR;
  781. nread = -1;
  782. goto out;
  783. }
  784. /* recvbuf had nothing before, maybe after progressing ingress? */
  785. if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
  786. nread = Curl_bufq_read(&stream->recvbuf,
  787. (unsigned char *)buf, len, err);
  788. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
  789. "-> %zd, %d", stream->id, len, nread, *err);
  790. if(nread < 0)
  791. goto out;
  792. }
  793. if(nread > 0) {
  794. if(stream->closed)
  795. h3_drain_stream(cf, data);
  796. }
  797. else {
  798. if(stream->closed) {
  799. nread = recv_closed_stream(cf, data, err);
  800. goto out;
  801. }
  802. else if(quiche_conn_is_draining(ctx->qconn)) {
  803. failf(data, "QUIC connection is draining");
  804. *err = CURLE_HTTP3;
  805. nread = -1;
  806. goto out;
  807. }
  808. *err = CURLE_AGAIN;
  809. nread = -1;
  810. }
  811. out:
  812. result = cf_flush_egress(cf, data);
  813. if(result) {
  814. CURL_TRC_CF(data, cf, "cf_recv, flush egress failed");
  815. *err = result;
  816. nread = -1;
  817. }
  818. if(nread > 0)
  819. ctx->data_recvd += nread;
  820. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] cf_recv(total=%"
  821. FMT_OFF_T ") -> %zd, %d",
  822. stream->id, ctx->data_recvd, nread, *err);
  823. return nread;
  824. }
  825. static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf,
  826. struct Curl_easy *data,
  827. struct stream_ctx *stream,
  828. const void *buf, size_t len, bool eos,
  829. CURLcode *err)
  830. {
  831. struct cf_quiche_ctx *ctx = cf->ctx;
  832. ssize_t nwritten;
  833. nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
  834. (uint8_t *)buf, len, eos);
  835. if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
  836. /* TODO: we seem to be blocked on flow control and should HOLD
  837. * sending. But when do we open again? */
  838. if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
  839. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
  840. "-> window exhausted", stream->id, len);
  841. stream->quic_flow_blocked = TRUE;
  842. }
  843. *err = CURLE_AGAIN;
  844. return -1;
  845. }
  846. else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
  847. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
  848. "-> invalid stream state", stream->id, len);
  849. *err = CURLE_HTTP3;
  850. return -1;
  851. }
  852. else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
  853. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
  854. "-> exceeds size", stream->id, len);
  855. *err = CURLE_SEND_ERROR;
  856. return -1;
  857. }
  858. else if(nwritten < 0) {
  859. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
  860. "-> quiche err %zd", stream->id, len, nwritten);
  861. *err = CURLE_SEND_ERROR;
  862. return -1;
  863. }
  864. else {
  865. if(eos && (len == (size_t)nwritten))
  866. stream->send_closed = TRUE;
  867. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send body(len=%zu, "
  868. "eos=%d) -> %zd",
  869. stream->id, len, stream->send_closed, nwritten);
  870. *err = CURLE_OK;
  871. return nwritten;
  872. }
  873. }
  874. /* Index where :authority header field will appear in request header
  875. field list. */
  876. #define AUTHORITY_DST_IDX 3
  877. static ssize_t h3_open_stream(struct Curl_cfilter *cf,
  878. struct Curl_easy *data,
  879. const char *buf, size_t len, bool eos,
  880. CURLcode *err)
  881. {
  882. struct cf_quiche_ctx *ctx = cf->ctx;
  883. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  884. size_t nheader, i;
  885. curl_int64_t stream3_id;
  886. struct dynhds h2_headers;
  887. quiche_h3_header *nva = NULL;
  888. ssize_t nwritten;
  889. if(!stream) {
  890. *err = h3_data_setup(cf, data);
  891. if(*err) {
  892. return -1;
  893. }
  894. stream = H3_STREAM_CTX(ctx, data);
  895. DEBUGASSERT(stream);
  896. }
  897. Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
  898. DEBUGASSERT(stream);
  899. nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
  900. if(nwritten < 0)
  901. goto out;
  902. if(!stream->h1.done) {
  903. /* need more data */
  904. goto out;
  905. }
  906. DEBUGASSERT(stream->h1.req);
  907. *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
  908. if(*err) {
  909. nwritten = -1;
  910. goto out;
  911. }
  912. /* no longer needed */
  913. Curl_h1_req_parse_free(&stream->h1);
  914. nheader = Curl_dynhds_count(&h2_headers);
  915. nva = malloc(sizeof(quiche_h3_header) * nheader);
  916. if(!nva) {
  917. *err = CURLE_OUT_OF_MEMORY;
  918. nwritten = -1;
  919. goto out;
  920. }
  921. for(i = 0; i < nheader; ++i) {
  922. struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
  923. nva[i].name = (unsigned char *)e->name;
  924. nva[i].name_len = e->namelen;
  925. nva[i].value = (unsigned char *)e->value;
  926. nva[i].value_len = e->valuelen;
  927. }
  928. if(eos && ((size_t)nwritten == len))
  929. stream->send_closed = TRUE;
  930. stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader,
  931. stream->send_closed);
  932. if(stream3_id < 0) {
  933. if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) {
  934. /* quiche seems to report this error if the connection window is
  935. * exhausted. Which happens frequently and intermittent. */
  936. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] blocked", stream->id);
  937. stream->quic_flow_blocked = TRUE;
  938. *err = CURLE_AGAIN;
  939. nwritten = -1;
  940. goto out;
  941. }
  942. else {
  943. CURL_TRC_CF(data, cf, "send_request(%s) -> %" FMT_PRIu64,
  944. data->state.url, stream3_id);
  945. }
  946. *err = CURLE_SEND_ERROR;
  947. nwritten = -1;
  948. goto out;
  949. }
  950. DEBUGASSERT(!stream->opened);
  951. *err = CURLE_OK;
  952. stream->id = stream3_id;
  953. stream->opened = TRUE;
  954. stream->closed = FALSE;
  955. stream->reset = FALSE;
  956. if(Curl_trc_is_verbose(data)) {
  957. infof(data, "[HTTP/3] [%" FMT_PRIu64 "] OPENED stream for %s",
  958. stream->id, data->state.url);
  959. for(i = 0; i < nheader; ++i) {
  960. infof(data, "[HTTP/3] [%" FMT_PRIu64 "] [%.*s: %.*s]", stream->id,
  961. (int)nva[i].name_len, nva[i].name,
  962. (int)nva[i].value_len, nva[i].value);
  963. }
  964. }
  965. if(nwritten > 0 && ((size_t)nwritten < len)) {
  966. /* after the headers, there was request BODY data */
  967. size_t hds_len = (size_t)nwritten;
  968. ssize_t bwritten;
  969. bwritten = cf_quiche_send_body(cf, data, stream,
  970. buf + hds_len, len - hds_len, eos, err);
  971. if((bwritten < 0) && (CURLE_AGAIN != *err)) {
  972. /* real error, fail */
  973. nwritten = -1;
  974. }
  975. else if(bwritten > 0) {
  976. nwritten += bwritten;
  977. }
  978. }
  979. out:
  980. free(nva);
  981. Curl_dynhds_free(&h2_headers);
  982. return nwritten;
  983. }
  984. static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
  985. const void *buf, size_t len, bool eos,
  986. CURLcode *err)
  987. {
  988. struct cf_quiche_ctx *ctx = cf->ctx;
  989. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  990. CURLcode result;
  991. ssize_t nwritten;
  992. vquic_ctx_update_time(&ctx->q);
  993. *err = cf_process_ingress(cf, data);
  994. if(*err) {
  995. nwritten = -1;
  996. goto out;
  997. }
  998. if(!stream || !stream->opened) {
  999. nwritten = h3_open_stream(cf, data, buf, len, eos, err);
  1000. if(nwritten < 0)
  1001. goto out;
  1002. stream = H3_STREAM_CTX(ctx, data);
  1003. }
  1004. else if(stream->closed) {
  1005. if(stream->resp_hds_complete) {
  1006. /* sending request body on a stream that has been closed by the
  1007. * server. If the server has send us a final response, we should
  1008. * silently discard the send data.
  1009. * This happens for example on redirects where the server, instead
  1010. * of reading the full request body just closed the stream after
  1011. * sending the 30x response.
  1012. * This is sort of a race: had the transfer loop called recv first,
  1013. * it would see the response and stop/discard sending on its own- */
  1014. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] discarding data"
  1015. "on closed stream with response", stream->id);
  1016. *err = CURLE_OK;
  1017. nwritten = (ssize_t)len;
  1018. goto out;
  1019. }
  1020. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
  1021. "-> stream closed", stream->id, len);
  1022. *err = CURLE_HTTP3;
  1023. nwritten = -1;
  1024. goto out;
  1025. }
  1026. else {
  1027. nwritten = cf_quiche_send_body(cf, data, stream, buf, len, eos, err);
  1028. }
  1029. out:
  1030. result = cf_flush_egress(cf, data);
  1031. if(result) {
  1032. *err = result;
  1033. nwritten = -1;
  1034. }
  1035. CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
  1036. stream ? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
  1037. return nwritten;
  1038. }
  1039. static bool stream_is_writeable(struct Curl_cfilter *cf,
  1040. struct Curl_easy *data)
  1041. {
  1042. struct cf_quiche_ctx *ctx = cf->ctx;
  1043. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  1044. return stream && (quiche_conn_stream_writable(
  1045. ctx->qconn, (curl_uint64_t)stream->id, 1) > 0);
  1046. }
  1047. static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
  1048. struct Curl_easy *data,
  1049. struct easy_pollset *ps)
  1050. {
  1051. struct cf_quiche_ctx *ctx = cf->ctx;
  1052. bool want_recv, want_send;
  1053. if(!ctx->qconn)
  1054. return;
  1055. Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
  1056. if(want_recv || want_send) {
  1057. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  1058. bool c_exhaust, s_exhaust;
  1059. c_exhaust = FALSE; /* Have not found any call in quiche that tells
  1060. us if the connection itself is blocked */
  1061. s_exhaust = want_send && stream && stream->opened &&
  1062. (stream->quic_flow_blocked || !stream_is_writeable(cf, data));
  1063. want_recv = (want_recv || c_exhaust || s_exhaust);
  1064. want_send = (!s_exhaust && want_send) ||
  1065. !Curl_bufq_is_empty(&ctx->q.sendbuf);
  1066. Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
  1067. }
  1068. }
  1069. /*
  1070. * Called from transfer.c:data_pending to know if we should keep looping
  1071. * to receive more data from the connection.
  1072. */
  1073. static bool cf_quiche_data_pending(struct Curl_cfilter *cf,
  1074. const struct Curl_easy *data)
  1075. {
  1076. struct cf_quiche_ctx *ctx = cf->ctx;
  1077. const struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  1078. (void)cf;
  1079. return stream && !Curl_bufq_is_empty(&stream->recvbuf);
  1080. }
  1081. static CURLcode h3_data_pause(struct Curl_cfilter *cf,
  1082. struct Curl_easy *data,
  1083. bool pause)
  1084. {
  1085. /* TODO: there seems right now no API in quiche to shrink/enlarge
  1086. * the streams windows. As we do in HTTP/2. */
  1087. if(!pause) {
  1088. h3_drain_stream(cf, data);
  1089. Curl_expire(data, 0, EXPIRE_RUN_NOW);
  1090. }
  1091. return CURLE_OK;
  1092. }
  1093. static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
  1094. struct Curl_easy *data,
  1095. int event, int arg1, void *arg2)
  1096. {
  1097. struct cf_quiche_ctx *ctx = cf->ctx;
  1098. CURLcode result = CURLE_OK;
  1099. (void)arg1;
  1100. (void)arg2;
  1101. switch(event) {
  1102. case CF_CTRL_DATA_SETUP:
  1103. break;
  1104. case CF_CTRL_DATA_PAUSE:
  1105. result = h3_data_pause(cf, data, (arg1 != 0));
  1106. break;
  1107. case CF_CTRL_DATA_DETACH:
  1108. h3_data_done(cf, data);
  1109. break;
  1110. case CF_CTRL_DATA_DONE:
  1111. h3_data_done(cf, data);
  1112. break;
  1113. case CF_CTRL_DATA_DONE_SEND: {
  1114. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  1115. if(stream && !stream->send_closed) {
  1116. unsigned char body[1];
  1117. ssize_t sent;
  1118. stream->send_closed = TRUE;
  1119. body[0] = 'X';
  1120. sent = cf_quiche_send(cf, data, body, 0, TRUE, &result);
  1121. CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] DONE_SEND -> %zd, %d",
  1122. stream->id, sent, result);
  1123. }
  1124. break;
  1125. }
  1126. case CF_CTRL_DATA_IDLE: {
  1127. struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
  1128. if(stream && !stream->closed) {
  1129. result = cf_flush_egress(cf, data);
  1130. if(result)
  1131. CURL_TRC_CF(data, cf, "data idle, flush egress -> %d", result);
  1132. }
  1133. break;
  1134. }
  1135. default:
  1136. break;
  1137. }
  1138. return result;
  1139. }
  1140. static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
  1141. struct Curl_easy *data)
  1142. {
  1143. struct cf_quiche_ctx *ctx = cf->ctx;
  1144. int rv;
  1145. CURLcode result;
  1146. const struct Curl_sockaddr_ex *sockaddr;
  1147. DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
  1148. DEBUGASSERT(ctx->initialized);
  1149. result = vquic_ctx_init(&ctx->q);
  1150. if(result)
  1151. return result;
  1152. result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
  1153. if(result)
  1154. return result;
  1155. ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
  1156. if(!ctx->cfg) {
  1157. failf(data, "cannot create quiche config");
  1158. return CURLE_FAILED_INIT;
  1159. }
  1160. quiche_config_enable_pacing(ctx->cfg, FALSE);
  1161. quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
  1162. quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
  1163. /* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
  1164. quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);
  1165. quiche_config_set_initial_max_streams_uni(ctx->cfg, QUIC_MAX_STREAMS);
  1166. quiche_config_set_initial_max_stream_data_bidi_local(ctx->cfg,
  1167. H3_STREAM_WINDOW_SIZE);
  1168. quiche_config_set_initial_max_stream_data_bidi_remote(ctx->cfg,
  1169. H3_STREAM_WINDOW_SIZE);
  1170. quiche_config_set_initial_max_stream_data_uni(ctx->cfg,
  1171. H3_STREAM_WINDOW_SIZE);
  1172. quiche_config_set_disable_active_migration(ctx->cfg, TRUE);
  1173. quiche_config_set_max_connection_window(ctx->cfg,
  1174. 10 * QUIC_MAX_STREAMS * H3_STREAM_WINDOW_SIZE);
  1175. quiche_config_set_max_stream_window(ctx->cfg, 10 * H3_STREAM_WINDOW_SIZE);
  1176. quiche_config_set_application_protos(ctx->cfg,
  1177. (uint8_t *)
  1178. QUICHE_H3_APPLICATION_PROTOCOL,
  1179. sizeof(QUICHE_H3_APPLICATION_PROTOCOL)
  1180. - 1);
  1181. result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
  1182. QUICHE_H3_APPLICATION_PROTOCOL,
  1183. sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
  1184. NULL, NULL, cf);
  1185. if(result)
  1186. return result;
  1187. result = Curl_rand(data, ctx->scid, sizeof(ctx->scid));
  1188. if(result)
  1189. return result;
  1190. Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
  1191. ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
  1192. rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
  1193. &ctx->q.local_addrlen);
  1194. if(rv == -1)
  1195. return CURLE_QUIC_CONNECT_ERROR;
  1196. ctx->qconn = quiche_conn_new_with_tls((const uint8_t *)ctx->scid,
  1197. sizeof(ctx->scid), NULL, 0,
  1198. (struct sockaddr *)&ctx->q.local_addr,
  1199. ctx->q.local_addrlen,
  1200. &sockaddr->curl_sa_addr,
  1201. sockaddr->addrlen,
  1202. ctx->cfg, ctx->tls.ossl.ssl, FALSE);
  1203. if(!ctx->qconn) {
  1204. failf(data, "cannot create quiche connection");
  1205. return CURLE_OUT_OF_MEMORY;
  1206. }
  1207. /* Known to not work on Windows */
  1208. #if !defined(_WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
  1209. {
  1210. int qfd;
  1211. (void)Curl_qlogdir(data, ctx->scid, sizeof(ctx->scid), &qfd);
  1212. if(qfd != -1)
  1213. quiche_conn_set_qlog_fd(ctx->qconn, qfd,
  1214. "qlog title", "curl qlog");
  1215. }
  1216. #endif
  1217. result = cf_flush_egress(cf, data);
  1218. if(result)
  1219. return result;
  1220. {
  1221. unsigned char alpn_protocols[] = QUICHE_H3_APPLICATION_PROTOCOL;
  1222. unsigned alpn_len, offset = 0;
  1223. /* Replace each ALPN length prefix by a comma. */
  1224. while(offset < sizeof(alpn_protocols) - 1) {
  1225. alpn_len = alpn_protocols[offset];
  1226. alpn_protocols[offset] = ',';
  1227. offset += 1 + alpn_len;
  1228. }
  1229. CURL_TRC_CF(data, cf, "Sent QUIC client Initial, ALPN: %s",
  1230. alpn_protocols + 1);
  1231. }
  1232. return CURLE_OK;
  1233. }
  1234. static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf,
  1235. struct Curl_easy *data)
  1236. {
  1237. struct cf_quiche_ctx *ctx = cf->ctx;
  1238. cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
  1239. cf->conn->httpversion = 30;
  1240. return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
  1241. }
  1242. static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
  1243. struct Curl_easy *data,
  1244. bool blocking, bool *done)
  1245. {
  1246. struct cf_quiche_ctx *ctx = cf->ctx;
  1247. CURLcode result = CURLE_OK;
  1248. if(cf->connected) {
  1249. *done = TRUE;
  1250. return CURLE_OK;
  1251. }
  1252. /* Connect the UDP filter first */
  1253. if(!cf->next->connected) {
  1254. result = Curl_conn_cf_connect(cf->next, data, blocking, done);
  1255. if(result || !*done)
  1256. return result;
  1257. }
  1258. *done = FALSE;
  1259. vquic_ctx_update_time(&ctx->q);
  1260. if(!ctx->qconn) {
  1261. result = cf_quiche_ctx_open(cf, data);
  1262. if(result)
  1263. goto out;
  1264. ctx->started_at = ctx->q.last_op;
  1265. result = cf_flush_egress(cf, data);
  1266. /* we do not expect to be able to recv anything yet */
  1267. goto out;
  1268. }
  1269. result = cf_process_ingress(cf, data);
  1270. if(result)
  1271. goto out;
  1272. result = cf_flush_egress(cf, data);
  1273. if(result)
  1274. goto out;
  1275. if(quiche_conn_is_established(ctx->qconn)) {
  1276. ctx->handshake_at = ctx->q.last_op;
  1277. CURL_TRC_CF(data, cf, "handshake complete after %dms",
  1278. (int)Curl_timediff(ctx->handshake_at, ctx->started_at));
  1279. result = cf_quiche_verify_peer(cf, data);
  1280. if(!result) {
  1281. CURL_TRC_CF(data, cf, "peer verified");
  1282. ctx->h3config = quiche_h3_config_new();
  1283. if(!ctx->h3config) {
  1284. result = CURLE_OUT_OF_MEMORY;
  1285. goto out;
  1286. }
  1287. /* Create a new HTTP/3 connection on the QUIC connection. */
  1288. ctx->h3c = quiche_h3_conn_new_with_transport(ctx->qconn, ctx->h3config);
  1289. if(!ctx->h3c) {
  1290. result = CURLE_OUT_OF_MEMORY;
  1291. goto out;
  1292. }
  1293. cf->connected = TRUE;
  1294. cf->conn->alpn = CURL_HTTP_VERSION_3;
  1295. *done = TRUE;
  1296. connkeep(cf->conn, "HTTP/3 default");
  1297. }
  1298. }
  1299. else if(quiche_conn_is_draining(ctx->qconn)) {
  1300. /* When a QUIC server instance is shutting down, it may send us a
  1301. * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
  1302. * state. The CONNECT may work in the near future again. Indicate
  1303. * that as a "weird" reply. */
  1304. result = CURLE_WEIRD_SERVER_REPLY;
  1305. }
  1306. out:
  1307. #ifndef CURL_DISABLE_VERBOSE_STRINGS
  1308. if(result && result != CURLE_AGAIN) {
  1309. struct ip_quadruple ip;
  1310. Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
  1311. infof(data, "connect to %s port %u failed: %s",
  1312. ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
  1313. }
  1314. #endif
  1315. return result;
  1316. }
  1317. static CURLcode cf_quiche_shutdown(struct Curl_cfilter *cf,
  1318. struct Curl_easy *data, bool *done)
  1319. {
  1320. struct cf_quiche_ctx *ctx = cf->ctx;
  1321. CURLcode result = CURLE_OK;
  1322. if(cf->shutdown || !ctx || !ctx->qconn) {
  1323. *done = TRUE;
  1324. return CURLE_OK;
  1325. }
  1326. *done = FALSE;
  1327. if(!ctx->shutdown_started) {
  1328. int err;
  1329. ctx->shutdown_started = TRUE;
  1330. vquic_ctx_update_time(&ctx->q);
  1331. err = quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);
  1332. if(err) {
  1333. CURL_TRC_CF(data, cf, "error %d adding shutdown packet, "
  1334. "aborting shutdown", err);
  1335. result = CURLE_SEND_ERROR;
  1336. goto out;
  1337. }
  1338. }
  1339. if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
  1340. CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf");
  1341. result = cf_flush_egress(cf, data);
  1342. if(result)
  1343. goto out;
  1344. }
  1345. if(Curl_bufq_is_empty(&ctx->q.sendbuf)) {
  1346. /* sent everything, quiche does not seem to support a graceful
  1347. * shutdown waiting for a reply, so ware done. */
  1348. CURL_TRC_CF(data, cf, "shutdown completely sent off, done");
  1349. *done = TRUE;
  1350. }
  1351. else {
  1352. CURL_TRC_CF(data, cf, "shutdown sending blocked");
  1353. }
  1354. out:
  1355. return result;
  1356. }
  1357. static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
  1358. {
  1359. if(cf->ctx) {
  1360. bool done;
  1361. (void)cf_quiche_shutdown(cf, data, &done);
  1362. cf_quiche_ctx_close(cf->ctx);
  1363. }
  1364. }
  1365. static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
  1366. {
  1367. (void)data;
  1368. if(cf->ctx) {
  1369. cf_quiche_ctx_free(cf->ctx);
  1370. cf->ctx = NULL;
  1371. }
  1372. }
  1373. static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
  1374. struct Curl_easy *data,
  1375. int query, int *pres1, void *pres2)
  1376. {
  1377. struct cf_quiche_ctx *ctx = cf->ctx;
  1378. switch(query) {
  1379. case CF_QUERY_MAX_CONCURRENT: {
  1380. curl_uint64_t max_streams = CONN_INUSE(cf->conn);
  1381. if(!ctx->goaway) {
  1382. max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
  1383. }
  1384. *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
  1385. CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
  1386. "MAX_CONCURRENT -> %d (%zu in use)",
  1387. cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
  1388. return CURLE_OK;
  1389. }
  1390. case CF_QUERY_CONNECT_REPLY_MS:
  1391. if(ctx->q.got_first_byte) {
  1392. timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
  1393. *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
  1394. }
  1395. else
  1396. *pres1 = -1;
  1397. return CURLE_OK;
  1398. case CF_QUERY_TIMER_CONNECT: {
  1399. struct curltime *when = pres2;
  1400. if(ctx->q.got_first_byte)
  1401. *when = ctx->q.first_byte_at;
  1402. return CURLE_OK;
  1403. }
  1404. case CF_QUERY_TIMER_APPCONNECT: {
  1405. struct curltime *when = pres2;
  1406. if(cf->connected)
  1407. *when = ctx->handshake_at;
  1408. return CURLE_OK;
  1409. }
  1410. default:
  1411. break;
  1412. }
  1413. return cf->next ?
  1414. cf->next->cft->query(cf->next, data, query, pres1, pres2) :
  1415. CURLE_UNKNOWN_OPTION;
  1416. }
  1417. static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
  1418. struct Curl_easy *data,
  1419. bool *input_pending)
  1420. {
  1421. struct cf_quiche_ctx *ctx = cf->ctx;
  1422. bool alive = TRUE;
  1423. *input_pending = FALSE;
  1424. if(!ctx->qconn)
  1425. return FALSE;
  1426. if(quiche_conn_is_closed(ctx->qconn)) {
  1427. if(quiche_conn_is_timed_out(ctx->qconn))
  1428. CURL_TRC_CF(data, cf, "connection was closed due to idle timeout");
  1429. else
  1430. CURL_TRC_CF(data, cf, "connection is closed");
  1431. return FALSE;
  1432. }
  1433. if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
  1434. return FALSE;
  1435. if(*input_pending) {
  1436. /* This happens before we have sent off a request and the connection is
  1437. not in use by any other transfer, there should not be any data here,
  1438. only "protocol frames" */
  1439. *input_pending = FALSE;
  1440. if(cf_process_ingress(cf, data))
  1441. alive = FALSE;
  1442. else {
  1443. alive = TRUE;
  1444. }
  1445. }
  1446. return alive;
  1447. }
  1448. struct Curl_cftype Curl_cft_http3 = {
  1449. "HTTP/3",
  1450. CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  1451. 0,
  1452. cf_quiche_destroy,
  1453. cf_quiche_connect,
  1454. cf_quiche_close,
  1455. cf_quiche_shutdown,
  1456. Curl_cf_def_get_host,
  1457. cf_quiche_adjust_pollset,
  1458. cf_quiche_data_pending,
  1459. cf_quiche_send,
  1460. cf_quiche_recv,
  1461. cf_quiche_data_event,
  1462. cf_quiche_conn_is_alive,
  1463. Curl_cf_def_conn_keep_alive,
  1464. cf_quiche_query,
  1465. };
  1466. CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
  1467. struct Curl_easy *data,
  1468. struct connectdata *conn,
  1469. const struct Curl_addrinfo *ai)
  1470. {
  1471. struct cf_quiche_ctx *ctx = NULL;
  1472. struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
  1473. CURLcode result;
  1474. (void)data;
  1475. (void)conn;
  1476. ctx = calloc(1, sizeof(*ctx));
  1477. if(!ctx) {
  1478. result = CURLE_OUT_OF_MEMORY;
  1479. goto out;
  1480. }
  1481. cf_quiche_ctx_init(ctx);
  1482. result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
  1483. if(result)
  1484. goto out;
  1485. result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
  1486. if(result)
  1487. goto out;
  1488. udp_cf->conn = cf->conn;
  1489. udp_cf->sockindex = cf->sockindex;
  1490. cf->next = udp_cf;
  1491. out:
  1492. *pcf = (!result) ? cf : NULL;
  1493. if(result) {
  1494. if(udp_cf)
  1495. Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
  1496. Curl_safefree(cf);
  1497. cf_quiche_ctx_free(ctx);
  1498. }
  1499. return result;
  1500. }
  1501. bool Curl_conn_is_quiche(const struct Curl_easy *data,
  1502. const struct connectdata *conn,
  1503. int sockindex)
  1504. {
  1505. struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
  1506. (void)data;
  1507. for(; cf; cf = cf->next) {
  1508. if(cf->cft == &Curl_cft_http3)
  1509. return TRUE;
  1510. if(cf->cft->flags & CF_TYPE_IP_CONNECT)
  1511. return FALSE;
  1512. }
  1513. return FALSE;
  1514. }
  1515. #endif