From baf7860b7168dd9363b2d594f8d62704b34baeb4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 12 Aug 2019 22:29:42 +0200 Subject: quiche: happy eyeballs Closes #4220 --- lib/vquic/quiche.c | 73 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 31 deletions(-) (limited to 'lib/vquic/quiche.c') diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c index 386d83352..0ac848134 100644 --- a/lib/vquic/quiche.c +++ b/lib/vquic/quiche.c @@ -53,9 +53,11 @@ #define QUIC_IDLE_TIMEOUT 60 * 1000 /* milliseconds */ static CURLcode process_ingress(struct connectdata *conn, - curl_socket_t sockfd); + curl_socket_t sockfd, + struct quicsocket *qs); -static CURLcode flush_egress(struct connectdata *conn, curl_socket_t sockfd); +static CURLcode flush_egress(struct connectdata *conn, curl_socket_t sockfd, + struct quicsocket *qs); static CURLcode http_request(struct connectdata *conn, const void *mem, size_t len); @@ -90,7 +92,7 @@ static int quiche_perform_getsock(const struct connectdata *conn, static CURLcode quiche_disconnect(struct connectdata *conn, bool dead_connection) { - struct quicsocket *qs = &conn->quic; + struct quicsocket *qs = conn->quic; (void)dead_connection; quiche_h3_config_free(qs->h3config); quiche_h3_conn_free(qs->h3c); @@ -126,7 +128,7 @@ static const struct Curl_handler Curl_handler_h3_quiche = { quiche_getsock, /* proto_getsock */ quiche_getsock, /* doing_getsock */ ZERO_NULL, /* domore_getsock */ - quiche_perform_getsock, /* perform_getsock */ + quiche_perform_getsock, /* perform_getsock */ quiche_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ quiche_conncheck, /* connection_check */ @@ -136,10 +138,11 @@ static const struct Curl_handler Curl_handler_h3_quiche = { }; CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, + int sockindex, const struct sockaddr *addr, socklen_t addrlen) { CURLcode result; - struct quicsocket *qs = &conn->quic; + struct quicsocket *qs = &conn->hequic[sockindex]; struct Curl_easy *data = conn->data; (void)addr; (void)addrlen; @@ -178,10 +181,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, return CURLE_OUT_OF_MEMORY; } - result = flush_egress(conn, sockfd); + result = flush_egress(conn, sockfd, qs); if(result) return result; +#if 0 /* store the used address as a string */ if(!Curl_addr2string((struct sockaddr*)addr, conn->primary_ip, &conn->primary_port)) { @@ -191,7 +195,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, return CURLE_BAD_FUNCTION_ARGUMENT; } memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN); - +#endif /* for connection reuse purposes: */ conn->ssl[FIRSTSOCKET].state = ssl_connection_complete; @@ -202,10 +206,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd, } static CURLcode quiche_has_connected(struct connectdata *conn, - int sockindex) + int sockindex, + int tempindex) { CURLcode result; - struct quicsocket *qs = &conn->quic; + struct quicsocket *qs = conn->quic = &conn->hequic[tempindex]; conn->recv[sockindex] = h3_stream_recv; conn->send[sockindex] = h3_stream_send; @@ -224,6 +229,13 @@ static CURLcode quiche_has_connected(struct connectdata *conn, result = CURLE_OUT_OF_MEMORY; goto fail; } + if(conn->hequic[1-tempindex].cfg) { + qs = &conn->hequic[1-tempindex]; + quiche_config_free(qs->cfg); + quiche_conn_free(qs->conn); + qs->cfg = NULL; + qs->conn = NULL; + } return CURLE_OK; fail: quiche_h3_config_free(qs->h3config); @@ -231,35 +243,37 @@ static CURLcode quiche_has_connected(struct connectdata *conn, return result; } - +/* + * This function gets polled to check if this QUIC connection has connected. + */ CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; - struct quicsocket *qs = &conn->quic; - curl_socket_t sockfd = conn->sock[sockindex]; + struct quicsocket *qs = &conn->hequic[sockindex]; + curl_socket_t sockfd = conn->tempsock[sockindex]; - result = process_ingress(conn, sockfd); + result = process_ingress(conn, sockfd, qs); if(result) return result; - result = flush_egress(conn, sockfd); + result = flush_egress(conn, sockfd, qs); if(result) return result; if(quiche_conn_is_established(qs->conn)) { *done = TRUE; - result = quiche_has_connected(conn, sockindex); + result = quiche_has_connected(conn, 0, sockindex); DEBUGF(infof(conn->data, "quiche established connection!\n")); } return result; } -static CURLcode process_ingress(struct connectdata *conn, int sockfd) +static CURLcode process_ingress(struct connectdata *conn, int sockfd, + struct quicsocket *qs) { ssize_t recvd; - struct quicsocket *qs = &conn->quic; struct Curl_easy *data = conn->data; uint8_t *buf = (uint8_t *)data->state.buffer; size_t bufsize = data->set.buffer_size; @@ -273,7 +287,8 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd) break; if(recvd < 0) { - failf(conn->data, "quiche: recv() unexpectedly returned %d", recvd); + failf(conn->data, "quiche: recv() unexpectedly returned %d " + "(errno: %d, socket %d)", recvd, SOCKERRNO, sockfd); return CURLE_RECV_ERROR; } @@ -294,10 +309,10 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd) * flush_egress drains the buffers and sends off data. * Calls failf() on errors. */ -static CURLcode flush_egress(struct connectdata *conn, int sockfd) +static CURLcode flush_egress(struct connectdata *conn, int sockfd, + struct quicsocket *qs) { ssize_t sent; - struct quicsocket *qs = &conn->quic; static uint8_t out[1200]; int64_t timeout_ns; @@ -366,7 +381,7 @@ static ssize_t h3_stream_recv(struct connectdata *conn, { ssize_t recvd = -1; ssize_t rcode; - struct quicsocket *qs = &conn->quic; + struct quicsocket *qs = conn->quic; curl_socket_t sockfd = conn->sock[sockindex]; quiche_h3_event *ev; int rc; @@ -376,7 +391,7 @@ static ssize_t h3_stream_recv(struct connectdata *conn, headers.destlen = buffersize; headers.nlen = 0; - if(process_ingress(conn, sockfd)) { + if(process_ingress(conn, sockfd, qs)) { infof(conn->data, "h3_stream_recv returns on ingress\n"); *curlcode = CURLE_RECV_ERROR; return -1; @@ -397,16 +412,13 @@ static ssize_t h3_stream_recv(struct connectdata *conn, switch(quiche_h3_event_type(ev)) { case QUICHE_H3_EVENT_HEADERS: - H3BUGF(infof(conn->data, "quiche says HEADERS\n")); rc = quiche_h3_event_for_each_header(ev, cb_each_header, &headers); if(rc) { - fprintf(stderr, "failed to process headers"); /* what do we do about this? */ } recvd = headers.nlen; break; case QUICHE_H3_EVENT_DATA: - H3BUGF(infof(conn->data, "quiche says DATA\n")); if(!stream->firstbody) { /* add a header-body separator CRLF */ buf[0] = '\r'; @@ -428,9 +440,8 @@ static ssize_t h3_stream_recv(struct connectdata *conn, break; case QUICHE_H3_EVENT_FINISHED: - H3BUGF(infof(conn->data, "quiche says FINISHED\n")); if(quiche_conn_close(qs->conn, true, 0, NULL, 0) < 0) { - fprintf(stderr, "failed to close connection\n"); + ; } recvd = 0; /* end of stream */ break; @@ -440,7 +451,7 @@ static ssize_t h3_stream_recv(struct connectdata *conn, quiche_h3_event_free(ev); } - if(flush_egress(conn, sockfd)) { + if(flush_egress(conn, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } @@ -456,7 +467,7 @@ static ssize_t h3_stream_send(struct connectdata *conn, CURLcode *curlcode) { ssize_t sent; - struct quicsocket *qs = &conn->quic; + struct quicsocket *qs = conn->quic; curl_socket_t sockfd = conn->sock[sockindex]; struct HTTP *stream = conn->data->req.protop; @@ -476,7 +487,7 @@ static ssize_t h3_stream_send(struct connectdata *conn, } } - if(flush_egress(conn, sockfd)) { + if(flush_egress(conn, sockfd, qs)) { *curlcode = CURLE_SEND_ERROR; return -1; } @@ -519,7 +530,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, char *end, *line_end; int64_t stream3_id; quiche_h3_header *nva = NULL; - struct quicsocket *qs = &conn->quic; + struct quicsocket *qs = conn->quic; CURLcode result = CURLE_OK; struct Curl_easy *data = conn->data; -- cgit v1.2.3