quiche: happy eyeballs

Closes #4220
This commit is contained in:
Daniel Stenberg 2019-08-12 22:29:42 +02:00
parent f2cc26456b
commit baf7860b71
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -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;