diff options
Diffstat (limited to 'Utilities/cmcurl/lib/vquic/ngtcp2.c')
-rw-r--r-- | Utilities/cmcurl/lib/vquic/ngtcp2.c | 267 |
1 files changed, 129 insertions, 138 deletions
diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.c b/Utilities/cmcurl/lib/vquic/ngtcp2.c index 0f2fea0..d4d0e8b 100644 --- a/Utilities/cmcurl/lib/vquic/ngtcp2.c +++ b/Utilities/cmcurl/lib/vquic/ngtcp2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -87,10 +87,10 @@ struct h3out { "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1" #endif -static CURLcode ng_process_ingress(struct connectdata *conn, +static CURLcode ng_process_ingress(struct Curl_easy *data, curl_socket_t sockfd, struct quicsocket *qs); -static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, +static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd, struct quicsocket *qs); static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, size_t datalen, void *user_data, @@ -170,20 +170,22 @@ static void quic_settings(struct quicsocket *qs, uint64_t stream_buffer_size) { ngtcp2_settings *s = &qs->settings; + ngtcp2_transport_params *t = &qs->transport_params; ngtcp2_settings_default(s); + ngtcp2_transport_params_default(t); #ifdef DEBUG_NGTCP2 s->log_printf = quic_printf; #else s->log_printf = NULL; #endif s->initial_ts = timestamp(); - s->transport_params.initial_max_stream_data_bidi_local = stream_buffer_size; - s->transport_params.initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS; - s->transport_params.initial_max_stream_data_uni = QUIC_MAX_STREAMS; - s->transport_params.initial_max_data = QUIC_MAX_DATA; - s->transport_params.initial_max_streams_bidi = 1; - s->transport_params.initial_max_streams_uni = 3; - s->transport_params.max_idle_timeout = QUIC_IDLE_TIMEOUT; + t->initial_max_stream_data_bidi_local = stream_buffer_size; + t->initial_max_stream_data_bidi_remote = QUIC_MAX_STREAMS; + t->initial_max_stream_data_uni = QUIC_MAX_STREAMS; + t->initial_max_data = QUIC_MAX_DATA; + t->initial_max_streams_bidi = 1; + t->initial_max_streams_uni = 3; + t->max_idle_timeout = QUIC_IDLE_TIMEOUT; if(qs->qlogfd != -1) { s->qlog.write = qlog_callback; } @@ -556,10 +558,8 @@ cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level, static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) { - struct quicsocket *qs = (struct quicsocket *)user_data; + (void)user_data; (void)tconn; - infof(qs->conn->data, "QUIC handshake is completed\n"); - return 0; } @@ -587,8 +587,6 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags, nconsumed = nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin); if(nconsumed < 0) { - failf(qs->conn->data, "nghttp3_conn_read_stream returned error: %s\n", - nghttp3_strerror((int)nconsumed)); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -616,8 +614,6 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id, rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen); if(rv != 0) { - failf(qs->conn->data, "nghttp3_conn_add_ack_offset returned error: %s\n", - nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -637,8 +633,6 @@ static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id, rv = nghttp3_conn_close_stream(qs->h3conn, stream_id, app_error_code); if(rv != 0) { - failf(qs->conn->data, "nghttp3_conn_close_stream returned error: %s\n", - nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -658,8 +652,6 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id, rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id); if(rv != 0) { - failf(qs->conn->data, "nghttp3_conn_reset_stream returned error: %s\n", - nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -689,8 +681,6 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id, rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id); if(rv != 0) { - failf(qs->conn->data, "nghttp3_conn_unblock_stream returned error: %s\n", - nghttp3_strerror(rv)); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -701,23 +691,23 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, uint8_t *token, size_t cidlen, void *user_data) { - struct quicsocket *qs = (struct quicsocket *)user_data; CURLcode result; (void)tconn; + (void)user_data; - result = Curl_rand(qs->conn->data, cid->data, cidlen); + result = Curl_rand(NULL, cid->data, cidlen); if(result) return NGTCP2_ERR_CALLBACK_FAILURE; cid->datalen = cidlen; - result = Curl_rand(qs->conn->data, token, NGTCP2_STATELESS_RESET_TOKENLEN); + result = Curl_rand(NULL, token, NGTCP2_STATELESS_RESET_TOKENLEN); if(result) return NGTCP2_ERR_CALLBACK_FAILURE; return 0; } -static ngtcp2_conn_callbacks ng_callbacks = { +static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_client_initial_cb, NULL, /* recv_client_initial */ cb_recv_crypto_data, @@ -755,7 +745,8 @@ static ngtcp2_conn_callbacks ng_callbacks = { /* * Might be called twice for happy eyeballs. */ -CURLcode Curl_quic_connect(struct connectdata *conn, +CURLcode Curl_quic_connect(struct Curl_easy *data, + struct connectdata *conn, curl_socket_t sockfd, int sockindex, const struct sockaddr *addr, @@ -765,14 +756,13 @@ CURLcode Curl_quic_connect(struct connectdata *conn, int rv; CURLcode result; ngtcp2_path path; /* TODO: this must be initialized properly */ - struct Curl_easy *data = conn->data; struct quicsocket *qs = &conn->hequic[sockindex]; char ipbuf[40]; long port; int qfd; if(qs->conn) - Curl_quic_disconnect(conn, sockindex); + Curl_quic_disconnect(data, conn, sockindex); qs->conn = conn; /* extract the used address as a string */ @@ -822,7 +812,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, NGTCP2_PROTO_VER_MIN, &ng_callbacks, - &qs->settings, NULL, qs); + &qs->settings, &qs->transport_params, NULL, qs); if(rc) return CURLE_QUIC_CONNECT_ERROR; @@ -843,9 +833,10 @@ int Curl_quic_ver(char *p, size_t len) ng2->version_str, ht3->version_str); } -static int ng_getsock(struct connectdata *conn, curl_socket_t *socks) +static int ng_getsock(struct Curl_easy *data, struct connectdata *conn, + curl_socket_t *socks) { - struct SingleRequest *k = &conn->data->req; + struct SingleRequest *k = &data->req; int bitmap = GETSOCK_BLANK; socks[0] = conn->sock[FIRSTSOCKET]; @@ -861,12 +852,6 @@ static int ng_getsock(struct connectdata *conn, curl_socket_t *socks) return bitmap; } -static int ng_perform_getsock(const struct connectdata *conn, - curl_socket_t *socks) -{ - return ng_getsock((struct connectdata *)conn, socks); -} - static void qs_disconnect(struct quicsocket *qs) { int i; @@ -897,25 +882,30 @@ static void qs_disconnect(struct quicsocket *qs) #endif } -void Curl_quic_disconnect(struct connectdata *conn, +void Curl_quic_disconnect(struct Curl_easy *data, + struct connectdata *conn, int tempindex) { + (void)data; if(conn->transport == TRNSPRT_QUIC) qs_disconnect(&conn->hequic[tempindex]); } -static CURLcode ng_disconnect(struct connectdata *conn, +static CURLcode ng_disconnect(struct Curl_easy *data, + struct connectdata *conn, bool dead_connection) { (void)dead_connection; - Curl_quic_disconnect(conn, 0); - Curl_quic_disconnect(conn, 1); + Curl_quic_disconnect(data, conn, 0); + Curl_quic_disconnect(data, conn, 1); return CURLE_OK; } -static unsigned int ng_conncheck(struct connectdata *conn, +static unsigned int ng_conncheck(struct Curl_easy *data, + struct connectdata *conn, unsigned int checks_to_perform) { + (void)data; (void)conn; (void)checks_to_perform; return CONNRESULT_NONE; @@ -933,7 +923,7 @@ static const struct Curl_handler Curl_handler_http3 = { ng_getsock, /* proto_getsock */ ng_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ - ng_perform_getsock, /* perform_getsock */ + ng_getsock, /* perform_getsock */ ng_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ ng_conncheck, /* connection_check */ @@ -1134,7 +1124,7 @@ static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id, return 0; } -static nghttp3_conn_callbacks ngh3_callbacks = { +static nghttp3_callbacks ngh3_callbacks = { cb_h3_acked_stream_data, /* acked_stream_data */ cb_h3_stream_close, cb_h3_recv_data, @@ -1162,11 +1152,10 @@ static int init_ngh3_conn(struct quicsocket *qs) int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id; if(ngtcp2_conn_get_max_local_streams_uni(qs->qconn) < 3) { - failf(qs->conn->data, "too few available QUIC streams"); return CURLE_QUIC_CONNECT_ERROR; } - nghttp3_conn_settings_default(&qs->h3settings); + nghttp3_settings_default(&qs->h3settings); rc = nghttp3_conn_client_new(&qs->h3conn, &ngh3_callbacks, @@ -1235,14 +1224,15 @@ static size_t drain_overflow_buffer(struct HTTP *stream) } /* incoming data frames on the h3 stream */ -static ssize_t ngh3_stream_recv(struct connectdata *conn, +static ssize_t ngh3_stream_recv(struct Curl_easy *data, int sockindex, char *buf, size_t buffersize, CURLcode *curlcode) { + struct connectdata *conn = data->conn; curl_socket_t sockfd = conn->sock[sockindex]; - struct HTTP *stream = conn->data->req.p.http; + struct HTTP *stream = data->req.p.http; struct quicsocket *qs = conn->quic; if(!stream->memlen) { @@ -1257,11 +1247,11 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn, as possible to the receive buffer before receiving more */ drain_overflow_buffer(stream); - if(ng_process_ingress(conn, sockfd, qs)) { + if(ng_process_ingress(data, sockfd, qs)) { *curlcode = CURLE_RECV_ERROR; return -1; } - if(ng_flush_egress(conn, sockfd, qs)) { + if(ng_flush_egress(data, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } @@ -1277,7 +1267,7 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn, /* extend the stream window with the data we're consuming and send out any additional packets to tell the server that we can receive more */ extend_stream_window(qs->qconn, stream); - if(ng_flush_egress(conn, sockfd, qs)) { + if(ng_flush_egress(data, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } @@ -1289,7 +1279,7 @@ static ssize_t ngh3_stream_recv(struct connectdata *conn, return 0; } - infof(conn->data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n"); + infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n"); *curlcode = CURLE_AGAIN; return -1; } @@ -1301,8 +1291,7 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, { struct Curl_easy *data = stream_user_data; struct HTTP *stream = data->req.p.http; - (void)conn; - (void)stream_id; + int rv; (void)user_data; if(!data->set.postfields) { @@ -1311,6 +1300,13 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, "cb_h3_acked_stream_data, %zd bytes, %zd left unacked\n", datalen, stream->h3out->used)); DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE); + + if(stream->h3out->used == 0) { + rv = nghttp3_conn_resume_stream(conn, stream_id); + if(rv != 0) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + } } return 0; } @@ -1346,13 +1342,14 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id, nread = H3_SEND_SIZE - out->windex; memcpy(&out->buf[out->windex], stream->upload_mem, nread); - out->windex += nread; - out->used += nread; /* that's the chunk we return to nghttp3 */ vec[0].base = &out->buf[out->windex]; vec[0].len = nread; + out->windex += nread; + out->used += nread; + if(out->windex == H3_SEND_SIZE) out->windex = 0; /* wrap */ stream->upload_mem += nread; @@ -1370,7 +1367,7 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id, (stream->upload_left <= 0)) { H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF\n")); *pflags = NGHTTP3_DATA_FLAG_EOF; - return 0; + return nread ? 1 : 0; } else if(!nread) { return NGHTTP3_ERR_WOULDBLOCK; @@ -1382,10 +1379,11 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id, field list. */ #define AUTHORITY_DST_IDX 3 -static CURLcode http_request(struct connectdata *conn, const void *mem, +static CURLcode http_request(struct Curl_easy *data, const void *mem, size_t len) { - struct HTTP *stream = conn->data->req.p.http; + struct connectdata *conn = data->conn; + struct HTTP *stream = data->req.p.http; size_t nheader; size_t i; size_t authority_idx; @@ -1393,7 +1391,6 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, char *end, *line_end; struct quicsocket *qs = conn->quic; CURLcode result = CURLE_OK; - struct Curl_easy *data = conn->data; nghttp3_nv *nva = NULL; int64_t stream3_id; int rc; @@ -1401,7 +1398,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, rc = ngtcp2_conn_open_bidi_stream(qs->qconn, &stream3_id, NULL); if(rc) { - failf(conn->data, "can get bidi streams"); + failf(data, "can get bidi streams"); result = CURLE_SEND_ERROR; goto fail; } @@ -1587,8 +1584,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, stream->h3out = h3out; rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id, - nva, nheader, &data_reader, - conn->data); + nva, nheader, &data_reader, data); if(rc) { result = CURLE_SEND_ERROR; goto fail; @@ -1598,9 +1594,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, default: stream->upload_left = 0; /* nothing left to send */ rc = nghttp3_conn_submit_request(qs->h3conn, stream->stream3_id, - nva, nheader, - NULL, /* no body! */ - conn->data); + nva, nheader, NULL, data); if(rc) { result = CURLE_SEND_ERROR; goto fail; @@ -1619,19 +1613,20 @@ fail: free(nva); return result; } -static ssize_t ngh3_stream_send(struct connectdata *conn, +static ssize_t ngh3_stream_send(struct Curl_easy *data, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { ssize_t sent; + struct connectdata *conn = data->conn; struct quicsocket *qs = conn->quic; curl_socket_t sockfd = conn->sock[sockindex]; - struct HTTP *stream = conn->data->req.p.http; + struct HTTP *stream = data->req.p.http; if(!stream->h3req) { - CURLcode result = http_request(conn, mem, len); + CURLcode result = http_request(data, mem, len); if(result) { *curlcode = CURLE_SEND_ERROR; return -1; @@ -1639,7 +1634,7 @@ static ssize_t ngh3_stream_send(struct connectdata *conn, sent = len; } else { - H3BUGF(infof(conn->data, "ngh3_stream_send() wants to send %zd bytes\n", + H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes\n", len)); if(!stream->upload_len) { stream->upload_mem = mem; @@ -1653,7 +1648,7 @@ static ssize_t ngh3_stream_send(struct connectdata *conn, } } - if(ng_flush_egress(conn, sockfd, qs)) { + if(ng_flush_egress(data, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } @@ -1671,13 +1666,13 @@ static void ng_has_connected(struct connectdata *conn, int tempindex) conn->httpversion = 30; conn->bundle->multiuse = BUNDLE_MULTIPLEX; conn->quic = &conn->hequic[tempindex]; - DEBUGF(infof(conn->data, "ngtcp2 established connection!\n")); } /* * There can be multiple connection attempts going on in parallel. */ -CURLcode Curl_quic_is_connected(struct connectdata *conn, +CURLcode Curl_quic_is_connected(struct Curl_easy *data, + struct connectdata *conn, int sockindex, bool *done) { @@ -1685,11 +1680,11 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, struct quicsocket *qs = &conn->hequic[sockindex]; curl_socket_t sockfd = conn->tempsock[sockindex]; - result = ng_process_ingress(conn, sockfd, qs); + result = ng_process_ingress(data, sockfd, qs); if(result) goto error; - result = ng_flush_egress(conn, sockfd, qs); + result = ng_flush_egress(data, sockfd, qs); if(result) goto error; @@ -1705,7 +1700,7 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, } -static CURLcode ng_process_ingress(struct connectdata *conn, +static CURLcode ng_process_ingress(struct Curl_easy *data, curl_socket_t sockfd, struct quicsocket *qs) { @@ -1730,7 +1725,7 @@ static CURLcode ng_process_ingress(struct connectdata *conn, if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) break; - failf(conn->data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd); + failf(data, "ngtcp2: recvfrom() unexpectedly returned %zd", recvd); return CURLE_RECV_ERROR; } @@ -1749,7 +1744,8 @@ static CURLcode ng_process_ingress(struct connectdata *conn, return CURLE_OK; } -static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, +static CURLcode ng_flush_egress(struct Curl_easy *data, + int sockfd, struct quicsocket *qs) { int rv; @@ -1767,6 +1763,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, int fin; nghttp3_vec vec[16]; ssize_t ndatalen; + uint32_t flags; switch(qs->local_addr.ss_family) { case AF_INET: @@ -1783,7 +1780,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, rv = ngtcp2_conn_handle_expiry(qs->qconn, ts); if(rv != 0) { - failf(conn->data, "ngtcp2_conn_handle_expiry returned error: %s\n", + failf(data, "ngtcp2_conn_handle_expiry returned error: %s", ngtcp2_strerror(rv)); return CURLE_SEND_ERROR; } @@ -1792,72 +1789,64 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, for(;;) { outlen = -1; + veccnt = 0; + stream_id = -1; + fin = 0; + if(qs->h3conn && ngtcp2_conn_get_max_data_left(qs->qconn)) { veccnt = nghttp3_conn_writev_stream(qs->h3conn, &stream_id, &fin, vec, sizeof(vec) / sizeof(vec[0])); if(veccnt < 0) { - failf(conn->data, "nghttp3_conn_writev_stream returned error: %s\n", + failf(data, "nghttp3_conn_writev_stream returned error: %s", nghttp3_strerror((int)veccnt)); return CURLE_SEND_ERROR; } - else if(veccnt > 0) { - uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE | - (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); - outlen = - ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, - out, pktlen, &ndatalen, - flags, stream_id, - (const ngtcp2_vec *)vec, veccnt, ts); - if(outlen == 0) { - break; - } - if(outlen < 0) { - if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED || - outlen == NGTCP2_ERR_STREAM_SHUT_WR) { - assert(ndatalen == -1); - rv = nghttp3_conn_block_stream(qs->h3conn, stream_id); - if(rv != 0) { - failf(conn->data, - "nghttp3_conn_block_stream returned error: %s\n", - nghttp3_strerror(rv)); - return CURLE_SEND_ERROR; - } - continue; - } - else if(outlen == NGTCP2_ERR_WRITE_MORE) { - assert(ndatalen > 0); - rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, - ndatalen); - if(rv != 0) { - failf(conn->data, - "nghttp3_conn_add_write_offset returned error: %s\n", - nghttp3_strerror(rv)); - return CURLE_SEND_ERROR; - } - continue; - } - else { - assert(ndatalen == -1); - failf(conn->data, "ngtcp2_conn_writev_stream returned error: %s\n", - ngtcp2_strerror((int)outlen)); - return CURLE_SEND_ERROR; - } + } + + flags = NGTCP2_WRITE_STREAM_FLAG_MORE | + (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); + outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out, pktlen, + &ndatalen, flags, stream_id, + (const ngtcp2_vec *)vec, veccnt, ts); + if(outlen == 0) { + break; + } + if(outlen < 0) { + if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED || + outlen == NGTCP2_ERR_STREAM_SHUT_WR) { + assert(ndatalen == -1); + rv = nghttp3_conn_block_stream(qs->h3conn, stream_id); + if(rv != 0) { + failf(data, "nghttp3_conn_block_stream returned error: %s\n", + nghttp3_strerror(rv)); + return CURLE_SEND_ERROR; } - else { - assert(ndatalen == -1); + continue; + } + else if(outlen == NGTCP2_ERR_WRITE_MORE) { + assert(ndatalen >= 0); + rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen); + if(rv != 0) { + failf(data, "nghttp3_conn_add_write_offset returned error: %s\n", + nghttp3_strerror(rv)); + return CURLE_SEND_ERROR; } + continue; } - } - if(outlen < 0) { - outlen = ngtcp2_conn_write_pkt(qs->qconn, &ps.path, NULL, - out, pktlen, ts); - if(outlen < 0) { - failf(conn->data, "ngtcp2_conn_write_pkt returned error: %s\n", + else { + assert(ndatalen == -1); + failf(data, "ngtcp2_conn_writev_stream returned error: %s", ngtcp2_strerror((int)outlen)); return CURLE_SEND_ERROR; } - if(outlen == 0) - break; + } + else if(ndatalen >= 0) { + rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen); + if(rv != 0) { + failf(data, "nghttp3_conn_add_write_offset returned error: %s\n", + nghttp3_strerror(rv)); + return CURLE_SEND_ERROR; + } } memcpy(&remote_addr, ps.path.remote.addr, ps.path.remote.addrlen); @@ -1871,7 +1860,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, break; } else { - failf(conn->data, "send() returned %zd (errno %d)\n", sent, + failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO); return CURLE_SEND_ERROR; } @@ -1886,7 +1875,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, else { timeout = expiry - ts; } - Curl_expire(conn->data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC); + Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC); } return CURLE_OK; @@ -1895,11 +1884,13 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd, /* * Called from transfer.c:done_sending when we stop HTTP/3 uploading. */ -CURLcode Curl_quic_done_sending(struct connectdata *conn) +CURLcode Curl_quic_done_sending(struct Curl_easy *data) { + struct connectdata *conn = data->conn; + DEBUGASSERT(conn); if(conn->handler == &Curl_handler_http3) { /* only for HTTP/3 transfers */ - struct HTTP *stream = conn->data->req.p.http; + struct HTTP *stream = data->req.p.http; struct quicsocket *qs = conn->quic; stream->upload_done = TRUE; (void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id); |