curl_quiche.c 49 KB

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