msh3.c 17 KB

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