summaryrefslogtreecommitdiff
path: root/lib/vquic/curl_msh3.c
diff options
context:
space:
mode:
authorStefan Eissing <stefan@eissing.org>2023-01-02 14:08:16 +0100
committerDaniel Stenberg <daniel@haxx.se>2023-01-08 11:06:30 +0100
commit4303093cd532cf48f1ec2db5899cf60c95a116d4 (patch)
tree30f1dbe9e180b0c6dbfcabb281384c8eace3a4d0 /lib/vquic/curl_msh3.c
parent260fea215adf0cffed91fb9cb331e163431ebc5b (diff)
downloadcurl-4303093cd532cf48f1ec2db5899cf60c95a116d4.tar.gz
msh3: run again in its cfilter
- test 2500, single GET works - test 2501, single POST stalls - test 2502, multiple, sequential GETs each use a new connection since MsH3ConnectionGetState(qconn) no longer reports CONNECTED after one GET. Closes #10204
Diffstat (limited to 'lib/vquic/curl_msh3.c')
-rw-r--r--lib/vquic/curl_msh3.c306
1 files changed, 240 insertions, 66 deletions
diff --git a/lib/vquic/curl_msh3.c b/lib/vquic/curl_msh3.c
index 15d0bab5b..8f323ddd3 100644
--- a/lib/vquic/curl_msh3.c
+++ b/lib/vquic/curl_msh3.c
@@ -31,20 +31,23 @@
#include "multiif.h"
#include "sendf.h"
#include "cfilters.h"
+#include "cf-socket.h"
#include "connect.h"
#include "h2h3.h"
#include "curl_msh3.h"
+#include "socketpair.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
-/* #define DEBUG_HTTP3 1 */
-#ifdef DEBUG_HTTP3
-#define H3BUGF(x) x
+#define DEBUG_CF 1
+
+#if DEBUG_CF
+#define CF_DEBUGF(x) x
#else
-#define H3BUGF(x) do { } while(0)
+#define CF_DEBUGF(x) do { } while(0)
#endif
#define MSH3_REQ_INIT_BUF_LEN 8192
@@ -91,9 +94,17 @@ void Curl_msh3_ver(char *p, size_t len)
(void)msnprintf(p, len, "msh3/%d.%d.%d.%d", v[0], v[1], v[2], v[3]);
}
+#define SP_LOCAL 0
+#define SP_REMOTE 1
+
struct cf_msh3_ctx {
MSH3_API *api;
MSH3_CONNECTION *qconn;
+ struct Curl_sockaddr_ex addr;
+ curl_socket_t sock[2]; /* fake socket pair until we get support in msh3 */
+ char l_ip[MAX_IPADR_LEN]; /* local IP as string */
+ int l_port; /* local port number */
+ BIT(active);
};
static const MSH3_REQUEST_IF msh3_request_if = {
@@ -110,19 +121,22 @@ static CURLcode msh3_data_setup(struct Curl_cfilter *cf,
struct HTTP *stream = data->req.p.http;
(void)cf;
- H3BUGF(infof(data, "msh3_data_setup"));
- stream->recv_buf = malloc(MSH3_REQ_INIT_BUF_LEN);
+ DEBUGASSERT(stream);
if(!stream->recv_buf) {
- return CURLE_OUT_OF_MEMORY;
- }
- stream->req = ZERO_NULL;
- msh3_lock_initialize(&stream->recv_lock);
- stream->recv_buf_alloc = MSH3_REQ_INIT_BUF_LEN;
- stream->recv_header_len = 0;
- stream->recv_header_complete = false;
- stream->recv_data_len = 0;
- stream->recv_data_complete = false;
- stream->recv_error = CURLE_OK;
+ CF_DEBUGF(infof(data, CFMSG(cf, "msh3_data_setup")));
+ stream->recv_buf = malloc(MSH3_REQ_INIT_BUF_LEN);
+ if(!stream->recv_buf) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ stream->req = ZERO_NULL;
+ msh3_lock_initialize(&stream->recv_lock);
+ stream->recv_buf_alloc = MSH3_REQ_INIT_BUF_LEN;
+ stream->recv_header_len = 0;
+ stream->recv_header_complete = false;
+ stream->recv_data_len = 0;
+ stream->recv_data_complete = false;
+ stream->recv_error = CURLE_OK;
+ }
return CURLE_OK;
}
@@ -131,13 +145,18 @@ static bool msh3request_ensure_room(struct HTTP *stream, size_t len)
{
uint8_t *new_recv_buf;
const size_t cur_recv_len = stream->recv_header_len + stream->recv_data_len;
+
if(cur_recv_len + len > stream->recv_buf_alloc) {
size_t new_recv_buf_alloc_len = stream->recv_buf_alloc;
do {
new_recv_buf_alloc_len <<= 1; /* TODO - handle overflow */
} while(cur_recv_len + len > new_recv_buf_alloc_len);
+ CF_DEBUGF(fprintf(stderr, "* enlarging buffer to %zu\n",
+ new_recv_buf_alloc_len));
new_recv_buf = malloc(new_recv_buf_alloc_len);
if(!new_recv_buf) {
+ CF_DEBUGF(fprintf(stderr, "* FAILED: enlarging buffer to %zu\n",
+ new_recv_buf_alloc_len));
return false;
}
if(cur_recv_len) {
@@ -154,12 +173,13 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
void *IfContext,
const MSH3_HEADER *Header)
{
- struct HTTP *stream = IfContext;
+ struct Curl_easy *data = IfContext;
+ struct HTTP *stream = data->req.p.http;
size_t total_len;
(void)Request;
if(stream->recv_header_complete) {
- H3BUGF(printf("* ignoring header after data\n"));
+ CF_DEBUGF(fprintf(stderr, "* ignoring header after data\n"));
return;
}
@@ -167,9 +187,11 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
if((Header->NameLength == 7) &&
!strncmp(H2H3_PSEUDO_STATUS, (char *)Header->Name, 7)) {
- total_len = 9 + Header->ValueLength;
+ total_len = 10 + Header->ValueLength;
if(!msh3request_ensure_room(stream, total_len)) {
- /* TODO - handle error */
+ CF_DEBUGF(fprintf(stderr, "* ERROR: unable to buffer: %.*s\n",
+ (int)Header->NameLength, Header->Name));
+ stream->recv_error = CURLE_OUT_OF_MEMORY;
goto release_lock;
}
msnprintf((char *)stream->recv_buf + stream->recv_header_len,
@@ -177,9 +199,11 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
"HTTP/3 %.*s \r\n", (int)Header->ValueLength, Header->Value);
}
else {
- total_len = Header->NameLength + 4 + Header->ValueLength;
+ total_len = 4 + Header->NameLength + Header->ValueLength;
if(!msh3request_ensure_room(stream, total_len)) {
- /* TODO - handle error */
+ CF_DEBUGF(fprintf(stderr, "* ERROR: unable to buffer: %.*s\n",
+ (int)Header->NameLength, Header->Name));
+ stream->recv_error = CURLE_OUT_OF_MEMORY;
goto release_lock;
}
msnprintf((char *)stream->recv_buf + stream->recv_header_len,
@@ -189,7 +213,8 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
(int)Header->ValueLength, Header->Value);
}
- stream->recv_header_len += total_len - 1; /* don't include null-terminator */
+ stream->recv_header_len += total_len;
+ data->state.drain = 1;
release_lock:
msh3_lock_release(&stream->recv_lock);
@@ -199,16 +224,20 @@ static void MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
void *IfContext, uint32_t Length,
const uint8_t *Data)
{
- struct HTTP *stream = IfContext;
+ struct Curl_easy *data = IfContext;
+ struct HTTP *stream = data->req.p.http;
size_t cur_recv_len = stream->recv_header_len + stream->recv_data_len;
+
(void)Request;
- H3BUGF(printf("* msh3_data_received %u. %zu buffered, %zu allocated\n",
- Length, cur_recv_len, stream->recv_buf_alloc));
+ CF_DEBUGF(fprintf(stderr, "* msh3_data_received %u. %zu buffered, "
+ "%zu allocated\n",
+ Length, cur_recv_len, stream->recv_buf_alloc));
msh3_lock_acquire(&stream->recv_lock);
+
if(!stream->recv_header_complete) {
- H3BUGF(printf("* Headers complete!\n"));
+ CF_DEBUGF(fprintf(stderr, "* Headers complete!\n"));
if(!msh3request_ensure_room(stream, 2)) {
- /* TODO - handle error */
+ stream->recv_error = CURLE_OUT_OF_MEMORY;
goto release_lock;
}
stream->recv_buf[stream->recv_header_len++] = '\r';
@@ -217,11 +246,13 @@ static void MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
cur_recv_len += 2;
}
if(!msh3request_ensure_room(stream, Length)) {
- /* TODO - handle error */
+ stream->recv_error = CURLE_OUT_OF_MEMORY;
goto release_lock;
}
memcpy(stream->recv_buf + cur_recv_len, Data, Length);
stream->recv_data_len += (size_t)Length;
+ data->state.drain = 1;
+
release_lock:
msh3_lock_release(&stream->recv_lock);
}
@@ -229,10 +260,13 @@ release_lock:
static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
bool Aborted, uint64_t AbortError)
{
- struct HTTP *stream = IfContext;
+ struct Curl_easy *data = IfContext;
+ struct HTTP *stream = data->req.p.http;
+
(void)Request;
(void)AbortError;
- H3BUGF(printf("* msh3_complete, aborted=%s\n", Aborted ? "true" : "false"));
+ CF_DEBUGF(fprintf(stderr, "* msh3_complete, aborted=%s\n",
+ Aborted ? "true" : "false"));
msh3_lock_acquire(&stream->recv_lock);
if(Aborted) {
stream->recv_error = CURLE_HTTP3; /* TODO - how do we pass AbortError? */
@@ -244,7 +278,8 @@ static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
static void MSH3_CALL msh3_shutdown(MSH3_REQUEST *Request, void *IfContext)
{
- struct HTTP *stream = IfContext;
+ struct Curl_easy *data = IfContext;
+ struct HTTP *stream = data->req.p.http;
(void)Request;
(void)stream;
}
@@ -252,7 +287,8 @@ static void MSH3_CALL msh3_shutdown(MSH3_REQUEST *Request, void *IfContext)
static void MSH3_CALL msh3_send_complete(MSH3_REQUEST *Request,
void *IfContext, void *SendContext)
{
- struct HTTP *stream = IfContext;
+ struct Curl_easy *data = IfContext;
+ struct HTTP *stream = data->req.p.http;
(void)Request;
(void)stream;
(void)SendContext;
@@ -265,14 +301,16 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
size_t outsize = 0;
(void)cf;
- H3BUGF(infof(data, "msh3_stream_recv %zu", len));
+ CF_DEBUGF(infof(data, CFMSG(cf, "recv(len=%zu)"), len));
if(stream->recv_error) {
failf(data, "request aborted");
+ data->state.drain = 0;
*err = stream->recv_error;
return -1;
}
+ *err = CURLE_OK;
msh3_lock_acquire(&stream->recv_lock);
if(stream->recv_header_len) {
@@ -286,7 +324,8 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
stream->recv_header_len + stream->recv_data_len - outsize);
}
stream->recv_header_len -= outsize;
- H3BUGF(infof(data, "returned %zu bytes of headers", outsize));
+ CF_DEBUGF(infof(data, CFMSG(cf, "returned %zu bytes of headers"),
+ outsize));
}
else if(stream->recv_data_len) {
outsize = len;
@@ -299,10 +338,18 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
stream->recv_data_len - outsize);
}
stream->recv_data_len -= outsize;
- H3BUGF(infof(data, "returned %zu bytes of data", outsize));
+ CF_DEBUGF(infof(data, CFMSG(cf, "returned %zu bytes of data"), outsize));
+ if(stream->recv_data_len == 0 && stream->recv_data_complete)
+ data->state.drain = 1;
}
else if(stream->recv_data_complete) {
- H3BUGF(infof(data, "receive complete"));
+ CF_DEBUGF(infof(data, CFMSG(cf, "receive complete")));
+ data->state.drain = 0;
+ }
+ else {
+ CF_DEBUGF(infof(data, CFMSG(cf, "nothing here, call again")));
+ *err = CURLE_AGAIN;
+ outsize = -1;
}
msh3_lock_release(&stream->recv_lock);
@@ -322,20 +369,26 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
/* Sizes must match for cast below to work" */
DEBUGASSERT(sizeof(MSH3_HEADER) == sizeof(struct h2h3pseudo));
- H3BUGF(infof(data, "msh3_stream_send %zu", len));
-
if(!stream->req) {
/* The first send on the request contains the headers and possibly some
data. Parse out the headers and create the request, then if there is
any data left over go ahead and send it too. */
+
+ *err = msh3_data_setup(cf, data);
+ if(*err) {
+ failf(data, "could not setup data");
+ return -1;
+ }
+
*err = Curl_pseudo_headers(data, buf, len, &hdrlen, &hreq);
if(*err) {
failf(data, "Curl_pseudo_headers failed");
return -1;
}
- H3BUGF(infof(data, "starting request with %zu headers", hreq->entries));
- stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, stream,
+ CF_DEBUGF(infof(data, CFMSG(cf, "opening request(%zu headers, len=%zu)"),
+ hreq->entries, len - hdrlen));
+ stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data,
(MSH3_HEADER*)hreq->header, hreq->entries,
hdrlen == len ? MSH3_REQUEST_FLAG_FIN :
MSH3_REQUEST_FLAG_NONE);
@@ -348,8 +401,8 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
*err = CURLE_OK;
return len;
}
- H3BUGF(infof(data, "send %zd body bytes on request %p", len,
- (void *)stream->req));
+
+ CF_DEBUGF(infof(data, CFMSG(cf, "send body(len=%zu)"), len));
if(len > 0xFFFFFFFF) {
/* msh3 doesn't support size_t sends currently. */
*err = CURLE_SEND_ERROR;
@@ -377,17 +430,20 @@ static int cf_msh3_get_select_socks(struct Curl_cfilter *cf,
struct HTTP *stream = data->req.p.http;
int bitmap = GETSOCK_BLANK;
- socks[0] = cf->conn->sock[FIRSTSOCKET];
+ if(stream && cf->conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
+ socks[0] = cf->conn->sock[FIRSTSOCKET];
- if(stream->recv_error) {
- bitmap |= GETSOCK_READSOCK(0);
- data->state.drain++;
- }
- else if(stream->recv_header_len || stream->recv_data_len) {
- bitmap |= GETSOCK_READSOCK(0);
- data->state.drain++;
+ if(stream->recv_error) {
+ bitmap |= GETSOCK_READSOCK(0);
+ data->state.drain = 1;
+ }
+ else if(stream->recv_header_len || stream->recv_data_len) {
+ bitmap |= GETSOCK_READSOCK(0);
+ data->state.drain = 1;
+ }
}
- H3BUGF(infof(data, "msh3_getsock %u", (uint32_t)data->state.drain));
+ CF_DEBUGF(infof(data, CFMSG(cf, "get_select_socks %u -> %d"),
+ (uint32_t)data->state.drain, bitmap));
return bitmap;
}
@@ -397,12 +453,28 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
{
struct HTTP *stream = data->req.p.http;
- (void)data;
(void)cf;
- H3BUGF(infof((struct Curl_easy *)data, "Curl_quic_data_pending"));
+ CF_DEBUGF(infof((struct Curl_easy *)data, CFMSG(cf, "data_pending")));
return stream->recv_header_len || stream->recv_data_len;
}
+static void cf_msh3_active(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct cf_msh3_ctx *ctx = cf->ctx;
+
+ /* use this socket from now on */
+ cf->conn->sock[cf->sockindex] = ctx->sock[SP_LOCAL];
+ /* the first socket info gets set at conn and data */
+ if(cf->sockindex == FIRSTSOCKET) {
+ cf->conn->remote_addr = &ctx->addr;
+ #ifdef ENABLE_IPV6
+ cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
+ #endif
+ Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
+ }
+ ctx->active = TRUE;
+}
+
static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
@@ -418,7 +490,7 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
break;
case CF_CTRL_DATA_DONE:
- H3BUGF(infof(data, "Curl_quic_done"));
+ CF_DEBUGF(infof(data, CFMSG(cf, "Curl_quic_done")));
if(stream) {
if(stream->recv_buf) {
Curl_safefree(stream->recv_buf);
@@ -432,10 +504,14 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
break;
case CF_CTRL_DATA_DONE_SEND:
- H3BUGF(infof(data, "Curl_quic_done_sending"));
+ CF_DEBUGF(infof(data, CFMSG(cf, "Curl_quic_done_sending")));
stream->upload_done = TRUE;
break;
+ case CF_CTRL_CONN_INFO_UPDATE:
+ cf_msh3_active(cf, data);
+ break;
+
default:
break;
}
@@ -446,9 +522,23 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- bool insecure = !cf->conn->ssl_config.verifypeer;
+ bool verify = !!cf->conn->ssl_config.verifypeer;
+
+ if(verify && (cf->conn->ssl_config.CAfile || cf->conn->ssl_config.CApath)) {
+ /* TODO: find out if there is a way to provide trust anchors to MSH3 */
+#ifdef DEBUGBUILD
+ /* we need this for our test cases to run */
+ CF_DEBUGF(infof(data, CFMSG(cf, "non-standard CA not supported"
+ "switching off verifypeer in DEBUG mode")));
+ verify = 0;
+#else
+ failf(data, "non-standard CA not supported via MsH3");
+ return CURLE_FAILED_INIT;
+#endif
+ }
- H3BUGF(infof(data, "creating new api/connection"));
+ CF_DEBUGF(infof(data, CFMSG(cf, "connecting to %s:%d (verify=%d)"),
+ cf->conn->host.name, (int)cf->conn->remote_port, verify));
ctx->api = MsH3ApiOpen();
if(!ctx->api) {
@@ -459,7 +549,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
ctx->qconn = MsH3ConnectionOpen(ctx->api,
cf->conn->host.name,
(uint16_t)cf->conn->remote_port,
- insecure);
+ !verify);
if(!ctx->qconn) {
failf(data, "can't create msh3 connection");
if(ctx->api) {
@@ -486,6 +576,14 @@ static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
+ if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) {
+ if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0]) < 0) {
+ ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+ ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+
*done = FALSE;
if(!ctx->qconn) {
result = cf_connect_start(cf, data);
@@ -494,14 +592,23 @@ static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
}
state = MsH3ConnectionGetState(ctx->qconn, FALSE);
- if(state == MSH3_CONN_HANDSHAKE_FAILED || state == MSH3_CONN_DISCONNECTED) {
- failf(data, "failed to connect, state=%u", (uint32_t)state);
+ if(state == MSH3_CONN_DISCONNECTED) {
+ failf(data, "failed to connect, MsH3 reports `DISCONNECTED`");
+ result = CURLE_COULDNT_CONNECT;
+ goto out;
+ }
+ if(state == MSH3_CONN_HANDSHAKE_FAILED) {
+ failf(data, "failed to connect, handshake failed");
result = CURLE_COULDNT_CONNECT;
goto out;
}
if(state == MSH3_CONN_CONNECTED) {
DEBUGF(infof(data, "msh3 established connection"));
+ cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+ cf->conn->httpversion = 30;
+ cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+
cf->connected = TRUE;
cf->conn->alpn = CURL_HTTP_VERSION_3;
*done = TRUE;
@@ -512,14 +619,45 @@ out:
return result;
}
-static void cf_msh3_ctx_clear(struct cf_msh3_ctx *ctx)
+static void cf_msh3_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct cf_msh3_ctx *ctx = cf->ctx;
+
+ (void)data;
+ CF_DEBUGF(infof(data, CFMSG(cf, "clearing ctx")));
if(ctx) {
if(ctx->qconn)
MsH3ConnectionClose(ctx->qconn);
if(ctx->api)
MsH3ApiClose(ctx->api);
+
+ if(ctx->active) {
+ /* We share our socket at cf->conn->sock[cf->sockindex] when active.
+ * If it is no longer there, someone has stolen (and hopefully
+ * closed it) and we just forget about it.
+ */
+ if(ctx->sock[SP_LOCAL] == cf->conn->sock[cf->sockindex]) {
+ CF_DEBUGF(infof(data, CFMSG(cf, "cf_msh3_close(%d) active"),
+ (int)ctx->sock[SP_LOCAL]));
+ cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
+ }
+ else {
+ CF_DEBUGF(infof(data, CFMSG(cf, "cf_socket_close(%d) no longer at "
+ "conn->sock[%d], discarding"), (int)ctx->sock[SP_LOCAL]));
+ ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+ }
+ if(cf->sockindex == FIRSTSOCKET)
+ cf->conn->remote_addr = NULL;
+ }
+ if(ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
+ sclose(ctx->sock[SP_LOCAL]);
+ }
+ if(ctx->sock[SP_REMOTE] != CURL_SOCKET_BAD) {
+ sclose(ctx->sock[SP_REMOTE]);
+ }
memset(ctx, 0, sizeof(*ctx));
+ ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+ ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
}
}
@@ -529,7 +667,7 @@ static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data)
(void)data;
if(ctx) {
- cf_msh3_ctx_clear(ctx);
+ cf_msh3_ctx_clear(cf, data);
}
}
@@ -538,11 +676,44 @@ static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
struct cf_msh3_ctx *ctx = cf->ctx;
(void)data;
- cf_msh3_ctx_clear(ctx);
+ cf_msh3_ctx_clear(cf, data);
free(ctx);
cf->ctx = NULL;
}
+static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ int query, int *pres1, void **pres2)
+{
+ struct cf_msh3_ctx *ctx = cf->ctx;
+
+ switch(query) {
+ case CF_QUERY_MAX_CONCURRENT: {
+ /* TODO: we do not have access to this so far, fake it */
+ (void)ctx;
+ *pres1 = 100;
+ return CURLE_OK;
+ }
+ default:
+ break;
+ }
+ return cf->next?
+ cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+ CURLE_UNKNOWN_OPTION;
+}
+
+static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_msh3_ctx *ctx = cf->ctx;
+
+ (void)data;
+ if(!ctx || ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD || !ctx->qconn)
+ return FALSE;
+
+ return MSH3_CONN_CONNECTED == MsH3ConnectionGetState(ctx->qconn, FALSE);
+}
+
static const struct Curl_cftype cft_msh3 = {
"HTTP/3-MSH3",
CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
@@ -555,9 +726,9 @@ static const struct Curl_cftype cft_msh3 = {
cf_msh3_send,
cf_msh3_recv,
cf_msh3_data_event,
- Curl_cf_def_conn_is_alive,
+ cf_msh3_conn_is_alive,
Curl_cf_def_conn_keep_alive,
- Curl_cf_def_query,
+ cf_msh3_query,
};
CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
@@ -577,6 +748,9 @@ CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+ Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
+ ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+ ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
result = Curl_cf_create(&cf, &cft_msh3, ctx);