error = 0;
#ifdef ENABLE_QUIC
if(conn->transport == TRNSPRT_QUIC) {
- result = Curl_quic_is_connected(conn, i, connected);
+ result = Curl_quic_is_connected(data, conn, i, connected);
if(!result && *connected) {
/* use this socket from now on */
conn->sock[sockindex] = conn->tempsock[i];
hostname, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
- Curl_quic_disconnect(conn, 0);
- Curl_quic_disconnect(conn, 1);
+ Curl_quic_disconnect(data, conn, 0);
+ Curl_quic_disconnect(data, conn, 1);
#ifdef WSAETIMEDOUT
if(WSAETIMEDOUT == data->state.os_errno)
else if(conn->transport == TRNSPRT_QUIC) {
/* pass in 'sockfd' separately since it hasn't been put into the
tempsock array at this point */
- result = Curl_quic_connect(conn, sockfd, tempindex,
+ result = Curl_quic_connect(data, conn, sockfd, tempindex,
&addr.sa_addr, addr.addrlen);
if(result)
error = SOCKERRNO;
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * 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
#include "urldata.h"
/* functions provided by the specific backends */
-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,
socklen_t addrlen);
-CURLcode Curl_quic_is_connected(struct connectdata *conn,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+ struct connectdata *conn,
int sockindex,
bool *connected);
int Curl_quic_ver(char *p, size_t len);
-CURLcode Curl_quic_done_sending(struct connectdata *conn);
+CURLcode Curl_quic_done_sending(struct Curl_easy *data);
void Curl_quic_done(struct Curl_easy *data, bool premature);
bool Curl_quic_data_pending(const struct Curl_easy *data);
-void Curl_quic_disconnect(struct connectdata *conn, int tempindex);
+void Curl_quic_disconnect(struct Curl_easy *data,
+ struct connectdata *conn, int tempindex);
#else /* ENABLE_QUIC */
#define Curl_quic_done_sending(x)
#define Curl_quic_done(x,y)
#define Curl_quic_data_pending(x)
-#define Curl_quic_disconnect(x,y)
+#define Curl_quic_disconnect(x,y,z)
#endif /* !ENABLE_QUIC */
#endif /* HEADER_CURL_QUIC_H */
/* These functions should be moved into the handler struct! */
Curl_http2_done_sending(data, conn);
- Curl_quic_done_sending(conn);
+ Curl_quic_done_sending(data);
if(conn->bits.rewindaftersend) {
CURLcode result = Curl_readrewind(conn);
"+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 Curl_easy *data, int sockfd,
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;
}
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",
- nghttp3_strerror((int)nconsumed));
return NGTCP2_ERR_CALLBACK_FAILURE;
}
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",
- nghttp3_strerror(rv));
return NGTCP2_ERR_CALLBACK_FAILURE;
}
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",
- nghttp3_strerror(rv));
return NGTCP2_ERR_CALLBACK_FAILURE;
}
rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id);
if(rv != 0) {
- failf(qs->conn->data, "nghttp3_conn_reset_stream returned error: %s",
- nghttp3_strerror(rv));
return NGTCP2_ERR_CALLBACK_FAILURE;
}
rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
if(rv != 0) {
- failf(qs->conn->data, "nghttp3_conn_unblock_stream returned error: %s",
- nghttp3_strerror(rv));
return NGTCP2_ERR_CALLBACK_FAILURE;
}
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;
/*
* 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,
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 */
#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]);
}
bool dead_connection)
{
(void)dead_connection;
- (void)data;
- 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;
}
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;
}
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;
}
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)
{
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->data, sockfd, qs);
+ result = ng_flush_egress(data, sockfd, qs);
if(result)
goto error;
}
-static CURLcode ng_process_ingress(struct connectdata *conn,
+static CURLcode ng_process_ingress(struct Curl_easy *data,
curl_socket_t sockfd,
struct quicsocket *qs)
{
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;
}
/*
* 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);
#define QUIC_MAX_DATA (1*1024*1024)
#define QUIC_IDLE_TIMEOUT (60 * 1000) /* milliseconds */
-static CURLcode process_ingress(struct connectdata *conn,
+static CURLcode process_ingress(struct Curl_easy *data,
curl_socket_t sockfd,
struct quicsocket *qs);
-static CURLcode flush_egress(struct connectdata *conn, curl_socket_t sockfd,
+static CURLcode flush_egress(struct Curl_easy *data, curl_socket_t sockfd,
struct quicsocket *qs);
-static CURLcode http_request(struct connectdata *conn, const void *mem,
+static CURLcode http_request(struct Curl_easy *data, const void *mem,
size_t len);
static Curl_recv h3_stream_recv;
static Curl_send h3_stream_send;
return bitmap;
}
-static CURLcode qs_disconnect(struct connectdata *conn,
+static CURLcode qs_disconnect(struct Curl_easy *data,
+ struct connectdata *conn,
struct quicsocket *qs)
{
+ DEBUGASSERT(conn);
+ DEBUGASSERT(qs);
if(qs->conn) {
(void)quiche_conn_close(qs->conn, TRUE, 0, NULL, 0);
/* flushing the egress is not a failsafe way to deliver all the
outstanding packets, but we also don't want to get stuck here... */
- (void)flush_egress(conn, qs->sockfd, qs);
+ (void)flush_egress(data, qs->sockfd, qs);
quiche_conn_free(qs->conn);
qs->conn = NULL;
}
bool dead_connection)
{
struct quicsocket *qs = conn->quic;
- (void)data;
(void)dead_connection;
- return qs_disconnect(conn, qs);
+ return qs_disconnect(data, conn, qs);
}
-void Curl_quic_disconnect(struct connectdata *conn,
+void Curl_quic_disconnect(struct Curl_easy *data,
+ struct connectdata *conn,
int tempindex)
{
if(conn->transport == TRNSPRT_QUIC)
- qs_disconnect(conn, &conn->hequic[tempindex]);
+ qs_disconnect(data, conn, &conn->hequic[tempindex]);
}
static unsigned int quiche_conncheck(struct Curl_easy *data,
}
#endif
-CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+ struct connectdata *conn, curl_socket_t sockfd,
int sockindex,
const struct sockaddr *addr, socklen_t addrlen)
{
CURLcode result;
struct quicsocket *qs = &conn->hequic[sockindex];
- struct Curl_easy *data = conn->data;
char *keylog_file = NULL;
#ifdef DEBUG_QUICHE
}
#endif
- result = flush_egress(conn, sockfd, qs);
+ result = flush_egress(data, sockfd, qs);
if(result)
return result;
/*
* This function gets polled to check if this QUIC connection has connected.
*/
-CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
bool *done)
{
CURLcode result;
struct quicsocket *qs = &conn->hequic[sockindex];
curl_socket_t sockfd = conn->tempsock[sockindex];
- result = process_ingress(conn, sockfd, qs);
+ result = process_ingress(data, sockfd, qs);
if(result)
goto error;
- result = flush_egress(conn, sockfd, qs);
+ result = flush_egress(data, sockfd, qs);
if(result)
goto error;
if(quiche_conn_is_established(qs->conn)) {
*done = TRUE;
result = quiche_has_connected(conn, 0, sockindex);
- DEBUGF(infof(conn->data, "quiche established connection!\n"));
+ DEBUGF(infof(data, "quiche established connection!\n"));
}
return result;
error:
- qs_disconnect(conn, qs);
+ qs_disconnect(data, conn, qs);
return result;
}
-static CURLcode process_ingress(struct connectdata *conn, int sockfd,
+static CURLcode process_ingress(struct Curl_easy *data, int sockfd,
struct quicsocket *qs)
{
ssize_t recvd;
- struct Curl_easy *data = conn->data;
uint8_t *buf = (uint8_t *)data->state.buffer;
size_t bufsize = data->set.buffer_size;
break;
if(recvd < 0) {
- failf(conn->data, "quiche: recv() unexpectedly returned %zd "
+ failf(data, "quiche: recv() unexpectedly returned %zd "
"(errno: %d, socket %d)", recvd, SOCKERRNO, sockfd);
return CURLE_RECV_ERROR;
}
break;
if(recvd < 0) {
- failf(conn->data, "quiche_conn_recv() == %zd", recvd);
+ failf(data, "quiche_conn_recv() == %zd", recvd);
return CURLE_RECV_ERROR;
}
} while(1);
* 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 Curl_easy *data, int sockfd,
struct quicsocket *qs)
{
ssize_t sent;
break;
if(sent < 0) {
- failf(conn->data, "quiche_conn_send returned %zd",
- sent);
+ failf(data, "quiche_conn_send returned %zd", sent);
return CURLE_SEND_ERROR;
}
sent = send(sockfd, out, sent, 0);
if(sent < 0) {
- failf(conn->data, "send() returned %zd", sent);
+ failf(data, "send() returned %zd", sent);
return CURLE_SEND_ERROR;
}
} while(1);
timeout_ns = quiche_conn_timeout_as_nanos(qs->conn);
if(timeout_ns)
/* expire uses milliseconds */
- Curl_expire(conn->data, (timeout_ns + 999999) / 1000000, EXPIRE_QUIC);
+ Curl_expire(data, (timeout_ns + 999999) / 1000000, EXPIRE_QUIC);
return CURLE_OK;
}
headers.destlen = buffersize;
headers.nlen = 0;
- if(process_ingress(conn, sockfd, qs)) {
+ if(process_ingress(data, sockfd, qs)) {
infof(data, "h3_stream_recv returns on ingress\n");
*curlcode = CURLE_RECV_ERROR;
return -1;
quiche_h3_event_free(ev);
}
- if(flush_egress(conn, sockfd, qs)) {
+ if(flush_egress(data, sockfd, qs)) {
*curlcode = CURLE_SEND_ERROR;
return -1;
}
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;
sent = len;
}
else {
- H3BUGF(infof(conn->data, "Pass on %zd body bytes to quiche\n",
- len));
+ H3BUGF(infof(data, "Pass on %zd body bytes to quiche\n", len));
sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,
(uint8_t *)mem, len, FALSE);
if(sent < 0) {
}
}
- if(flush_egress(conn, sockfd, qs)) {
+ if(flush_egress(data, sockfd, qs)) {
*curlcode = CURLE_SEND_ERROR;
return -1;
}
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;
quiche_h3_header *nva = NULL;
struct quicsocket *qs = conn->quic;
CURLcode result = CURLE_OK;
- struct Curl_easy *data = conn->data;
stream->h3req = TRUE; /* senf off! */
/*
* 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 */
ssize_t sent;
- struct HTTP *stream = conn->data->req.p.http;
+ struct HTTP *stream = data->req.p.http;
struct quicsocket *qs = conn->quic;
stream->upload_done = TRUE;
sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,