mirror of
https://github.com/curl/curl.git
synced 2024-12-03 06:20:31 +08:00
quiche: improved error handling and memory cleanups
This commit is contained in:
parent
470551b7fc
commit
07828b1c9d
@ -87,8 +87,12 @@ static int quiche_perform_getsock(const struct connectdata *conn,
|
|||||||
static CURLcode quiche_disconnect(struct connectdata *conn,
|
static CURLcode quiche_disconnect(struct connectdata *conn,
|
||||||
bool dead_connection)
|
bool dead_connection)
|
||||||
{
|
{
|
||||||
(void)conn;
|
struct quicsocket *qs = &conn->quic;
|
||||||
(void)dead_connection;
|
(void)dead_connection;
|
||||||
|
quiche_h3_config_free(qs->h3config);
|
||||||
|
quiche_h3_conn_free(qs->h3c);
|
||||||
|
quiche_config_free(qs->cfg);
|
||||||
|
quiche_conn_free(qs->conn);
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,11 +133,11 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
|
|||||||
(void)addr;
|
(void)addr;
|
||||||
(void)addrlen;
|
(void)addrlen;
|
||||||
|
|
||||||
infof(conn->data, "Connecting socket %d over QUIC\n", sockfd);
|
|
||||||
|
|
||||||
qs->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
|
qs->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
|
||||||
if(!qs->cfg)
|
if(!qs->cfg) {
|
||||||
return CURLE_FAILED_INIT; /* TODO: better return code */
|
failf(conn->data, "can't create quiche config");
|
||||||
|
return CURLE_FAILED_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
quiche_config_set_idle_timeout(qs->cfg, QUIC_IDLE_TIMEOUT);
|
quiche_config_set_idle_timeout(qs->cfg, QUIC_IDLE_TIMEOUT);
|
||||||
quiche_config_set_initial_max_data(qs->cfg, QUIC_MAX_DATA);
|
quiche_config_set_initial_max_data(qs->cfg, QUIC_MAX_DATA);
|
||||||
@ -155,12 +159,14 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
|
|||||||
|
|
||||||
qs->conn = quiche_connect(conn->host.name, (const uint8_t *) qs->scid,
|
qs->conn = quiche_connect(conn->host.name, (const uint8_t *) qs->scid,
|
||||||
sizeof(qs->scid), qs->cfg);
|
sizeof(qs->scid), qs->cfg);
|
||||||
if(!qs->conn)
|
if(!qs->conn) {
|
||||||
return CURLE_FAILED_INIT; /* TODO: better return code */
|
failf(conn->data, "can't create quiche connection");
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
result = flush_egress(conn, sockfd);
|
result = flush_egress(conn, sockfd);
|
||||||
if(result)
|
if(result)
|
||||||
return CURLE_FAILED_INIT; /* TODO: better return code */
|
return result;
|
||||||
|
|
||||||
infof(conn->data, "Sent QUIC client Initial, ALPN: %s\n",
|
infof(conn->data, "Sent QUIC client Initial, ALPN: %s\n",
|
||||||
QUICHE_H3_APPLICATION_PROTOCOL + 1);
|
QUICHE_H3_APPLICATION_PROTOCOL + 1);
|
||||||
@ -225,6 +231,10 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd)
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
{
|
{
|
||||||
ssize_t sent;
|
ssize_t sent;
|
||||||
@ -236,12 +246,17 @@ static CURLcode flush_egress(struct connectdata *conn, int sockfd)
|
|||||||
if(sent == QUICHE_ERR_DONE)
|
if(sent == QUICHE_ERR_DONE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(sent < 0)
|
if(sent < 0) {
|
||||||
|
failf(conn->data, "quiche_conn_send returned %zd\n",
|
||||||
|
sent);
|
||||||
return CURLE_SEND_ERROR;
|
return CURLE_SEND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
sent = send(sockfd, out, sent, 0);
|
sent = send(sockfd, out, sent, 0);
|
||||||
if(sent < 0)
|
if(sent < 0) {
|
||||||
|
failf(conn->data, "send() returned %zd\n", sent);
|
||||||
return CURLE_SEND_ERROR;
|
return CURLE_SEND_ERROR;
|
||||||
|
}
|
||||||
} while(1);
|
} while(1);
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
@ -431,17 +446,22 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
|
|||||||
int64_t stream3_id;
|
int64_t stream3_id;
|
||||||
quiche_h3_header *nva = NULL;
|
quiche_h3_header *nva = NULL;
|
||||||
struct quicsocket *qs = &conn->quic;
|
struct quicsocket *qs = &conn->quic;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
#ifdef DEBUG_HTTP3
|
#ifdef DEBUG_HTTP3
|
||||||
quiche_enable_debug_logging(debug_log, NULL);
|
quiche_enable_debug_logging(debug_log, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
qs->config = quiche_h3_config_new(0, 1024, 0, 0);
|
qs->h3config = quiche_h3_config_new(0, 1024, 0, 0);
|
||||||
/* TODO: handle failure */
|
if(!qs->h3config)
|
||||||
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
/* Create a new HTTP/3 connection on the QUIC connection. */
|
/* Create a new HTTP/3 connection on the QUIC connection. */
|
||||||
qs->h3c = quiche_h3_conn_new_with_transport(qs->conn, qs->config);
|
qs->h3c = quiche_h3_conn_new_with_transport(qs->conn, qs->h3config);
|
||||||
/* TODO: handle failure */
|
if(!qs->h3c) {
|
||||||
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate number of headers contained in [mem, mem + len). Assumes a
|
/* Calculate number of headers contained in [mem, mem + len). Assumes a
|
||||||
correctly generated HTTP header field block. */
|
correctly generated HTTP header field block. */
|
||||||
@ -460,14 +480,18 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
|
|||||||
more space. */
|
more space. */
|
||||||
nheader += 1;
|
nheader += 1;
|
||||||
nva = malloc(sizeof(quiche_h3_header) * nheader);
|
nva = malloc(sizeof(quiche_h3_header) * nheader);
|
||||||
if(!nva)
|
if(!nva) {
|
||||||
return CURLE_OUT_OF_MEMORY;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Extract :method, :path from request line
|
/* Extract :method, :path from request line
|
||||||
We do line endings with CRLF so checking for CR is enough */
|
We do line endings with CRLF so checking for CR is enough */
|
||||||
line_end = memchr(hdbuf, '\r', len);
|
line_end = memchr(hdbuf, '\r', len);
|
||||||
if(!line_end)
|
if(!line_end) {
|
||||||
|
result = CURLE_BAD_FUNCTION_ARGUMENT; /* internal error */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Method does not contain spaces */
|
/* Method does not contain spaces */
|
||||||
end = memchr(hdbuf, ' ', line_end - hdbuf);
|
end = memchr(hdbuf, ' ', line_end - hdbuf);
|
||||||
@ -615,8 +639,10 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
|
|||||||
Curl_safefree(nva);
|
Curl_safefree(nva);
|
||||||
|
|
||||||
if(stream3_id < 0) {
|
if(stream3_id < 0) {
|
||||||
H3BUGF(infof(conn->data, "http3_send() send error\n"));
|
H3BUGF(infof(conn->data, "quiche_h3_send_request returned %d\n",
|
||||||
return CURLE_SEND_ERROR;
|
stream3_id));
|
||||||
|
result = CURLE_SEND_ERROR;
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
infof(conn->data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
|
infof(conn->data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
|
||||||
@ -626,8 +652,10 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
quiche_h3_config_free(qs->h3config);
|
||||||
|
quiche_h3_conn_free(qs->h3c);
|
||||||
free(nva);
|
free(nva);
|
||||||
return CURLE_SEND_ERROR;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ struct quicsocket {
|
|||||||
quiche_config *cfg;
|
quiche_config *cfg;
|
||||||
quiche_conn *conn;
|
quiche_conn *conn;
|
||||||
quiche_h3_conn *h3c;
|
quiche_h3_conn *h3c;
|
||||||
quiche_h3_config *config;
|
quiche_h3_config *h3config;
|
||||||
uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
|
uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user