xref: /aosp_15_r20/external/curl/lib/vquic/curl_msh3.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #ifdef USE_MSH3
28*6236dae4SAndroid Build Coastguard Worker 
29*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
30*6236dae4SAndroid Build Coastguard Worker #include "hash.h"
31*6236dae4SAndroid Build Coastguard Worker #include "timeval.h"
32*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
33*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
34*6236dae4SAndroid Build Coastguard Worker #include "curl_trc.h"
35*6236dae4SAndroid Build Coastguard Worker #include "cfilters.h"
36*6236dae4SAndroid Build Coastguard Worker #include "cf-socket.h"
37*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
38*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
39*6236dae4SAndroid Build Coastguard Worker #include "http1.h"
40*6236dae4SAndroid Build Coastguard Worker #include "curl_msh3.h"
41*6236dae4SAndroid Build Coastguard Worker #include "socketpair.h"
42*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
43*6236dae4SAndroid Build Coastguard Worker #include "vquic/vquic.h"
44*6236dae4SAndroid Build Coastguard Worker 
45*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
46*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
47*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
48*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
49*6236dae4SAndroid Build Coastguard Worker 
50*6236dae4SAndroid Build Coastguard Worker #ifdef CURL_DISABLE_SOCKETPAIR
51*6236dae4SAndroid Build Coastguard Worker #error "MSH3 cannot be build with CURL_DISABLE_SOCKETPAIR set"
52*6236dae4SAndroid Build Coastguard Worker #endif
53*6236dae4SAndroid Build Coastguard Worker 
54*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_WINDOW_SIZE (128 * 1024)
55*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_CHUNK_SIZE   (16 * 1024)
56*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_RECV_CHUNKS \
57*6236dae4SAndroid Build Coastguard Worker           (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
58*6236dae4SAndroid Build Coastguard Worker 
59*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
60*6236dae4SAndroid Build Coastguard Worker #define msh3_lock CRITICAL_SECTION
61*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_initialize(lock) InitializeCriticalSection(lock)
62*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_uninitialize(lock) DeleteCriticalSection(lock)
63*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_acquire(lock) EnterCriticalSection(lock)
64*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_release(lock) LeaveCriticalSection(lock)
65*6236dae4SAndroid Build Coastguard Worker #else /* !_WIN32 */
66*6236dae4SAndroid Build Coastguard Worker #include <pthread.h>
67*6236dae4SAndroid Build Coastguard Worker #define msh3_lock pthread_mutex_t
68*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_initialize(lock) do { \
69*6236dae4SAndroid Build Coastguard Worker   pthread_mutexattr_t attr; \
70*6236dae4SAndroid Build Coastguard Worker   pthread_mutexattr_init(&attr); \
71*6236dae4SAndroid Build Coastguard Worker   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
72*6236dae4SAndroid Build Coastguard Worker   pthread_mutex_init(lock, &attr); \
73*6236dae4SAndroid Build Coastguard Worker   pthread_mutexattr_destroy(&attr); \
74*6236dae4SAndroid Build Coastguard Worker } while(0)
75*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_uninitialize(lock) pthread_mutex_destroy(lock)
76*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_acquire(lock) pthread_mutex_lock(lock)
77*6236dae4SAndroid Build Coastguard Worker #define msh3_lock_release(lock) pthread_mutex_unlock(lock)
78*6236dae4SAndroid Build Coastguard Worker #endif /* _WIN32 */
79*6236dae4SAndroid Build Coastguard Worker 
80*6236dae4SAndroid Build Coastguard Worker 
81*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection,
82*6236dae4SAndroid Build Coastguard Worker                                           void *IfContext);
83*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
84*6236dae4SAndroid Build Coastguard Worker                                           void *IfContext);
85*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
86*6236dae4SAndroid Build Coastguard Worker                                           void *IfContext,
87*6236dae4SAndroid Build Coastguard Worker                                           MSH3_REQUEST *Request);
88*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
89*6236dae4SAndroid Build Coastguard Worker                                            void *IfContext,
90*6236dae4SAndroid Build Coastguard Worker                                            const MSH3_HEADER *Header);
91*6236dae4SAndroid Build Coastguard Worker static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
92*6236dae4SAndroid Build Coastguard Worker                                         void *IfContext, uint32_t *Length,
93*6236dae4SAndroid Build Coastguard Worker                                         const uint8_t *Data);
94*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
95*6236dae4SAndroid Build Coastguard Worker                                     bool Aborted, uint64_t AbortError);
96*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
97*6236dae4SAndroid Build Coastguard Worker                                              void *IfContext);
98*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request,
99*6236dae4SAndroid Build Coastguard Worker                                      void *IfContext, void *SendContext);
100*6236dae4SAndroid Build Coastguard Worker 
101*6236dae4SAndroid Build Coastguard Worker 
Curl_msh3_ver(char * p,size_t len)102*6236dae4SAndroid Build Coastguard Worker void Curl_msh3_ver(char *p, size_t len)
103*6236dae4SAndroid Build Coastguard Worker {
104*6236dae4SAndroid Build Coastguard Worker   uint32_t v[4];
105*6236dae4SAndroid Build Coastguard Worker   MsH3Version(v);
106*6236dae4SAndroid Build Coastguard Worker   (void)msnprintf(p, len, "msh3/%d.%d.%d.%d", v[0], v[1], v[2], v[3]);
107*6236dae4SAndroid Build Coastguard Worker }
108*6236dae4SAndroid Build Coastguard Worker 
109*6236dae4SAndroid Build Coastguard Worker #define SP_LOCAL   0
110*6236dae4SAndroid Build Coastguard Worker #define SP_REMOTE  1
111*6236dae4SAndroid Build Coastguard Worker 
112*6236dae4SAndroid Build Coastguard Worker struct cf_msh3_ctx {
113*6236dae4SAndroid Build Coastguard Worker   MSH3_API *api;
114*6236dae4SAndroid Build Coastguard Worker   MSH3_CONNECTION *qconn;
115*6236dae4SAndroid Build Coastguard Worker   struct Curl_sockaddr_ex addr;
116*6236dae4SAndroid Build Coastguard Worker   curl_socket_t sock[2]; /* fake socket pair until we get support in msh3 */
117*6236dae4SAndroid Build Coastguard Worker   char l_ip[MAX_IPADR_LEN];          /* local IP as string */
118*6236dae4SAndroid Build Coastguard Worker   int l_port;                        /* local port number */
119*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data call_data;
120*6236dae4SAndroid Build Coastguard Worker   struct curltime connect_started;   /* time the current attempt started */
121*6236dae4SAndroid Build Coastguard Worker   struct curltime handshake_at;      /* time connect handshake finished */
122*6236dae4SAndroid Build Coastguard Worker   struct Curl_hash streams;          /* hash `data->mid` to `stream_ctx` */
123*6236dae4SAndroid Build Coastguard Worker   /* Flags written by msh3/msquic thread */
124*6236dae4SAndroid Build Coastguard Worker   bool handshake_complete;
125*6236dae4SAndroid Build Coastguard Worker   bool handshake_succeeded;
126*6236dae4SAndroid Build Coastguard Worker   bool connected;
127*6236dae4SAndroid Build Coastguard Worker   BIT(initialized);
128*6236dae4SAndroid Build Coastguard Worker   /* Flags written by curl thread */
129*6236dae4SAndroid Build Coastguard Worker   BIT(verbose);
130*6236dae4SAndroid Build Coastguard Worker   BIT(active);
131*6236dae4SAndroid Build Coastguard Worker };
132*6236dae4SAndroid Build Coastguard Worker 
133*6236dae4SAndroid Build Coastguard Worker static void h3_stream_hash_free(void *stream);
134*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_ctx_init(struct cf_msh3_ctx * ctx,const struct Curl_addrinfo * ai)135*6236dae4SAndroid Build Coastguard Worker static void cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
136*6236dae4SAndroid Build Coastguard Worker                              const struct Curl_addrinfo *ai)
137*6236dae4SAndroid Build Coastguard Worker {
138*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(!ctx->initialized);
139*6236dae4SAndroid Build Coastguard Worker   Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
140*6236dae4SAndroid Build Coastguard Worker   Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
141*6236dae4SAndroid Build Coastguard Worker   ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
142*6236dae4SAndroid Build Coastguard Worker   ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
143*6236dae4SAndroid Build Coastguard Worker   ctx->initialized = TRUE;
144*6236dae4SAndroid Build Coastguard Worker }
145*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_ctx_free(struct cf_msh3_ctx * ctx)146*6236dae4SAndroid Build Coastguard Worker static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx)
147*6236dae4SAndroid Build Coastguard Worker {
148*6236dae4SAndroid Build Coastguard Worker   if(ctx && ctx->initialized) {
149*6236dae4SAndroid Build Coastguard Worker     Curl_hash_destroy(&ctx->streams);
150*6236dae4SAndroid Build Coastguard Worker   }
151*6236dae4SAndroid Build Coastguard Worker   free(ctx);
152*6236dae4SAndroid Build Coastguard Worker }
153*6236dae4SAndroid Build Coastguard Worker 
154*6236dae4SAndroid Build Coastguard Worker static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data);
155*6236dae4SAndroid Build Coastguard Worker 
156*6236dae4SAndroid Build Coastguard Worker /* How to access `call_data` from a cf_msh3 filter */
157*6236dae4SAndroid Build Coastguard Worker #undef CF_CTX_CALL_DATA
158*6236dae4SAndroid Build Coastguard Worker #define CF_CTX_CALL_DATA(cf)  \
159*6236dae4SAndroid Build Coastguard Worker   ((struct cf_msh3_ctx *)(cf)->ctx)->call_data
160*6236dae4SAndroid Build Coastguard Worker 
161*6236dae4SAndroid Build Coastguard Worker /**
162*6236dae4SAndroid Build Coastguard Worker  * All about the H3 internals of a stream
163*6236dae4SAndroid Build Coastguard Worker  */
164*6236dae4SAndroid Build Coastguard Worker struct stream_ctx {
165*6236dae4SAndroid Build Coastguard Worker   struct MSH3_REQUEST *req;
166*6236dae4SAndroid Build Coastguard Worker   struct bufq recvbuf;   /* h3 response */
167*6236dae4SAndroid Build Coastguard Worker #ifdef _WIN32
168*6236dae4SAndroid Build Coastguard Worker   CRITICAL_SECTION recv_lock;
169*6236dae4SAndroid Build Coastguard Worker #else /* !_WIN32 */
170*6236dae4SAndroid Build Coastguard Worker   pthread_mutex_t recv_lock;
171*6236dae4SAndroid Build Coastguard Worker #endif /* _WIN32 */
172*6236dae4SAndroid Build Coastguard Worker   uint64_t error3; /* HTTP/3 stream error code */
173*6236dae4SAndroid Build Coastguard Worker   int status_code; /* HTTP status code */
174*6236dae4SAndroid Build Coastguard Worker   CURLcode recv_error;
175*6236dae4SAndroid Build Coastguard Worker   bool closed;
176*6236dae4SAndroid Build Coastguard Worker   bool reset;
177*6236dae4SAndroid Build Coastguard Worker   bool upload_done;
178*6236dae4SAndroid Build Coastguard Worker   bool firstheader;  /* FALSE until headers arrive */
179*6236dae4SAndroid Build Coastguard Worker   bool recv_header_complete;
180*6236dae4SAndroid Build Coastguard Worker };
181*6236dae4SAndroid Build Coastguard Worker 
182*6236dae4SAndroid Build Coastguard Worker #define H3_STREAM_CTX(ctx,data)   ((struct stream_ctx *)((data && ctx)? \
183*6236dae4SAndroid Build Coastguard Worker                 Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
184*6236dae4SAndroid Build Coastguard Worker 
h3_stream_ctx_free(struct stream_ctx * stream)185*6236dae4SAndroid Build Coastguard Worker static void h3_stream_ctx_free(struct stream_ctx *stream)
186*6236dae4SAndroid Build Coastguard Worker {
187*6236dae4SAndroid Build Coastguard Worker   Curl_bufq_free(&stream->recvbuf);
188*6236dae4SAndroid Build Coastguard Worker   free(stream);
189*6236dae4SAndroid Build Coastguard Worker }
190*6236dae4SAndroid Build Coastguard Worker 
h3_stream_hash_free(void * stream)191*6236dae4SAndroid Build Coastguard Worker static void h3_stream_hash_free(void *stream)
192*6236dae4SAndroid Build Coastguard Worker {
193*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(stream);
194*6236dae4SAndroid Build Coastguard Worker   h3_stream_ctx_free((struct stream_ctx *)stream);
195*6236dae4SAndroid Build Coastguard Worker }
196*6236dae4SAndroid Build Coastguard Worker 
h3_data_setup(struct Curl_cfilter * cf,struct Curl_easy * data)197*6236dae4SAndroid Build Coastguard Worker static CURLcode h3_data_setup(struct Curl_cfilter *cf,
198*6236dae4SAndroid Build Coastguard Worker                               struct Curl_easy *data)
199*6236dae4SAndroid Build Coastguard Worker {
200*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
201*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
202*6236dae4SAndroid Build Coastguard Worker 
203*6236dae4SAndroid Build Coastguard Worker   if(stream)
204*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
205*6236dae4SAndroid Build Coastguard Worker 
206*6236dae4SAndroid Build Coastguard Worker   stream = calloc(1, sizeof(*stream));
207*6236dae4SAndroid Build Coastguard Worker   if(!stream)
208*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
209*6236dae4SAndroid Build Coastguard Worker 
210*6236dae4SAndroid Build Coastguard Worker   stream->req = ZERO_NULL;
211*6236dae4SAndroid Build Coastguard Worker   msh3_lock_initialize(&stream->recv_lock);
212*6236dae4SAndroid Build Coastguard Worker   Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE,
213*6236dae4SAndroid Build Coastguard Worker                   H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
214*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_CF(data, cf, "data setup");
215*6236dae4SAndroid Build Coastguard Worker 
216*6236dae4SAndroid Build Coastguard Worker   if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
217*6236dae4SAndroid Build Coastguard Worker     h3_stream_ctx_free(stream);
218*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
219*6236dae4SAndroid Build Coastguard Worker   }
220*6236dae4SAndroid Build Coastguard Worker 
221*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
222*6236dae4SAndroid Build Coastguard Worker }
223*6236dae4SAndroid Build Coastguard Worker 
h3_data_done(struct Curl_cfilter * cf,struct Curl_easy * data)224*6236dae4SAndroid Build Coastguard Worker static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
225*6236dae4SAndroid Build Coastguard Worker {
226*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
227*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
228*6236dae4SAndroid Build Coastguard Worker 
229*6236dae4SAndroid Build Coastguard Worker   (void)cf;
230*6236dae4SAndroid Build Coastguard Worker   if(stream) {
231*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "easy handle is done");
232*6236dae4SAndroid Build Coastguard Worker     Curl_hash_offt_remove(&ctx->streams, data->mid);
233*6236dae4SAndroid Build Coastguard Worker   }
234*6236dae4SAndroid Build Coastguard Worker }
235*6236dae4SAndroid Build Coastguard Worker 
drain_stream_from_other_thread(struct Curl_easy * data,struct stream_ctx * stream)236*6236dae4SAndroid Build Coastguard Worker static void drain_stream_from_other_thread(struct Curl_easy *data,
237*6236dae4SAndroid Build Coastguard Worker                                            struct stream_ctx *stream)
238*6236dae4SAndroid Build Coastguard Worker {
239*6236dae4SAndroid Build Coastguard Worker   unsigned char bits;
240*6236dae4SAndroid Build Coastguard Worker 
241*6236dae4SAndroid Build Coastguard Worker   /* risky */
242*6236dae4SAndroid Build Coastguard Worker   bits = CURL_CSELECT_IN;
243*6236dae4SAndroid Build Coastguard Worker   if(stream && !stream->upload_done)
244*6236dae4SAndroid Build Coastguard Worker     bits |= CURL_CSELECT_OUT;
245*6236dae4SAndroid Build Coastguard Worker   if(data->state.select_bits != bits) {
246*6236dae4SAndroid Build Coastguard Worker     data->state.select_bits = bits;
247*6236dae4SAndroid Build Coastguard Worker     /* cannot expire from other thread */
248*6236dae4SAndroid Build Coastguard Worker   }
249*6236dae4SAndroid Build Coastguard Worker }
250*6236dae4SAndroid Build Coastguard Worker 
h3_drain_stream(struct Curl_cfilter * cf,struct Curl_easy * data)251*6236dae4SAndroid Build Coastguard Worker static void h3_drain_stream(struct Curl_cfilter *cf,
252*6236dae4SAndroid Build Coastguard Worker                             struct Curl_easy *data)
253*6236dae4SAndroid Build Coastguard Worker {
254*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
255*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
256*6236dae4SAndroid Build Coastguard Worker   unsigned char bits;
257*6236dae4SAndroid Build Coastguard Worker 
258*6236dae4SAndroid Build Coastguard Worker   (void)cf;
259*6236dae4SAndroid Build Coastguard Worker   bits = CURL_CSELECT_IN;
260*6236dae4SAndroid Build Coastguard Worker   if(stream && !stream->upload_done)
261*6236dae4SAndroid Build Coastguard Worker     bits |= CURL_CSELECT_OUT;
262*6236dae4SAndroid Build Coastguard Worker   if(data->state.select_bits != bits) {
263*6236dae4SAndroid Build Coastguard Worker     data->state.select_bits = bits;
264*6236dae4SAndroid Build Coastguard Worker     Curl_expire(data, 0, EXPIRE_RUN_NOW);
265*6236dae4SAndroid Build Coastguard Worker   }
266*6236dae4SAndroid Build Coastguard Worker }
267*6236dae4SAndroid Build Coastguard Worker 
268*6236dae4SAndroid Build Coastguard Worker static const MSH3_CONNECTION_IF msh3_conn_if = {
269*6236dae4SAndroid Build Coastguard Worker   msh3_conn_connected,
270*6236dae4SAndroid Build Coastguard Worker   msh3_conn_shutdown_complete,
271*6236dae4SAndroid Build Coastguard Worker   msh3_conn_new_request
272*6236dae4SAndroid Build Coastguard Worker };
273*6236dae4SAndroid Build Coastguard Worker 
msh3_conn_connected(MSH3_CONNECTION * Connection,void * IfContext)274*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection,
275*6236dae4SAndroid Build Coastguard Worker                                           void *IfContext)
276*6236dae4SAndroid Build Coastguard Worker {
277*6236dae4SAndroid Build Coastguard Worker   struct Curl_cfilter *cf = IfContext;
278*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
279*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = CF_DATA_CURRENT(cf);
280*6236dae4SAndroid Build Coastguard Worker   (void)Connection;
281*6236dae4SAndroid Build Coastguard Worker 
282*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_CF(data, cf, "[MSH3] connected");
283*6236dae4SAndroid Build Coastguard Worker   ctx->handshake_succeeded = TRUE;
284*6236dae4SAndroid Build Coastguard Worker   ctx->connected = TRUE;
285*6236dae4SAndroid Build Coastguard Worker   ctx->handshake_complete = TRUE;
286*6236dae4SAndroid Build Coastguard Worker }
287*6236dae4SAndroid Build Coastguard Worker 
msh3_conn_shutdown_complete(MSH3_CONNECTION * Connection,void * IfContext)288*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
289*6236dae4SAndroid Build Coastguard Worker                                           void *IfContext)
290*6236dae4SAndroid Build Coastguard Worker {
291*6236dae4SAndroid Build Coastguard Worker   struct Curl_cfilter *cf = IfContext;
292*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
293*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = CF_DATA_CURRENT(cf);
294*6236dae4SAndroid Build Coastguard Worker 
295*6236dae4SAndroid Build Coastguard Worker   (void)Connection;
296*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_CF(data, cf, "[MSH3] shutdown complete");
297*6236dae4SAndroid Build Coastguard Worker   ctx->connected = FALSE;
298*6236dae4SAndroid Build Coastguard Worker   ctx->handshake_complete = TRUE;
299*6236dae4SAndroid Build Coastguard Worker }
300*6236dae4SAndroid Build Coastguard Worker 
msh3_conn_new_request(MSH3_CONNECTION * Connection,void * IfContext,MSH3_REQUEST * Request)301*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
302*6236dae4SAndroid Build Coastguard Worker                                           void *IfContext,
303*6236dae4SAndroid Build Coastguard Worker                                           MSH3_REQUEST *Request)
304*6236dae4SAndroid Build Coastguard Worker {
305*6236dae4SAndroid Build Coastguard Worker   (void)Connection;
306*6236dae4SAndroid Build Coastguard Worker   (void)IfContext;
307*6236dae4SAndroid Build Coastguard Worker   (void)Request;
308*6236dae4SAndroid Build Coastguard Worker }
309*6236dae4SAndroid Build Coastguard Worker 
310*6236dae4SAndroid Build Coastguard Worker static const MSH3_REQUEST_IF msh3_request_if = {
311*6236dae4SAndroid Build Coastguard Worker   msh3_header_received,
312*6236dae4SAndroid Build Coastguard Worker   msh3_data_received,
313*6236dae4SAndroid Build Coastguard Worker   msh3_complete,
314*6236dae4SAndroid Build Coastguard Worker   msh3_shutdown_complete,
315*6236dae4SAndroid Build Coastguard Worker   msh3_data_sent
316*6236dae4SAndroid Build Coastguard Worker };
317*6236dae4SAndroid Build Coastguard Worker 
318*6236dae4SAndroid Build Coastguard Worker /* Decode HTTP status code. Returns -1 if no valid status code was
319*6236dae4SAndroid Build Coastguard Worker    decoded. (duplicate from http2.c) */
decode_status_code(const char * value,size_t len)320*6236dae4SAndroid Build Coastguard Worker static int decode_status_code(const char *value, size_t len)
321*6236dae4SAndroid Build Coastguard Worker {
322*6236dae4SAndroid Build Coastguard Worker   int i;
323*6236dae4SAndroid Build Coastguard Worker   int res;
324*6236dae4SAndroid Build Coastguard Worker 
325*6236dae4SAndroid Build Coastguard Worker   if(len != 3) {
326*6236dae4SAndroid Build Coastguard Worker     return -1;
327*6236dae4SAndroid Build Coastguard Worker   }
328*6236dae4SAndroid Build Coastguard Worker 
329*6236dae4SAndroid Build Coastguard Worker   res = 0;
330*6236dae4SAndroid Build Coastguard Worker 
331*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < 3; ++i) {
332*6236dae4SAndroid Build Coastguard Worker     char c = value[i];
333*6236dae4SAndroid Build Coastguard Worker 
334*6236dae4SAndroid Build Coastguard Worker     if(c < '0' || c > '9') {
335*6236dae4SAndroid Build Coastguard Worker       return -1;
336*6236dae4SAndroid Build Coastguard Worker     }
337*6236dae4SAndroid Build Coastguard Worker 
338*6236dae4SAndroid Build Coastguard Worker     res *= 10;
339*6236dae4SAndroid Build Coastguard Worker     res += c - '0';
340*6236dae4SAndroid Build Coastguard Worker   }
341*6236dae4SAndroid Build Coastguard Worker 
342*6236dae4SAndroid Build Coastguard Worker   return res;
343*6236dae4SAndroid Build Coastguard Worker }
344*6236dae4SAndroid Build Coastguard Worker 
345*6236dae4SAndroid Build Coastguard Worker /*
346*6236dae4SAndroid Build Coastguard Worker  * write_resp_raw() copies response data in raw format to the `data`'s
347*6236dae4SAndroid Build Coastguard Worker   * receive buffer. If not enough space is available, it appends to the
348*6236dae4SAndroid Build Coastguard Worker  * `data`'s overflow buffer.
349*6236dae4SAndroid Build Coastguard Worker  */
write_resp_raw(struct Curl_easy * data,const void * mem,size_t memlen)350*6236dae4SAndroid Build Coastguard Worker static CURLcode write_resp_raw(struct Curl_easy *data,
351*6236dae4SAndroid Build Coastguard Worker                                const void *mem, size_t memlen)
352*6236dae4SAndroid Build Coastguard Worker {
353*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
354*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
355*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
356*6236dae4SAndroid Build Coastguard Worker   ssize_t nwritten;
357*6236dae4SAndroid Build Coastguard Worker 
358*6236dae4SAndroid Build Coastguard Worker   if(!stream)
359*6236dae4SAndroid Build Coastguard Worker     return CURLE_RECV_ERROR;
360*6236dae4SAndroid Build Coastguard Worker 
361*6236dae4SAndroid Build Coastguard Worker   nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
362*6236dae4SAndroid Build Coastguard Worker   if(nwritten < 0) {
363*6236dae4SAndroid Build Coastguard Worker     return result;
364*6236dae4SAndroid Build Coastguard Worker   }
365*6236dae4SAndroid Build Coastguard Worker 
366*6236dae4SAndroid Build Coastguard Worker   if((size_t)nwritten < memlen) {
367*6236dae4SAndroid Build Coastguard Worker     /* This MUST not happen. Our recbuf is dimensioned to hold the
368*6236dae4SAndroid Build Coastguard Worker      * full max_stream_window and then some for this very reason. */
369*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(0);
370*6236dae4SAndroid Build Coastguard Worker     return CURLE_RECV_ERROR;
371*6236dae4SAndroid Build Coastguard Worker   }
372*6236dae4SAndroid Build Coastguard Worker   return result;
373*6236dae4SAndroid Build Coastguard Worker }
374*6236dae4SAndroid Build Coastguard Worker 
msh3_header_received(MSH3_REQUEST * Request,void * userp,const MSH3_HEADER * hd)375*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
376*6236dae4SAndroid Build Coastguard Worker                                            void *userp,
377*6236dae4SAndroid Build Coastguard Worker                                            const MSH3_HEADER *hd)
378*6236dae4SAndroid Build Coastguard Worker {
379*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = userp;
380*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
381*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
382*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
383*6236dae4SAndroid Build Coastguard Worker   (void)Request;
384*6236dae4SAndroid Build Coastguard Worker 
385*6236dae4SAndroid Build Coastguard Worker   DEBUGF(infof(data, "[MSH3] header received, stream=%d", !!stream));
386*6236dae4SAndroid Build Coastguard Worker   if(!stream || stream->recv_header_complete) {
387*6236dae4SAndroid Build Coastguard Worker     return;
388*6236dae4SAndroid Build Coastguard Worker   }
389*6236dae4SAndroid Build Coastguard Worker 
390*6236dae4SAndroid Build Coastguard Worker   msh3_lock_acquire(&stream->recv_lock);
391*6236dae4SAndroid Build Coastguard Worker 
392*6236dae4SAndroid Build Coastguard Worker   if((hd->NameLength == 7) &&
393*6236dae4SAndroid Build Coastguard Worker      !strncmp(HTTP_PSEUDO_STATUS, (char *)hd->Name, 7)) {
394*6236dae4SAndroid Build Coastguard Worker     char line[14]; /* status line is always 13 characters long */
395*6236dae4SAndroid Build Coastguard Worker     size_t ncopy;
396*6236dae4SAndroid Build Coastguard Worker 
397*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(!stream->firstheader);
398*6236dae4SAndroid Build Coastguard Worker     stream->status_code = decode_status_code(hd->Value, hd->ValueLength);
399*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(stream->status_code != -1);
400*6236dae4SAndroid Build Coastguard Worker     ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
401*6236dae4SAndroid Build Coastguard Worker                       stream->status_code);
402*6236dae4SAndroid Build Coastguard Worker     result = write_resp_raw(data, line, ncopy);
403*6236dae4SAndroid Build Coastguard Worker     if(result)
404*6236dae4SAndroid Build Coastguard Worker       stream->recv_error = result;
405*6236dae4SAndroid Build Coastguard Worker     stream->firstheader = TRUE;
406*6236dae4SAndroid Build Coastguard Worker   }
407*6236dae4SAndroid Build Coastguard Worker   else {
408*6236dae4SAndroid Build Coastguard Worker     /* store as an HTTP1-style header */
409*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(stream->firstheader);
410*6236dae4SAndroid Build Coastguard Worker     result = write_resp_raw(data, hd->Name, hd->NameLength);
411*6236dae4SAndroid Build Coastguard Worker     if(!result)
412*6236dae4SAndroid Build Coastguard Worker       result = write_resp_raw(data, ": ", 2);
413*6236dae4SAndroid Build Coastguard Worker     if(!result)
414*6236dae4SAndroid Build Coastguard Worker       result = write_resp_raw(data, hd->Value, hd->ValueLength);
415*6236dae4SAndroid Build Coastguard Worker     if(!result)
416*6236dae4SAndroid Build Coastguard Worker       result = write_resp_raw(data, "\r\n", 2);
417*6236dae4SAndroid Build Coastguard Worker     if(result) {
418*6236dae4SAndroid Build Coastguard Worker       stream->recv_error = result;
419*6236dae4SAndroid Build Coastguard Worker     }
420*6236dae4SAndroid Build Coastguard Worker   }
421*6236dae4SAndroid Build Coastguard Worker 
422*6236dae4SAndroid Build Coastguard Worker   drain_stream_from_other_thread(data, stream);
423*6236dae4SAndroid Build Coastguard Worker   msh3_lock_release(&stream->recv_lock);
424*6236dae4SAndroid Build Coastguard Worker }
425*6236dae4SAndroid Build Coastguard Worker 
msh3_data_received(MSH3_REQUEST * Request,void * IfContext,uint32_t * buflen,const uint8_t * buf)426*6236dae4SAndroid Build Coastguard Worker static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
427*6236dae4SAndroid Build Coastguard Worker                                          void *IfContext, uint32_t *buflen,
428*6236dae4SAndroid Build Coastguard Worker                                          const uint8_t *buf)
429*6236dae4SAndroid Build Coastguard Worker {
430*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = IfContext;
431*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
432*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
433*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
434*6236dae4SAndroid Build Coastguard Worker   bool rv = FALSE;
435*6236dae4SAndroid Build Coastguard Worker 
436*6236dae4SAndroid Build Coastguard Worker   /* TODO: we would like to limit the amount of data we are buffer here.
437*6236dae4SAndroid Build Coastguard Worker    * There seems to be no mechanism in msh3 to adjust flow control and
438*6236dae4SAndroid Build Coastguard Worker    * it is undocumented what happens if we return FALSE here or less
439*6236dae4SAndroid Build Coastguard Worker    * length (buflen is an inout parameter).
440*6236dae4SAndroid Build Coastguard Worker    */
441*6236dae4SAndroid Build Coastguard Worker   (void)Request;
442*6236dae4SAndroid Build Coastguard Worker   if(!stream)
443*6236dae4SAndroid Build Coastguard Worker     return FALSE;
444*6236dae4SAndroid Build Coastguard Worker 
445*6236dae4SAndroid Build Coastguard Worker   msh3_lock_acquire(&stream->recv_lock);
446*6236dae4SAndroid Build Coastguard Worker 
447*6236dae4SAndroid Build Coastguard Worker   if(!stream->recv_header_complete) {
448*6236dae4SAndroid Build Coastguard Worker     result = write_resp_raw(data, "\r\n", 2);
449*6236dae4SAndroid Build Coastguard Worker     if(result) {
450*6236dae4SAndroid Build Coastguard Worker       stream->recv_error = result;
451*6236dae4SAndroid Build Coastguard Worker       goto out;
452*6236dae4SAndroid Build Coastguard Worker     }
453*6236dae4SAndroid Build Coastguard Worker     stream->recv_header_complete = TRUE;
454*6236dae4SAndroid Build Coastguard Worker   }
455*6236dae4SAndroid Build Coastguard Worker 
456*6236dae4SAndroid Build Coastguard Worker   result = write_resp_raw(data, buf, *buflen);
457*6236dae4SAndroid Build Coastguard Worker   if(result) {
458*6236dae4SAndroid Build Coastguard Worker     stream->recv_error = result;
459*6236dae4SAndroid Build Coastguard Worker   }
460*6236dae4SAndroid Build Coastguard Worker   rv = TRUE;
461*6236dae4SAndroid Build Coastguard Worker 
462*6236dae4SAndroid Build Coastguard Worker out:
463*6236dae4SAndroid Build Coastguard Worker   msh3_lock_release(&stream->recv_lock);
464*6236dae4SAndroid Build Coastguard Worker   return rv;
465*6236dae4SAndroid Build Coastguard Worker }
466*6236dae4SAndroid Build Coastguard Worker 
msh3_complete(MSH3_REQUEST * Request,void * IfContext,bool aborted,uint64_t error)467*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
468*6236dae4SAndroid Build Coastguard Worker                                     bool aborted, uint64_t error)
469*6236dae4SAndroid Build Coastguard Worker {
470*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = IfContext;
471*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
472*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
473*6236dae4SAndroid Build Coastguard Worker 
474*6236dae4SAndroid Build Coastguard Worker   (void)Request;
475*6236dae4SAndroid Build Coastguard Worker   if(!stream)
476*6236dae4SAndroid Build Coastguard Worker     return;
477*6236dae4SAndroid Build Coastguard Worker   msh3_lock_acquire(&stream->recv_lock);
478*6236dae4SAndroid Build Coastguard Worker   stream->closed = TRUE;
479*6236dae4SAndroid Build Coastguard Worker   stream->recv_header_complete = TRUE;
480*6236dae4SAndroid Build Coastguard Worker   if(error)
481*6236dae4SAndroid Build Coastguard Worker     stream->error3 = error;
482*6236dae4SAndroid Build Coastguard Worker   if(aborted)
483*6236dae4SAndroid Build Coastguard Worker     stream->reset = TRUE;
484*6236dae4SAndroid Build Coastguard Worker   msh3_lock_release(&stream->recv_lock);
485*6236dae4SAndroid Build Coastguard Worker }
486*6236dae4SAndroid Build Coastguard Worker 
msh3_shutdown_complete(MSH3_REQUEST * Request,void * IfContext)487*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
488*6236dae4SAndroid Build Coastguard Worker                                              void *IfContext)
489*6236dae4SAndroid Build Coastguard Worker {
490*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = IfContext;
491*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
492*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
493*6236dae4SAndroid Build Coastguard Worker 
494*6236dae4SAndroid Build Coastguard Worker   if(!stream)
495*6236dae4SAndroid Build Coastguard Worker     return;
496*6236dae4SAndroid Build Coastguard Worker   (void)Request;
497*6236dae4SAndroid Build Coastguard Worker   (void)stream;
498*6236dae4SAndroid Build Coastguard Worker }
499*6236dae4SAndroid Build Coastguard Worker 
msh3_data_sent(MSH3_REQUEST * Request,void * IfContext,void * SendContext)500*6236dae4SAndroid Build Coastguard Worker static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request,
501*6236dae4SAndroid Build Coastguard Worker                                      void *IfContext, void *SendContext)
502*6236dae4SAndroid Build Coastguard Worker {
503*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data = IfContext;
504*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
505*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
506*6236dae4SAndroid Build Coastguard Worker   if(!stream)
507*6236dae4SAndroid Build Coastguard Worker     return;
508*6236dae4SAndroid Build Coastguard Worker   (void)Request;
509*6236dae4SAndroid Build Coastguard Worker   (void)stream;
510*6236dae4SAndroid Build Coastguard Worker   (void)SendContext;
511*6236dae4SAndroid Build Coastguard Worker }
512*6236dae4SAndroid Build Coastguard Worker 
recv_closed_stream(struct Curl_cfilter * cf,struct Curl_easy * data,CURLcode * err)513*6236dae4SAndroid Build Coastguard Worker static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
514*6236dae4SAndroid Build Coastguard Worker                                   struct Curl_easy *data,
515*6236dae4SAndroid Build Coastguard Worker                                   CURLcode *err)
516*6236dae4SAndroid Build Coastguard Worker {
517*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
518*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
519*6236dae4SAndroid Build Coastguard Worker   ssize_t nread = -1;
520*6236dae4SAndroid Build Coastguard Worker 
521*6236dae4SAndroid Build Coastguard Worker   if(!stream) {
522*6236dae4SAndroid Build Coastguard Worker     *err = CURLE_RECV_ERROR;
523*6236dae4SAndroid Build Coastguard Worker     return -1;
524*6236dae4SAndroid Build Coastguard Worker   }
525*6236dae4SAndroid Build Coastguard Worker   (void)cf;
526*6236dae4SAndroid Build Coastguard Worker   if(stream->reset) {
527*6236dae4SAndroid Build Coastguard Worker     failf(data, "HTTP/3 stream reset by server");
528*6236dae4SAndroid Build Coastguard Worker     *err = CURLE_PARTIAL_FILE;
529*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "cf_recv, was reset -> %d", *err);
530*6236dae4SAndroid Build Coastguard Worker     goto out;
531*6236dae4SAndroid Build Coastguard Worker   }
532*6236dae4SAndroid Build Coastguard Worker   else if(stream->error3) {
533*6236dae4SAndroid Build Coastguard Worker     failf(data, "HTTP/3 stream was not closed cleanly: (error %zd)",
534*6236dae4SAndroid Build Coastguard Worker           (ssize_t)stream->error3);
535*6236dae4SAndroid Build Coastguard Worker     *err = CURLE_HTTP3;
536*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly -> %d", *err);
537*6236dae4SAndroid Build Coastguard Worker     goto out;
538*6236dae4SAndroid Build Coastguard Worker   }
539*6236dae4SAndroid Build Coastguard Worker   else {
540*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "cf_recv, closed ok -> %d", *err);
541*6236dae4SAndroid Build Coastguard Worker   }
542*6236dae4SAndroid Build Coastguard Worker   *err = CURLE_OK;
543*6236dae4SAndroid Build Coastguard Worker   nread = 0;
544*6236dae4SAndroid Build Coastguard Worker 
545*6236dae4SAndroid Build Coastguard Worker out:
546*6236dae4SAndroid Build Coastguard Worker   return nread;
547*6236dae4SAndroid Build Coastguard Worker }
548*6236dae4SAndroid Build Coastguard Worker 
set_quic_expire(struct Curl_cfilter * cf,struct Curl_easy * data)549*6236dae4SAndroid Build Coastguard Worker static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
550*6236dae4SAndroid Build Coastguard Worker {
551*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
552*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
553*6236dae4SAndroid Build Coastguard Worker 
554*6236dae4SAndroid Build Coastguard Worker   /* we have no indication from msh3 when it would be a good time
555*6236dae4SAndroid Build Coastguard Worker    * to juggle the connection again. So, we compromise by calling
556*6236dae4SAndroid Build Coastguard Worker    * us again every some milliseconds. */
557*6236dae4SAndroid Build Coastguard Worker   (void)cf;
558*6236dae4SAndroid Build Coastguard Worker   if(stream && stream->req && !stream->closed) {
559*6236dae4SAndroid Build Coastguard Worker     Curl_expire(data, 10, EXPIRE_QUIC);
560*6236dae4SAndroid Build Coastguard Worker   }
561*6236dae4SAndroid Build Coastguard Worker   else {
562*6236dae4SAndroid Build Coastguard Worker     Curl_expire(data, 50, EXPIRE_QUIC);
563*6236dae4SAndroid Build Coastguard Worker   }
564*6236dae4SAndroid Build Coastguard Worker }
565*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)566*6236dae4SAndroid Build Coastguard Worker static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
567*6236dae4SAndroid Build Coastguard Worker                             char *buf, size_t len, CURLcode *err)
568*6236dae4SAndroid Build Coastguard Worker {
569*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
570*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
571*6236dae4SAndroid Build Coastguard Worker   ssize_t nread = -1;
572*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
573*6236dae4SAndroid Build Coastguard Worker 
574*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_CF(data, cf, "cf_recv(len=%zu), stream=%d", len, !!stream);
575*6236dae4SAndroid Build Coastguard Worker   if(!stream) {
576*6236dae4SAndroid Build Coastguard Worker     *err = CURLE_RECV_ERROR;
577*6236dae4SAndroid Build Coastguard Worker     return -1;
578*6236dae4SAndroid Build Coastguard Worker   }
579*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
580*6236dae4SAndroid Build Coastguard Worker 
581*6236dae4SAndroid Build Coastguard Worker   msh3_lock_acquire(&stream->recv_lock);
582*6236dae4SAndroid Build Coastguard Worker 
583*6236dae4SAndroid Build Coastguard Worker   if(stream->recv_error) {
584*6236dae4SAndroid Build Coastguard Worker     failf(data, "request aborted");
585*6236dae4SAndroid Build Coastguard Worker     *err = stream->recv_error;
586*6236dae4SAndroid Build Coastguard Worker     goto out;
587*6236dae4SAndroid Build Coastguard Worker   }
588*6236dae4SAndroid Build Coastguard Worker 
589*6236dae4SAndroid Build Coastguard Worker   *err = CURLE_OK;
590*6236dae4SAndroid Build Coastguard Worker 
591*6236dae4SAndroid Build Coastguard Worker   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
592*6236dae4SAndroid Build Coastguard Worker     nread = Curl_bufq_read(&stream->recvbuf,
593*6236dae4SAndroid Build Coastguard Worker                            (unsigned char *)buf, len, err);
594*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d",
595*6236dae4SAndroid Build Coastguard Worker                 len, nread, *err);
596*6236dae4SAndroid Build Coastguard Worker     if(nread < 0)
597*6236dae4SAndroid Build Coastguard Worker       goto out;
598*6236dae4SAndroid Build Coastguard Worker     if(stream->closed)
599*6236dae4SAndroid Build Coastguard Worker       h3_drain_stream(cf, data);
600*6236dae4SAndroid Build Coastguard Worker   }
601*6236dae4SAndroid Build Coastguard Worker   else if(stream->closed) {
602*6236dae4SAndroid Build Coastguard Worker     nread = recv_closed_stream(cf, data, err);
603*6236dae4SAndroid Build Coastguard Worker     goto out;
604*6236dae4SAndroid Build Coastguard Worker   }
605*6236dae4SAndroid Build Coastguard Worker   else {
606*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "req: nothing here, call again");
607*6236dae4SAndroid Build Coastguard Worker     *err = CURLE_AGAIN;
608*6236dae4SAndroid Build Coastguard Worker   }
609*6236dae4SAndroid Build Coastguard Worker 
610*6236dae4SAndroid Build Coastguard Worker out:
611*6236dae4SAndroid Build Coastguard Worker   msh3_lock_release(&stream->recv_lock);
612*6236dae4SAndroid Build Coastguard Worker   set_quic_expire(cf, data);
613*6236dae4SAndroid Build Coastguard Worker   CF_DATA_RESTORE(cf, save);
614*6236dae4SAndroid Build Coastguard Worker   return nread;
615*6236dae4SAndroid Build Coastguard Worker }
616*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,bool eos,CURLcode * err)617*6236dae4SAndroid Build Coastguard Worker static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
618*6236dae4SAndroid Build Coastguard Worker                             const void *buf, size_t len, bool eos,
619*6236dae4SAndroid Build Coastguard Worker                             CURLcode *err)
620*6236dae4SAndroid Build Coastguard Worker {
621*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
622*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
623*6236dae4SAndroid Build Coastguard Worker   struct h1_req_parser h1;
624*6236dae4SAndroid Build Coastguard Worker   struct dynhds h2_headers;
625*6236dae4SAndroid Build Coastguard Worker   MSH3_HEADER *nva = NULL;
626*6236dae4SAndroid Build Coastguard Worker   size_t nheader, i;
627*6236dae4SAndroid Build Coastguard Worker   ssize_t nwritten = -1;
628*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
629*6236dae4SAndroid Build Coastguard Worker 
630*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
631*6236dae4SAndroid Build Coastguard Worker 
632*6236dae4SAndroid Build Coastguard Worker   Curl_h1_req_parse_init(&h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
633*6236dae4SAndroid Build Coastguard Worker   Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
634*6236dae4SAndroid Build Coastguard Worker 
635*6236dae4SAndroid Build Coastguard Worker   /* Sizes must match for cast below to work" */
636*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(stream);
637*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_CF(data, cf, "req: send %zu bytes", len);
638*6236dae4SAndroid Build Coastguard Worker 
639*6236dae4SAndroid Build Coastguard Worker   if(!stream->req) {
640*6236dae4SAndroid Build Coastguard Worker     /* The first send on the request contains the headers and possibly some
641*6236dae4SAndroid Build Coastguard Worker        data. Parse out the headers and create the request, then if there is
642*6236dae4SAndroid Build Coastguard Worker        any data left over go ahead and send it too. */
643*6236dae4SAndroid Build Coastguard Worker     nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, err);
644*6236dae4SAndroid Build Coastguard Worker     if(nwritten < 0)
645*6236dae4SAndroid Build Coastguard Worker       goto out;
646*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(h1.done);
647*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(h1.req);
648*6236dae4SAndroid Build Coastguard Worker 
649*6236dae4SAndroid Build Coastguard Worker     *err = Curl_http_req_to_h2(&h2_headers, h1.req, data);
650*6236dae4SAndroid Build Coastguard Worker     if(*err) {
651*6236dae4SAndroid Build Coastguard Worker       nwritten = -1;
652*6236dae4SAndroid Build Coastguard Worker       goto out;
653*6236dae4SAndroid Build Coastguard Worker     }
654*6236dae4SAndroid Build Coastguard Worker 
655*6236dae4SAndroid Build Coastguard Worker     nheader = Curl_dynhds_count(&h2_headers);
656*6236dae4SAndroid Build Coastguard Worker     nva = malloc(sizeof(MSH3_HEADER) * nheader);
657*6236dae4SAndroid Build Coastguard Worker     if(!nva) {
658*6236dae4SAndroid Build Coastguard Worker       *err = CURLE_OUT_OF_MEMORY;
659*6236dae4SAndroid Build Coastguard Worker       nwritten = -1;
660*6236dae4SAndroid Build Coastguard Worker       goto out;
661*6236dae4SAndroid Build Coastguard Worker     }
662*6236dae4SAndroid Build Coastguard Worker 
663*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < nheader; ++i) {
664*6236dae4SAndroid Build Coastguard Worker       struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
665*6236dae4SAndroid Build Coastguard Worker       nva[i].Name = e->name;
666*6236dae4SAndroid Build Coastguard Worker       nva[i].NameLength = e->namelen;
667*6236dae4SAndroid Build Coastguard Worker       nva[i].Value = e->value;
668*6236dae4SAndroid Build Coastguard Worker       nva[i].ValueLength = e->valuelen;
669*6236dae4SAndroid Build Coastguard Worker     }
670*6236dae4SAndroid Build Coastguard Worker 
671*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "req: send %zu headers", nheader);
672*6236dae4SAndroid Build Coastguard Worker     stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data,
673*6236dae4SAndroid Build Coastguard Worker                                   nva, nheader,
674*6236dae4SAndroid Build Coastguard Worker                                   eos ? MSH3_REQUEST_FLAG_FIN :
675*6236dae4SAndroid Build Coastguard Worker                                   MSH3_REQUEST_FLAG_NONE);
676*6236dae4SAndroid Build Coastguard Worker     if(!stream->req) {
677*6236dae4SAndroid Build Coastguard Worker       failf(data, "request open failed");
678*6236dae4SAndroid Build Coastguard Worker       *err = CURLE_SEND_ERROR;
679*6236dae4SAndroid Build Coastguard Worker       goto out;
680*6236dae4SAndroid Build Coastguard Worker     }
681*6236dae4SAndroid Build Coastguard Worker     *err = CURLE_OK;
682*6236dae4SAndroid Build Coastguard Worker     nwritten = len;
683*6236dae4SAndroid Build Coastguard Worker     goto out;
684*6236dae4SAndroid Build Coastguard Worker   }
685*6236dae4SAndroid Build Coastguard Worker   else {
686*6236dae4SAndroid Build Coastguard Worker     /* request is open */
687*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "req: send %zu body bytes", len);
688*6236dae4SAndroid Build Coastguard Worker     if(len > 0xFFFFFFFF) {
689*6236dae4SAndroid Build Coastguard Worker       len = 0xFFFFFFFF;
690*6236dae4SAndroid Build Coastguard Worker     }
691*6236dae4SAndroid Build Coastguard Worker 
692*6236dae4SAndroid Build Coastguard Worker     if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf,
693*6236dae4SAndroid Build Coastguard Worker                         (uint32_t)len, stream)) {
694*6236dae4SAndroid Build Coastguard Worker       *err = CURLE_SEND_ERROR;
695*6236dae4SAndroid Build Coastguard Worker       goto out;
696*6236dae4SAndroid Build Coastguard Worker     }
697*6236dae4SAndroid Build Coastguard Worker 
698*6236dae4SAndroid Build Coastguard Worker     /* TODO - msh3/msquic will hold onto this memory until the send complete
699*6236dae4SAndroid Build Coastguard Worker        event. How do we make sure curl does not free it until then? */
700*6236dae4SAndroid Build Coastguard Worker     *err = CURLE_OK;
701*6236dae4SAndroid Build Coastguard Worker     nwritten = len;
702*6236dae4SAndroid Build Coastguard Worker   }
703*6236dae4SAndroid Build Coastguard Worker 
704*6236dae4SAndroid Build Coastguard Worker out:
705*6236dae4SAndroid Build Coastguard Worker   set_quic_expire(cf, data);
706*6236dae4SAndroid Build Coastguard Worker   free(nva);
707*6236dae4SAndroid Build Coastguard Worker   Curl_h1_req_parse_free(&h1);
708*6236dae4SAndroid Build Coastguard Worker   Curl_dynhds_free(&h2_headers);
709*6236dae4SAndroid Build Coastguard Worker   CF_DATA_RESTORE(cf, save);
710*6236dae4SAndroid Build Coastguard Worker   return nwritten;
711*6236dae4SAndroid Build Coastguard Worker }
712*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)713*6236dae4SAndroid Build Coastguard Worker static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
714*6236dae4SAndroid Build Coastguard Worker                                    struct Curl_easy *data,
715*6236dae4SAndroid Build Coastguard Worker                                    struct easy_pollset *ps)
716*6236dae4SAndroid Build Coastguard Worker {
717*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
718*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
719*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
720*6236dae4SAndroid Build Coastguard Worker 
721*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
722*6236dae4SAndroid Build Coastguard Worker   if(stream && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
723*6236dae4SAndroid Build Coastguard Worker     if(stream->recv_error) {
724*6236dae4SAndroid Build Coastguard Worker       Curl_pollset_add_in(data, ps, ctx->sock[SP_LOCAL]);
725*6236dae4SAndroid Build Coastguard Worker       h3_drain_stream(cf, data);
726*6236dae4SAndroid Build Coastguard Worker     }
727*6236dae4SAndroid Build Coastguard Worker     else if(stream->req) {
728*6236dae4SAndroid Build Coastguard Worker       Curl_pollset_add_out(data, ps, ctx->sock[SP_LOCAL]);
729*6236dae4SAndroid Build Coastguard Worker       h3_drain_stream(cf, data);
730*6236dae4SAndroid Build Coastguard Worker     }
731*6236dae4SAndroid Build Coastguard Worker   }
732*6236dae4SAndroid Build Coastguard Worker }
733*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)734*6236dae4SAndroid Build Coastguard Worker static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
735*6236dae4SAndroid Build Coastguard Worker                                  const struct Curl_easy *data)
736*6236dae4SAndroid Build Coastguard Worker {
737*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
738*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
739*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
740*6236dae4SAndroid Build Coastguard Worker   bool pending = FALSE;
741*6236dae4SAndroid Build Coastguard Worker 
742*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
743*6236dae4SAndroid Build Coastguard Worker 
744*6236dae4SAndroid Build Coastguard Worker   (void)cf;
745*6236dae4SAndroid Build Coastguard Worker   if(stream && stream->req) {
746*6236dae4SAndroid Build Coastguard Worker     msh3_lock_acquire(&stream->recv_lock);
747*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF((struct Curl_easy *)data, cf, "data pending = %zu",
748*6236dae4SAndroid Build Coastguard Worker                 Curl_bufq_len(&stream->recvbuf));
749*6236dae4SAndroid Build Coastguard Worker     pending = !Curl_bufq_is_empty(&stream->recvbuf);
750*6236dae4SAndroid Build Coastguard Worker     msh3_lock_release(&stream->recv_lock);
751*6236dae4SAndroid Build Coastguard Worker     if(pending)
752*6236dae4SAndroid Build Coastguard Worker       h3_drain_stream(cf, (struct Curl_easy *)data);
753*6236dae4SAndroid Build Coastguard Worker   }
754*6236dae4SAndroid Build Coastguard Worker 
755*6236dae4SAndroid Build Coastguard Worker   CF_DATA_RESTORE(cf, save);
756*6236dae4SAndroid Build Coastguard Worker   return pending;
757*6236dae4SAndroid Build Coastguard Worker }
758*6236dae4SAndroid Build Coastguard Worker 
h3_data_pause(struct Curl_cfilter * cf,struct Curl_easy * data,bool pause)759*6236dae4SAndroid Build Coastguard Worker static CURLcode h3_data_pause(struct Curl_cfilter *cf,
760*6236dae4SAndroid Build Coastguard Worker                               struct Curl_easy *data,
761*6236dae4SAndroid Build Coastguard Worker                               bool pause)
762*6236dae4SAndroid Build Coastguard Worker {
763*6236dae4SAndroid Build Coastguard Worker   if(!pause) {
764*6236dae4SAndroid Build Coastguard Worker     h3_drain_stream(cf, data);
765*6236dae4SAndroid Build Coastguard Worker     Curl_expire(data, 0, EXPIRE_RUN_NOW);
766*6236dae4SAndroid Build Coastguard Worker   }
767*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
768*6236dae4SAndroid Build Coastguard Worker }
769*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_data_event(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)770*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
771*6236dae4SAndroid Build Coastguard Worker                                    struct Curl_easy *data,
772*6236dae4SAndroid Build Coastguard Worker                                    int event, int arg1, void *arg2)
773*6236dae4SAndroid Build Coastguard Worker {
774*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
775*6236dae4SAndroid Build Coastguard Worker   struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
776*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
777*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
778*6236dae4SAndroid Build Coastguard Worker 
779*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
780*6236dae4SAndroid Build Coastguard Worker 
781*6236dae4SAndroid Build Coastguard Worker   (void)arg1;
782*6236dae4SAndroid Build Coastguard Worker   (void)arg2;
783*6236dae4SAndroid Build Coastguard Worker   switch(event) {
784*6236dae4SAndroid Build Coastguard Worker   case CF_CTRL_DATA_SETUP:
785*6236dae4SAndroid Build Coastguard Worker     result = h3_data_setup(cf, data);
786*6236dae4SAndroid Build Coastguard Worker     break;
787*6236dae4SAndroid Build Coastguard Worker   case CF_CTRL_DATA_PAUSE:
788*6236dae4SAndroid Build Coastguard Worker     result = h3_data_pause(cf, data, (arg1 != 0));
789*6236dae4SAndroid Build Coastguard Worker     break;
790*6236dae4SAndroid Build Coastguard Worker   case CF_CTRL_DATA_DONE:
791*6236dae4SAndroid Build Coastguard Worker     h3_data_done(cf, data);
792*6236dae4SAndroid Build Coastguard Worker     break;
793*6236dae4SAndroid Build Coastguard Worker   case CF_CTRL_DATA_DONE_SEND:
794*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "req: send done");
795*6236dae4SAndroid Build Coastguard Worker     if(stream) {
796*6236dae4SAndroid Build Coastguard Worker       stream->upload_done = TRUE;
797*6236dae4SAndroid Build Coastguard Worker       if(stream->req) {
798*6236dae4SAndroid Build Coastguard Worker         char buf[1];
799*6236dae4SAndroid Build Coastguard Worker         if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_FIN,
800*6236dae4SAndroid Build Coastguard Worker                             buf, 0, data)) {
801*6236dae4SAndroid Build Coastguard Worker           result = CURLE_SEND_ERROR;
802*6236dae4SAndroid Build Coastguard Worker         }
803*6236dae4SAndroid Build Coastguard Worker       }
804*6236dae4SAndroid Build Coastguard Worker     }
805*6236dae4SAndroid Build Coastguard Worker     break;
806*6236dae4SAndroid Build Coastguard Worker   default:
807*6236dae4SAndroid Build Coastguard Worker     break;
808*6236dae4SAndroid Build Coastguard Worker   }
809*6236dae4SAndroid Build Coastguard Worker 
810*6236dae4SAndroid Build Coastguard Worker   CF_DATA_RESTORE(cf, save);
811*6236dae4SAndroid Build Coastguard Worker   return result;
812*6236dae4SAndroid Build Coastguard Worker }
813*6236dae4SAndroid Build Coastguard Worker 
cf_connect_start(struct Curl_cfilter * cf,struct Curl_easy * data)814*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_connect_start(struct Curl_cfilter *cf,
815*6236dae4SAndroid Build Coastguard Worker                                  struct Curl_easy *data)
816*6236dae4SAndroid Build Coastguard Worker {
817*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
818*6236dae4SAndroid Build Coastguard Worker   struct ssl_primary_config *conn_config;
819*6236dae4SAndroid Build Coastguard Worker   MSH3_ADDR addr = {0};
820*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
821*6236dae4SAndroid Build Coastguard Worker   bool verify;
822*6236dae4SAndroid Build Coastguard Worker 
823*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(ctx->initialized);
824*6236dae4SAndroid Build Coastguard Worker   conn_config = Curl_ssl_cf_get_primary_config(cf);
825*6236dae4SAndroid Build Coastguard Worker   if(!conn_config)
826*6236dae4SAndroid Build Coastguard Worker     return CURLE_FAILED_INIT;
827*6236dae4SAndroid Build Coastguard Worker   verify = !!conn_config->verifypeer;
828*6236dae4SAndroid Build Coastguard Worker 
829*6236dae4SAndroid Build Coastguard Worker   memcpy(&addr, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
830*6236dae4SAndroid Build Coastguard Worker   MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port);
831*6236dae4SAndroid Build Coastguard Worker 
832*6236dae4SAndroid Build Coastguard Worker   if(verify && (conn_config->CAfile || conn_config->CApath)) {
833*6236dae4SAndroid Build Coastguard Worker     /* TODO: need a way to provide trust anchors to MSH3 */
834*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
835*6236dae4SAndroid Build Coastguard Worker     /* we need this for our test cases to run */
836*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "non-standard CA not supported, "
837*6236dae4SAndroid Build Coastguard Worker                 "switching off verifypeer in DEBUG mode");
838*6236dae4SAndroid Build Coastguard Worker     verify = 0;
839*6236dae4SAndroid Build Coastguard Worker #else
840*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "non-standard CA not supported, "
841*6236dae4SAndroid Build Coastguard Worker                 "attempting with built-in verification");
842*6236dae4SAndroid Build Coastguard Worker #endif
843*6236dae4SAndroid Build Coastguard Worker   }
844*6236dae4SAndroid Build Coastguard Worker 
845*6236dae4SAndroid Build Coastguard Worker   CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)",
846*6236dae4SAndroid Build Coastguard Worker               cf->conn->host.name, (int)cf->conn->remote_port, verify);
847*6236dae4SAndroid Build Coastguard Worker 
848*6236dae4SAndroid Build Coastguard Worker   ctx->api = MsH3ApiOpen();
849*6236dae4SAndroid Build Coastguard Worker   if(!ctx->api) {
850*6236dae4SAndroid Build Coastguard Worker     failf(data, "cannot create msh3 api");
851*6236dae4SAndroid Build Coastguard Worker     return CURLE_FAILED_INIT;
852*6236dae4SAndroid Build Coastguard Worker   }
853*6236dae4SAndroid Build Coastguard Worker 
854*6236dae4SAndroid Build Coastguard Worker   ctx->qconn = MsH3ConnectionOpen(ctx->api,
855*6236dae4SAndroid Build Coastguard Worker                                   &msh3_conn_if,
856*6236dae4SAndroid Build Coastguard Worker                                   cf,
857*6236dae4SAndroid Build Coastguard Worker                                   cf->conn->host.name,
858*6236dae4SAndroid Build Coastguard Worker                                   &addr,
859*6236dae4SAndroid Build Coastguard Worker                                   !verify);
860*6236dae4SAndroid Build Coastguard Worker   if(!ctx->qconn) {
861*6236dae4SAndroid Build Coastguard Worker     failf(data, "cannot create msh3 connection");
862*6236dae4SAndroid Build Coastguard Worker     if(ctx->api) {
863*6236dae4SAndroid Build Coastguard Worker       MsH3ApiClose(ctx->api);
864*6236dae4SAndroid Build Coastguard Worker       ctx->api = NULL;
865*6236dae4SAndroid Build Coastguard Worker     }
866*6236dae4SAndroid Build Coastguard Worker     return CURLE_FAILED_INIT;
867*6236dae4SAndroid Build Coastguard Worker   }
868*6236dae4SAndroid Build Coastguard Worker 
869*6236dae4SAndroid Build Coastguard Worker   result = h3_data_setup(cf, data);
870*6236dae4SAndroid Build Coastguard Worker   if(result)
871*6236dae4SAndroid Build Coastguard Worker     return result;
872*6236dae4SAndroid Build Coastguard Worker 
873*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
874*6236dae4SAndroid Build Coastguard Worker }
875*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)876*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
877*6236dae4SAndroid Build Coastguard Worker                                 struct Curl_easy *data,
878*6236dae4SAndroid Build Coastguard Worker                                 bool blocking, bool *done)
879*6236dae4SAndroid Build Coastguard Worker {
880*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
881*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
882*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
883*6236dae4SAndroid Build Coastguard Worker 
884*6236dae4SAndroid Build Coastguard Worker   (void)blocking;
885*6236dae4SAndroid Build Coastguard Worker   if(cf->connected) {
886*6236dae4SAndroid Build Coastguard Worker     *done = TRUE;
887*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
888*6236dae4SAndroid Build Coastguard Worker   }
889*6236dae4SAndroid Build Coastguard Worker 
890*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
891*6236dae4SAndroid Build Coastguard Worker 
892*6236dae4SAndroid Build Coastguard Worker   if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) {
893*6236dae4SAndroid Build Coastguard Worker     if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0], FALSE) < 0) {
894*6236dae4SAndroid Build Coastguard Worker       ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
895*6236dae4SAndroid Build Coastguard Worker       ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
896*6236dae4SAndroid Build Coastguard Worker       return CURLE_COULDNT_CONNECT;
897*6236dae4SAndroid Build Coastguard Worker     }
898*6236dae4SAndroid Build Coastguard Worker   }
899*6236dae4SAndroid Build Coastguard Worker 
900*6236dae4SAndroid Build Coastguard Worker   *done = FALSE;
901*6236dae4SAndroid Build Coastguard Worker   if(!ctx->qconn) {
902*6236dae4SAndroid Build Coastguard Worker     ctx->connect_started = Curl_now();
903*6236dae4SAndroid Build Coastguard Worker     result = cf_connect_start(cf, data);
904*6236dae4SAndroid Build Coastguard Worker     if(result)
905*6236dae4SAndroid Build Coastguard Worker       goto out;
906*6236dae4SAndroid Build Coastguard Worker   }
907*6236dae4SAndroid Build Coastguard Worker 
908*6236dae4SAndroid Build Coastguard Worker   if(ctx->handshake_complete) {
909*6236dae4SAndroid Build Coastguard Worker     ctx->handshake_at = Curl_now();
910*6236dae4SAndroid Build Coastguard Worker     if(ctx->handshake_succeeded) {
911*6236dae4SAndroid Build Coastguard Worker       CURL_TRC_CF(data, cf, "handshake succeeded");
912*6236dae4SAndroid Build Coastguard Worker       cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
913*6236dae4SAndroid Build Coastguard Worker       cf->conn->httpversion = 30;
914*6236dae4SAndroid Build Coastguard Worker       cf->connected = TRUE;
915*6236dae4SAndroid Build Coastguard Worker       cf->conn->alpn = CURL_HTTP_VERSION_3;
916*6236dae4SAndroid Build Coastguard Worker       *done = TRUE;
917*6236dae4SAndroid Build Coastguard Worker       connkeep(cf->conn, "HTTP/3 default");
918*6236dae4SAndroid Build Coastguard Worker       Curl_pgrsTime(data, TIMER_APPCONNECT);
919*6236dae4SAndroid Build Coastguard Worker     }
920*6236dae4SAndroid Build Coastguard Worker     else {
921*6236dae4SAndroid Build Coastguard Worker       failf(data, "failed to connect, handshake failed");
922*6236dae4SAndroid Build Coastguard Worker       result = CURLE_COULDNT_CONNECT;
923*6236dae4SAndroid Build Coastguard Worker     }
924*6236dae4SAndroid Build Coastguard Worker   }
925*6236dae4SAndroid Build Coastguard Worker 
926*6236dae4SAndroid Build Coastguard Worker out:
927*6236dae4SAndroid Build Coastguard Worker   CF_DATA_RESTORE(cf, save);
928*6236dae4SAndroid Build Coastguard Worker   return result;
929*6236dae4SAndroid Build Coastguard Worker }
930*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_close(struct Curl_cfilter * cf,struct Curl_easy * data)931*6236dae4SAndroid Build Coastguard Worker static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data)
932*6236dae4SAndroid Build Coastguard Worker {
933*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
934*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
935*6236dae4SAndroid Build Coastguard Worker 
936*6236dae4SAndroid Build Coastguard Worker   (void)data;
937*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
938*6236dae4SAndroid Build Coastguard Worker 
939*6236dae4SAndroid Build Coastguard Worker   if(ctx) {
940*6236dae4SAndroid Build Coastguard Worker     CURL_TRC_CF(data, cf, "destroying");
941*6236dae4SAndroid Build Coastguard Worker     if(ctx->qconn) {
942*6236dae4SAndroid Build Coastguard Worker       MsH3ConnectionClose(ctx->qconn);
943*6236dae4SAndroid Build Coastguard Worker       ctx->qconn = NULL;
944*6236dae4SAndroid Build Coastguard Worker     }
945*6236dae4SAndroid Build Coastguard Worker     if(ctx->api) {
946*6236dae4SAndroid Build Coastguard Worker       MsH3ApiClose(ctx->api);
947*6236dae4SAndroid Build Coastguard Worker       ctx->api = NULL;
948*6236dae4SAndroid Build Coastguard Worker     }
949*6236dae4SAndroid Build Coastguard Worker 
950*6236dae4SAndroid Build Coastguard Worker     if(ctx->active) {
951*6236dae4SAndroid Build Coastguard Worker       /* We share our socket at cf->conn->sock[cf->sockindex] when active.
952*6236dae4SAndroid Build Coastguard Worker        * If it is no longer there, someone has stolen (and hopefully
953*6236dae4SAndroid Build Coastguard Worker        * closed it) and we just forget about it.
954*6236dae4SAndroid Build Coastguard Worker        */
955*6236dae4SAndroid Build Coastguard Worker       ctx->active = FALSE;
956*6236dae4SAndroid Build Coastguard Worker       if(ctx->sock[SP_LOCAL] == cf->conn->sock[cf->sockindex]) {
957*6236dae4SAndroid Build Coastguard Worker         CURL_TRC_CF(data, cf, "cf_msh3_close(%d) active",
958*6236dae4SAndroid Build Coastguard Worker                     (int)ctx->sock[SP_LOCAL]);
959*6236dae4SAndroid Build Coastguard Worker         cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
960*6236dae4SAndroid Build Coastguard Worker       }
961*6236dae4SAndroid Build Coastguard Worker       else {
962*6236dae4SAndroid Build Coastguard Worker         CURL_TRC_CF(data, cf, "cf_socket_close(%d) no longer at "
963*6236dae4SAndroid Build Coastguard Worker                     "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]);
964*6236dae4SAndroid Build Coastguard Worker         ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
965*6236dae4SAndroid Build Coastguard Worker       }
966*6236dae4SAndroid Build Coastguard Worker       if(cf->sockindex == FIRSTSOCKET)
967*6236dae4SAndroid Build Coastguard Worker         cf->conn->remote_addr = NULL;
968*6236dae4SAndroid Build Coastguard Worker     }
969*6236dae4SAndroid Build Coastguard Worker     if(ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
970*6236dae4SAndroid Build Coastguard Worker       sclose(ctx->sock[SP_LOCAL]);
971*6236dae4SAndroid Build Coastguard Worker     }
972*6236dae4SAndroid Build Coastguard Worker     if(ctx->sock[SP_REMOTE] != CURL_SOCKET_BAD) {
973*6236dae4SAndroid Build Coastguard Worker       sclose(ctx->sock[SP_REMOTE]);
974*6236dae4SAndroid Build Coastguard Worker     }
975*6236dae4SAndroid Build Coastguard Worker     ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
976*6236dae4SAndroid Build Coastguard Worker     ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
977*6236dae4SAndroid Build Coastguard Worker   }
978*6236dae4SAndroid Build Coastguard Worker   CF_DATA_RESTORE(cf, save);
979*6236dae4SAndroid Build Coastguard Worker }
980*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)981*6236dae4SAndroid Build Coastguard Worker static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
982*6236dae4SAndroid Build Coastguard Worker {
983*6236dae4SAndroid Build Coastguard Worker   struct cf_call_data save;
984*6236dae4SAndroid Build Coastguard Worker 
985*6236dae4SAndroid Build Coastguard Worker   CF_DATA_SAVE(save, cf, data);
986*6236dae4SAndroid Build Coastguard Worker   cf_msh3_close(cf, data);
987*6236dae4SAndroid Build Coastguard Worker   if(cf->ctx) {
988*6236dae4SAndroid Build Coastguard Worker     cf_msh3_ctx_free(cf->ctx);
989*6236dae4SAndroid Build Coastguard Worker     cf->ctx = NULL;
990*6236dae4SAndroid Build Coastguard Worker   }
991*6236dae4SAndroid Build Coastguard Worker   /* no CF_DATA_RESTORE(cf, save); its gone */
992*6236dae4SAndroid Build Coastguard Worker }
993*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)994*6236dae4SAndroid Build Coastguard Worker static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
995*6236dae4SAndroid Build Coastguard Worker                               struct Curl_easy *data,
996*6236dae4SAndroid Build Coastguard Worker                               int query, int *pres1, void *pres2)
997*6236dae4SAndroid Build Coastguard Worker {
998*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
999*6236dae4SAndroid Build Coastguard Worker 
1000*6236dae4SAndroid Build Coastguard Worker   switch(query) {
1001*6236dae4SAndroid Build Coastguard Worker   case CF_QUERY_MAX_CONCURRENT: {
1002*6236dae4SAndroid Build Coastguard Worker     /* TODO: we do not have access to this so far, fake it */
1003*6236dae4SAndroid Build Coastguard Worker     (void)ctx;
1004*6236dae4SAndroid Build Coastguard Worker     *pres1 = 100;
1005*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1006*6236dae4SAndroid Build Coastguard Worker   }
1007*6236dae4SAndroid Build Coastguard Worker   case CF_QUERY_TIMER_CONNECT: {
1008*6236dae4SAndroid Build Coastguard Worker     struct curltime *when = pres2;
1009*6236dae4SAndroid Build Coastguard Worker     /* we do not know when the first byte arrived */
1010*6236dae4SAndroid Build Coastguard Worker     if(cf->connected)
1011*6236dae4SAndroid Build Coastguard Worker       *when = ctx->handshake_at;
1012*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1013*6236dae4SAndroid Build Coastguard Worker   }
1014*6236dae4SAndroid Build Coastguard Worker   case CF_QUERY_TIMER_APPCONNECT: {
1015*6236dae4SAndroid Build Coastguard Worker     struct curltime *when = pres2;
1016*6236dae4SAndroid Build Coastguard Worker     if(cf->connected)
1017*6236dae4SAndroid Build Coastguard Worker       *when = ctx->handshake_at;
1018*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1019*6236dae4SAndroid Build Coastguard Worker   }
1020*6236dae4SAndroid Build Coastguard Worker   default:
1021*6236dae4SAndroid Build Coastguard Worker     break;
1022*6236dae4SAndroid Build Coastguard Worker   }
1023*6236dae4SAndroid Build Coastguard Worker   return cf->next ?
1024*6236dae4SAndroid Build Coastguard Worker     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1025*6236dae4SAndroid Build Coastguard Worker     CURLE_UNKNOWN_OPTION;
1026*6236dae4SAndroid Build Coastguard Worker }
1027*6236dae4SAndroid Build Coastguard Worker 
cf_msh3_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)1028*6236dae4SAndroid Build Coastguard Worker static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf,
1029*6236dae4SAndroid Build Coastguard Worker                                   struct Curl_easy *data,
1030*6236dae4SAndroid Build Coastguard Worker                                   bool *input_pending)
1031*6236dae4SAndroid Build Coastguard Worker {
1032*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = cf->ctx;
1033*6236dae4SAndroid Build Coastguard Worker 
1034*6236dae4SAndroid Build Coastguard Worker   (void)data;
1035*6236dae4SAndroid Build Coastguard Worker   *input_pending = FALSE;
1036*6236dae4SAndroid Build Coastguard Worker   return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn &&
1037*6236dae4SAndroid Build Coastguard Worker          ctx->connected;
1038*6236dae4SAndroid Build Coastguard Worker }
1039*6236dae4SAndroid Build Coastguard Worker 
1040*6236dae4SAndroid Build Coastguard Worker struct Curl_cftype Curl_cft_http3 = {
1041*6236dae4SAndroid Build Coastguard Worker   "HTTP/3",
1042*6236dae4SAndroid Build Coastguard Worker   CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
1043*6236dae4SAndroid Build Coastguard Worker   0,
1044*6236dae4SAndroid Build Coastguard Worker   cf_msh3_destroy,
1045*6236dae4SAndroid Build Coastguard Worker   cf_msh3_connect,
1046*6236dae4SAndroid Build Coastguard Worker   cf_msh3_close,
1047*6236dae4SAndroid Build Coastguard Worker   Curl_cf_def_shutdown,
1048*6236dae4SAndroid Build Coastguard Worker   Curl_cf_def_get_host,
1049*6236dae4SAndroid Build Coastguard Worker   cf_msh3_adjust_pollset,
1050*6236dae4SAndroid Build Coastguard Worker   cf_msh3_data_pending,
1051*6236dae4SAndroid Build Coastguard Worker   cf_msh3_send,
1052*6236dae4SAndroid Build Coastguard Worker   cf_msh3_recv,
1053*6236dae4SAndroid Build Coastguard Worker   cf_msh3_data_event,
1054*6236dae4SAndroid Build Coastguard Worker   cf_msh3_conn_is_alive,
1055*6236dae4SAndroid Build Coastguard Worker   Curl_cf_def_conn_keep_alive,
1056*6236dae4SAndroid Build Coastguard Worker   cf_msh3_query,
1057*6236dae4SAndroid Build Coastguard Worker };
1058*6236dae4SAndroid Build Coastguard Worker 
h3_get_msh3_ctx(struct Curl_easy * data)1059*6236dae4SAndroid Build Coastguard Worker static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data)
1060*6236dae4SAndroid Build Coastguard Worker {
1061*6236dae4SAndroid Build Coastguard Worker   if(data && data->conn) {
1062*6236dae4SAndroid Build Coastguard Worker     struct Curl_cfilter *cf = data->conn->cfilter[FIRSTSOCKET];
1063*6236dae4SAndroid Build Coastguard Worker     while(cf) {
1064*6236dae4SAndroid Build Coastguard Worker       if(cf->cft == &Curl_cft_http3)
1065*6236dae4SAndroid Build Coastguard Worker         return cf->ctx;
1066*6236dae4SAndroid Build Coastguard Worker       cf = cf->next;
1067*6236dae4SAndroid Build Coastguard Worker     }
1068*6236dae4SAndroid Build Coastguard Worker   }
1069*6236dae4SAndroid Build Coastguard Worker   DEBUGF(infof(data, "no filter context found"));
1070*6236dae4SAndroid Build Coastguard Worker   return NULL;
1071*6236dae4SAndroid Build Coastguard Worker }
1072*6236dae4SAndroid Build Coastguard Worker 
Curl_cf_msh3_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai)1073*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
1074*6236dae4SAndroid Build Coastguard Worker                              struct Curl_easy *data,
1075*6236dae4SAndroid Build Coastguard Worker                              struct connectdata *conn,
1076*6236dae4SAndroid Build Coastguard Worker                              const struct Curl_addrinfo *ai)
1077*6236dae4SAndroid Build Coastguard Worker {
1078*6236dae4SAndroid Build Coastguard Worker   struct cf_msh3_ctx *ctx = NULL;
1079*6236dae4SAndroid Build Coastguard Worker   struct Curl_cfilter *cf = NULL;
1080*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
1081*6236dae4SAndroid Build Coastguard Worker 
1082*6236dae4SAndroid Build Coastguard Worker   (void)data;
1083*6236dae4SAndroid Build Coastguard Worker   (void)conn;
1084*6236dae4SAndroid Build Coastguard Worker   (void)ai; /* TODO: msh3 resolves itself? */
1085*6236dae4SAndroid Build Coastguard Worker   ctx = calloc(1, sizeof(*ctx));
1086*6236dae4SAndroid Build Coastguard Worker   if(!ctx) {
1087*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OUT_OF_MEMORY;
1088*6236dae4SAndroid Build Coastguard Worker     goto out;
1089*6236dae4SAndroid Build Coastguard Worker   }
1090*6236dae4SAndroid Build Coastguard Worker   cf_msh3_ctx_init(ctx, ai);
1091*6236dae4SAndroid Build Coastguard Worker 
1092*6236dae4SAndroid Build Coastguard Worker   result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
1093*6236dae4SAndroid Build Coastguard Worker 
1094*6236dae4SAndroid Build Coastguard Worker out:
1095*6236dae4SAndroid Build Coastguard Worker   *pcf = (!result) ? cf : NULL;
1096*6236dae4SAndroid Build Coastguard Worker   if(result) {
1097*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(cf);
1098*6236dae4SAndroid Build Coastguard Worker     cf_msh3_ctx_free(ctx);
1099*6236dae4SAndroid Build Coastguard Worker   }
1100*6236dae4SAndroid Build Coastguard Worker 
1101*6236dae4SAndroid Build Coastguard Worker   return result;
1102*6236dae4SAndroid Build Coastguard Worker }
1103*6236dae4SAndroid Build Coastguard Worker 
Curl_conn_is_msh3(const struct Curl_easy * data,const struct connectdata * conn,int sockindex)1104*6236dae4SAndroid Build Coastguard Worker bool Curl_conn_is_msh3(const struct Curl_easy *data,
1105*6236dae4SAndroid Build Coastguard Worker                        const struct connectdata *conn,
1106*6236dae4SAndroid Build Coastguard Worker                        int sockindex)
1107*6236dae4SAndroid Build Coastguard Worker {
1108*6236dae4SAndroid Build Coastguard Worker   struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
1109*6236dae4SAndroid Build Coastguard Worker 
1110*6236dae4SAndroid Build Coastguard Worker   (void)data;
1111*6236dae4SAndroid Build Coastguard Worker   for(; cf; cf = cf->next) {
1112*6236dae4SAndroid Build Coastguard Worker     if(cf->cft == &Curl_cft_http3)
1113*6236dae4SAndroid Build Coastguard Worker       return TRUE;
1114*6236dae4SAndroid Build Coastguard Worker     if(cf->cft->flags & CF_TYPE_IP_CONNECT)
1115*6236dae4SAndroid Build Coastguard Worker       return FALSE;
1116*6236dae4SAndroid Build Coastguard Worker   }
1117*6236dae4SAndroid Build Coastguard Worker   return FALSE;
1118*6236dae4SAndroid Build Coastguard Worker }
1119*6236dae4SAndroid Build Coastguard Worker 
1120*6236dae4SAndroid Build Coastguard Worker #endif /* USE_MSH3 */
1121