2
0

curl_quiche.c 49 KB

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