1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery *
4*e7be843bSPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e7be843bSPierre Pronchery * this file except in compliance with the License. You can obtain a copy
6*e7be843bSPierre Pronchery * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery */
9*e7be843bSPierre Pronchery #include <assert.h>
10*e7be843bSPierre Pronchery #include <netinet/in.h>
11*e7be843bSPierre Pronchery #include <nghttp3/nghttp3.h>
12*e7be843bSPierre Pronchery #include <openssl/err.h>
13*e7be843bSPierre Pronchery #include <openssl/quic.h>
14*e7be843bSPierre Pronchery #include <openssl/ssl.h>
15*e7be843bSPierre Pronchery #include <unistd.h>
16*e7be843bSPierre Pronchery #include <sys/stat.h>
17*e7be843bSPierre Pronchery #include <fcntl.h>
18*e7be843bSPierre Pronchery #include <sys/socket.h>
19*e7be843bSPierre Pronchery
20*e7be843bSPierre Pronchery #ifndef PATH_MAX
21*e7be843bSPierre Pronchery # define PATH_MAX 255
22*e7be843bSPierre Pronchery #endif
23*e7be843bSPierre Pronchery
24*e7be843bSPierre Pronchery #define nghttp3_arraylen(A) (sizeof(A) / sizeof(*(A)))
25*e7be843bSPierre Pronchery
26*e7be843bSPierre Pronchery /* The crappy test wants 20 bytes */
27*e7be843bSPierre Pronchery #define NULL_PAYLOAD "12345678901234567890"
28*e7be843bSPierre Pronchery static uint8_t *nulldata = (uint8_t *) NULL_PAYLOAD;
29*e7be843bSPierre Pronchery static size_t nulldata_sz = sizeof(NULL_PAYLOAD) - 1;
30*e7be843bSPierre Pronchery
31*e7be843bSPierre Pronchery /* The nghttp3 variable we need in the main part and read_from_ssl_ids */
32*e7be843bSPierre Pronchery static nghttp3_settings settings;
33*e7be843bSPierre Pronchery static const nghttp3_mem *mem;
34*e7be843bSPierre Pronchery static nghttp3_callbacks callbacks = {0};
35*e7be843bSPierre Pronchery
36*e7be843bSPierre Pronchery /* 3 streams created by the server and 4 by the client (one is bidi) */
37*e7be843bSPierre Pronchery struct ssl_id {
38*e7be843bSPierre Pronchery SSL *s; /* the stream openssl uses in SSL_read(), SSL_write etc */
39*e7be843bSPierre Pronchery uint64_t id; /* the stream identifier the nghttp3 uses */
40*e7be843bSPierre Pronchery int status; /* 0 or one the below status and origin */
41*e7be843bSPierre Pronchery };
42*e7be843bSPierre Pronchery /* status and origin of the streams the possible values are: */
43*e7be843bSPierre Pronchery #define CLIENTUNIOPEN 0x01 /* unidirectional open by the client (2, 6 and 10) */
44*e7be843bSPierre Pronchery #define CLIENTCLOSED 0x02 /* closed by the client */
45*e7be843bSPierre Pronchery #define CLIENTBIDIOPEN 0x04 /* bidirectional open by the client (something like 0, 4, 8 ...) */
46*e7be843bSPierre Pronchery #define SERVERUNIOPEN 0x08 /* unidirectional open by the server (3, 7 and 11) */
47*e7be843bSPierre Pronchery #define SERVERCLOSED 0x10 /* closed by the server (us) */
48*e7be843bSPierre Pronchery #define TOBEREMOVED 0x20 /* marked for removing in read_from_ssl_ids, */
49*e7be843bSPierre Pronchery /* it will be removed after processing all events */
50*e7be843bSPierre Pronchery #define ISLISTENER 0x40 /* the stream is a listener from SSL_new_listener() */
51*e7be843bSPierre Pronchery #define ISCONNECTION 0x80 /* the stream is a connection from SSL_accept_connection() */
52*e7be843bSPierre Pronchery
53*e7be843bSPierre Pronchery #define MAXSSL_IDS 20
54*e7be843bSPierre Pronchery #define MAXURL 255
55*e7be843bSPierre Pronchery
56*e7be843bSPierre Pronchery struct h3ssl {
57*e7be843bSPierre Pronchery struct ssl_id ssl_ids[MAXSSL_IDS];
58*e7be843bSPierre Pronchery int end_headers_received; /* h3 header received call back called */
59*e7be843bSPierre Pronchery int datadone; /* h3 has given openssl all the data of the response */
60*e7be843bSPierre Pronchery int has_uni; /* we have the 3 uni directional stream needed */
61*e7be843bSPierre Pronchery int close_done; /* connection begins terminating EVENT_EC */
62*e7be843bSPierre Pronchery int close_wait; /* we are waiting for a close or a new request */
63*e7be843bSPierre Pronchery int done; /* connection terminated EVENT_ECD, after EVENT_EC */
64*e7be843bSPierre Pronchery int new_conn; /* a new connection has been received */
65*e7be843bSPierre Pronchery int received_from_two; /* workaround for -607 on nghttp3_conn_read_stream on stream 2 */
66*e7be843bSPierre Pronchery int restart; /* new request/response cycle started */
67*e7be843bSPierre Pronchery uint64_t id_bidi; /* the id of the stream used to read request and send response */
68*e7be843bSPierre Pronchery char *fileprefix; /* prefix of the directory to fetch files from */
69*e7be843bSPierre Pronchery char url[MAXURL]; /* url to serve the request */
70*e7be843bSPierre Pronchery uint8_t *ptr_data; /* pointer to the data to send */
71*e7be843bSPierre Pronchery size_t ldata; /* amount of bytes to send */
72*e7be843bSPierre Pronchery int offset_data; /* offset to next data to send */
73*e7be843bSPierre Pronchery };
74*e7be843bSPierre Pronchery
make_nv(nghttp3_nv * nv,const char * name,const char * value)75*e7be843bSPierre Pronchery static void make_nv(nghttp3_nv *nv, const char *name, const char *value)
76*e7be843bSPierre Pronchery {
77*e7be843bSPierre Pronchery nv->name = (uint8_t *)name;
78*e7be843bSPierre Pronchery nv->value = (uint8_t *)value;
79*e7be843bSPierre Pronchery nv->namelen = strlen(name);
80*e7be843bSPierre Pronchery nv->valuelen = strlen(value);
81*e7be843bSPierre Pronchery nv->flags = NGHTTP3_NV_FLAG_NONE;
82*e7be843bSPierre Pronchery }
83*e7be843bSPierre Pronchery
init_ids(struct h3ssl * h3ssl)84*e7be843bSPierre Pronchery static void init_ids(struct h3ssl *h3ssl)
85*e7be843bSPierre Pronchery {
86*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
87*e7be843bSPierre Pronchery int i;
88*e7be843bSPierre Pronchery char *prior_fileprefix = h3ssl->fileprefix;
89*e7be843bSPierre Pronchery
90*e7be843bSPierre Pronchery if (h3ssl->ptr_data != NULL && h3ssl->ptr_data != nulldata)
91*e7be843bSPierre Pronchery free(h3ssl->ptr_data);
92*e7be843bSPierre Pronchery
93*e7be843bSPierre Pronchery memset(h3ssl, 0, sizeof(struct h3ssl));
94*e7be843bSPierre Pronchery
95*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
96*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++)
97*e7be843bSPierre Pronchery ssl_ids[i].id = UINT64_MAX;
98*e7be843bSPierre Pronchery h3ssl->id_bidi = UINT64_MAX;
99*e7be843bSPierre Pronchery
100*e7be843bSPierre Pronchery /* restore the fileprefix */
101*e7be843bSPierre Pronchery h3ssl->fileprefix = prior_fileprefix;
102*e7be843bSPierre Pronchery }
103*e7be843bSPierre Pronchery
reuse_h3ssl(struct h3ssl * h3ssl)104*e7be843bSPierre Pronchery static void reuse_h3ssl(struct h3ssl *h3ssl)
105*e7be843bSPierre Pronchery {
106*e7be843bSPierre Pronchery h3ssl->end_headers_received = 0;
107*e7be843bSPierre Pronchery h3ssl->datadone = 0;
108*e7be843bSPierre Pronchery h3ssl->close_done = 0;
109*e7be843bSPierre Pronchery h3ssl->close_wait = 0;
110*e7be843bSPierre Pronchery h3ssl->done = 0;
111*e7be843bSPierre Pronchery memset(h3ssl->url, '\0', sizeof(h3ssl->url));
112*e7be843bSPierre Pronchery if (h3ssl->ptr_data != NULL && h3ssl->ptr_data != nulldata)
113*e7be843bSPierre Pronchery free(h3ssl->ptr_data);
114*e7be843bSPierre Pronchery h3ssl->ptr_data = NULL;
115*e7be843bSPierre Pronchery h3ssl->offset_data = 0;
116*e7be843bSPierre Pronchery h3ssl->ldata = 0;
117*e7be843bSPierre Pronchery }
118*e7be843bSPierre Pronchery
add_id_status(uint64_t id,SSL * ssl,struct h3ssl * h3ssl,int status)119*e7be843bSPierre Pronchery static void add_id_status(uint64_t id, SSL *ssl, struct h3ssl *h3ssl, int status)
120*e7be843bSPierre Pronchery {
121*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
122*e7be843bSPierre Pronchery int i;
123*e7be843bSPierre Pronchery
124*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
125*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
126*e7be843bSPierre Pronchery if (ssl_ids[i].s == NULL) {
127*e7be843bSPierre Pronchery ssl_ids[i].s = ssl;
128*e7be843bSPierre Pronchery ssl_ids[i].id = id;
129*e7be843bSPierre Pronchery ssl_ids[i].status = status;
130*e7be843bSPierre Pronchery return;
131*e7be843bSPierre Pronchery }
132*e7be843bSPierre Pronchery }
133*e7be843bSPierre Pronchery printf("Oops too many streams to add!!!\n");
134*e7be843bSPierre Pronchery exit(1);
135*e7be843bSPierre Pronchery }
add_id(uint64_t id,SSL * ssl,struct h3ssl * h3ssl)136*e7be843bSPierre Pronchery static void add_id(uint64_t id, SSL *ssl, struct h3ssl *h3ssl)
137*e7be843bSPierre Pronchery {
138*e7be843bSPierre Pronchery add_id_status(id, ssl, h3ssl, 0);
139*e7be843bSPierre Pronchery }
140*e7be843bSPierre Pronchery
141*e7be843bSPierre Pronchery /* Add listener and connection */
add_ids_listener(SSL * ssl,struct h3ssl * h3ssl)142*e7be843bSPierre Pronchery static void add_ids_listener(SSL *ssl, struct h3ssl *h3ssl)
143*e7be843bSPierre Pronchery {
144*e7be843bSPierre Pronchery add_id_status(UINT64_MAX, ssl, h3ssl, ISLISTENER);
145*e7be843bSPierre Pronchery }
add_ids_connection(struct h3ssl * h3ssl,SSL * ssl)146*e7be843bSPierre Pronchery static void add_ids_connection(struct h3ssl *h3ssl, SSL *ssl)
147*e7be843bSPierre Pronchery {
148*e7be843bSPierre Pronchery add_id_status(UINT64_MAX, ssl, h3ssl, ISCONNECTION);
149*e7be843bSPierre Pronchery }
get_ids_connection(struct h3ssl * h3ssl)150*e7be843bSPierre Pronchery static SSL *get_ids_connection(struct h3ssl *h3ssl)
151*e7be843bSPierre Pronchery {
152*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
153*e7be843bSPierre Pronchery int i;
154*e7be843bSPierre Pronchery
155*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
156*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
157*e7be843bSPierre Pronchery if (ssl_ids[i].status & ISCONNECTION) {
158*e7be843bSPierre Pronchery printf("get_ids_connection\n");
159*e7be843bSPierre Pronchery return ssl_ids[i].s;
160*e7be843bSPierre Pronchery }
161*e7be843bSPierre Pronchery }
162*e7be843bSPierre Pronchery return NULL;
163*e7be843bSPierre Pronchery }
replace_ids_connection(struct h3ssl * h3ssl,SSL * oldstream,SSL * newstream)164*e7be843bSPierre Pronchery static void replace_ids_connection(struct h3ssl *h3ssl, SSL *oldstream, SSL *newstream)
165*e7be843bSPierre Pronchery {
166*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
167*e7be843bSPierre Pronchery int i;
168*e7be843bSPierre Pronchery
169*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
170*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
171*e7be843bSPierre Pronchery if (ssl_ids[i].status & ISCONNECTION && ssl_ids[i].s == oldstream) {
172*e7be843bSPierre Pronchery printf("replace_ids_connection\n");
173*e7be843bSPierre Pronchery ssl_ids[i].s = newstream;
174*e7be843bSPierre Pronchery }
175*e7be843bSPierre Pronchery }
176*e7be843bSPierre Pronchery }
177*e7be843bSPierre Pronchery
178*e7be843bSPierre Pronchery /* remove the ids marked for removal */
remove_marked_ids(struct h3ssl * h3ssl)179*e7be843bSPierre Pronchery static void remove_marked_ids(struct h3ssl *h3ssl)
180*e7be843bSPierre Pronchery {
181*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
182*e7be843bSPierre Pronchery int i;
183*e7be843bSPierre Pronchery
184*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
185*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
186*e7be843bSPierre Pronchery if (ssl_ids[i].status & TOBEREMOVED) {
187*e7be843bSPierre Pronchery printf("remove_id %llu\n", (unsigned long long) ssl_ids[i].id);
188*e7be843bSPierre Pronchery SSL_free(ssl_ids[i].s);
189*e7be843bSPierre Pronchery ssl_ids[i].s = NULL;
190*e7be843bSPierre Pronchery ssl_ids[i].id = UINT64_MAX;
191*e7be843bSPierre Pronchery ssl_ids[i].status = 0;
192*e7be843bSPierre Pronchery return;
193*e7be843bSPierre Pronchery }
194*e7be843bSPierre Pronchery }
195*e7be843bSPierre Pronchery }
196*e7be843bSPierre Pronchery
197*e7be843bSPierre Pronchery /* add the status bytes to the status */
set_id_status(uint64_t id,int status,struct h3ssl * h3ssl)198*e7be843bSPierre Pronchery static void set_id_status(uint64_t id, int status, struct h3ssl *h3ssl)
199*e7be843bSPierre Pronchery {
200*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
201*e7be843bSPierre Pronchery int i;
202*e7be843bSPierre Pronchery
203*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
204*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
205*e7be843bSPierre Pronchery if (ssl_ids[i].id == id) {
206*e7be843bSPierre Pronchery printf("set_id_status: %llu to %d\n", (unsigned long long) ssl_ids[i].id, status);
207*e7be843bSPierre Pronchery ssl_ids[i].status = ssl_ids[i].status | status;
208*e7be843bSPierre Pronchery return;
209*e7be843bSPierre Pronchery }
210*e7be843bSPierre Pronchery }
211*e7be843bSPierre Pronchery printf("Oops can't set status, can't find stream!!!\n");
212*e7be843bSPierre Pronchery assert(0);
213*e7be843bSPierre Pronchery }
get_id_status(uint64_t id,struct h3ssl * h3ssl)214*e7be843bSPierre Pronchery static int get_id_status(uint64_t id, struct h3ssl *h3ssl)
215*e7be843bSPierre Pronchery {
216*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
217*e7be843bSPierre Pronchery int i;
218*e7be843bSPierre Pronchery
219*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
220*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
221*e7be843bSPierre Pronchery if (ssl_ids[i].id == id) {
222*e7be843bSPierre Pronchery printf("get_id_status: %llu to %d\n",
223*e7be843bSPierre Pronchery (unsigned long long) ssl_ids[i].id, ssl_ids[i].status);
224*e7be843bSPierre Pronchery return ssl_ids[i].status;
225*e7be843bSPierre Pronchery }
226*e7be843bSPierre Pronchery }
227*e7be843bSPierre Pronchery printf("Oops can't get status, can't find stream!!!\n");
228*e7be843bSPierre Pronchery assert(0);
229*e7be843bSPierre Pronchery return -1;
230*e7be843bSPierre Pronchery }
231*e7be843bSPierre Pronchery
232*e7be843bSPierre Pronchery /* check that all streams opened by the client are closed */
are_all_clientid_closed(struct h3ssl * h3ssl)233*e7be843bSPierre Pronchery static int are_all_clientid_closed(struct h3ssl *h3ssl)
234*e7be843bSPierre Pronchery {
235*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
236*e7be843bSPierre Pronchery int i;
237*e7be843bSPierre Pronchery
238*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
239*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
240*e7be843bSPierre Pronchery if (ssl_ids[i].id == UINT64_MAX)
241*e7be843bSPierre Pronchery continue;
242*e7be843bSPierre Pronchery printf("are_all_clientid_closed: %llu status %d : %d\n",
243*e7be843bSPierre Pronchery (unsigned long long) ssl_ids[i].id, ssl_ids[i].status, CLIENTUNIOPEN | CLIENTCLOSED);
244*e7be843bSPierre Pronchery if (ssl_ids[i].status & CLIENTUNIOPEN) {
245*e7be843bSPierre Pronchery if (ssl_ids[i].status & CLIENTCLOSED) {
246*e7be843bSPierre Pronchery printf("are_all_clientid_closed: %llu closed\n",
247*e7be843bSPierre Pronchery (unsigned long long) ssl_ids[i].id);
248*e7be843bSPierre Pronchery SSL_free(ssl_ids[i].s);
249*e7be843bSPierre Pronchery ssl_ids[i].s = NULL;
250*e7be843bSPierre Pronchery ssl_ids[i].id = UINT64_MAX;
251*e7be843bSPierre Pronchery continue;
252*e7be843bSPierre Pronchery }
253*e7be843bSPierre Pronchery printf("are_all_clientid_closed: %llu open\n", (unsigned long long) ssl_ids[i].id);
254*e7be843bSPierre Pronchery return 0;
255*e7be843bSPierre Pronchery }
256*e7be843bSPierre Pronchery }
257*e7be843bSPierre Pronchery return 1;
258*e7be843bSPierre Pronchery }
259*e7be843bSPierre Pronchery
260*e7be843bSPierre Pronchery /* free all the ids except listener and connection */
close_all_ids(struct h3ssl * h3ssl)261*e7be843bSPierre Pronchery static void close_all_ids(struct h3ssl *h3ssl)
262*e7be843bSPierre Pronchery {
263*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
264*e7be843bSPierre Pronchery int i;
265*e7be843bSPierre Pronchery
266*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
267*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
268*e7be843bSPierre Pronchery if (ssl_ids[i].id == UINT64_MAX)
269*e7be843bSPierre Pronchery continue;
270*e7be843bSPierre Pronchery SSL_free(ssl_ids[i].s);
271*e7be843bSPierre Pronchery ssl_ids[i].s = NULL;
272*e7be843bSPierre Pronchery ssl_ids[i].id = UINT64_MAX;
273*e7be843bSPierre Pronchery }
274*e7be843bSPierre Pronchery }
275*e7be843bSPierre Pronchery
on_recv_header(nghttp3_conn * conn,int64_t stream_id,int32_t token,nghttp3_rcbuf * name,nghttp3_rcbuf * value,uint8_t flags,void * user_data,void * stream_user_data)276*e7be843bSPierre Pronchery static int on_recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token,
277*e7be843bSPierre Pronchery nghttp3_rcbuf *name, nghttp3_rcbuf *value,
278*e7be843bSPierre Pronchery uint8_t flags, void *user_data,
279*e7be843bSPierre Pronchery void *stream_user_data)
280*e7be843bSPierre Pronchery {
281*e7be843bSPierre Pronchery nghttp3_vec vname, vvalue;
282*e7be843bSPierre Pronchery struct h3ssl *h3ssl = (struct h3ssl *)user_data;
283*e7be843bSPierre Pronchery
284*e7be843bSPierre Pronchery /* Received a single HTTP header. */
285*e7be843bSPierre Pronchery vname = nghttp3_rcbuf_get_buf(name);
286*e7be843bSPierre Pronchery vvalue = nghttp3_rcbuf_get_buf(value);
287*e7be843bSPierre Pronchery
288*e7be843bSPierre Pronchery fwrite(vname.base, vname.len, 1, stdout);
289*e7be843bSPierre Pronchery fprintf(stdout, ": ");
290*e7be843bSPierre Pronchery fwrite(vvalue.base, vvalue.len, 1, stdout);
291*e7be843bSPierre Pronchery fprintf(stdout, "\n");
292*e7be843bSPierre Pronchery
293*e7be843bSPierre Pronchery if (token == NGHTTP3_QPACK_TOKEN__PATH) {
294*e7be843bSPierre Pronchery int len = (((vvalue.len) < (MAXURL)) ? (vvalue.len) : (MAXURL));
295*e7be843bSPierre Pronchery
296*e7be843bSPierre Pronchery memset(h3ssl->url, 0, sizeof(h3ssl->url));
297*e7be843bSPierre Pronchery if (vvalue.base[0] == '/') {
298*e7be843bSPierre Pronchery if (vvalue.base[1] == '\0') {
299*e7be843bSPierre Pronchery strncpy(h3ssl->url, "index.html", MAXURL);
300*e7be843bSPierre Pronchery } else {
301*e7be843bSPierre Pronchery memcpy(h3ssl->url, vvalue.base + 1, len - 1);
302*e7be843bSPierre Pronchery h3ssl->url[len - 1] = '\0';
303*e7be843bSPierre Pronchery }
304*e7be843bSPierre Pronchery } else {
305*e7be843bSPierre Pronchery memcpy(h3ssl->url, vvalue.base, len);
306*e7be843bSPierre Pronchery }
307*e7be843bSPierre Pronchery }
308*e7be843bSPierre Pronchery
309*e7be843bSPierre Pronchery return 0;
310*e7be843bSPierre Pronchery }
311*e7be843bSPierre Pronchery
on_end_headers(nghttp3_conn * conn,int64_t stream_id,int fin,void * user_data,void * stream_user_data)312*e7be843bSPierre Pronchery static int on_end_headers(nghttp3_conn *conn, int64_t stream_id, int fin,
313*e7be843bSPierre Pronchery void *user_data, void *stream_user_data)
314*e7be843bSPierre Pronchery {
315*e7be843bSPierre Pronchery struct h3ssl *h3ssl = (struct h3ssl *)user_data;
316*e7be843bSPierre Pronchery
317*e7be843bSPierre Pronchery fprintf(stderr, "on_end_headers!\n");
318*e7be843bSPierre Pronchery h3ssl->end_headers_received = 1;
319*e7be843bSPierre Pronchery return 0;
320*e7be843bSPierre Pronchery }
321*e7be843bSPierre Pronchery
on_recv_data(nghttp3_conn * conn,int64_t stream_id,const uint8_t * data,size_t datalen,void * conn_user_data,void * stream_user_data)322*e7be843bSPierre Pronchery static int on_recv_data(nghttp3_conn *conn, int64_t stream_id,
323*e7be843bSPierre Pronchery const uint8_t *data, size_t datalen,
324*e7be843bSPierre Pronchery void *conn_user_data, void *stream_user_data)
325*e7be843bSPierre Pronchery {
326*e7be843bSPierre Pronchery fprintf(stderr, "on_recv_data! %ld\n", (unsigned long)datalen);
327*e7be843bSPierre Pronchery fprintf(stderr, "on_recv_data! %.*s\n", (int)datalen, data);
328*e7be843bSPierre Pronchery return 0;
329*e7be843bSPierre Pronchery }
330*e7be843bSPierre Pronchery
on_end_stream(nghttp3_conn * h3conn,int64_t stream_id,void * conn_user_data,void * stream_user_data)331*e7be843bSPierre Pronchery static int on_end_stream(nghttp3_conn *h3conn, int64_t stream_id,
332*e7be843bSPierre Pronchery void *conn_user_data, void *stream_user_data)
333*e7be843bSPierre Pronchery {
334*e7be843bSPierre Pronchery struct h3ssl *h3ssl = (struct h3ssl *)conn_user_data;
335*e7be843bSPierre Pronchery
336*e7be843bSPierre Pronchery printf("on_end_stream!\n");
337*e7be843bSPierre Pronchery h3ssl->done = 1;
338*e7be843bSPierre Pronchery return 0;
339*e7be843bSPierre Pronchery }
340*e7be843bSPierre Pronchery
341*e7be843bSPierre Pronchery /* Read from the stream and push to the h3conn */
quic_server_read(nghttp3_conn * h3conn,SSL * stream,uint64_t id,struct h3ssl * h3ssl)342*e7be843bSPierre Pronchery static int quic_server_read(nghttp3_conn *h3conn, SSL *stream, uint64_t id, struct h3ssl *h3ssl)
343*e7be843bSPierre Pronchery {
344*e7be843bSPierre Pronchery int ret, r;
345*e7be843bSPierre Pronchery uint8_t msg2[16000];
346*e7be843bSPierre Pronchery size_t l = sizeof(msg2);
347*e7be843bSPierre Pronchery
348*e7be843bSPierre Pronchery if (!SSL_has_pending(stream))
349*e7be843bSPierre Pronchery return 0; /* Nothing to read */
350*e7be843bSPierre Pronchery
351*e7be843bSPierre Pronchery ret = SSL_read(stream, msg2, l);
352*e7be843bSPierre Pronchery if (ret <= 0) {
353*e7be843bSPierre Pronchery fprintf(stderr, "SSL_read %d on %llu failed\n",
354*e7be843bSPierre Pronchery SSL_get_error(stream, ret),
355*e7be843bSPierre Pronchery (unsigned long long) id);
356*e7be843bSPierre Pronchery switch (SSL_get_error(stream, ret)) {
357*e7be843bSPierre Pronchery case SSL_ERROR_WANT_READ:
358*e7be843bSPierre Pronchery return 0;
359*e7be843bSPierre Pronchery case SSL_ERROR_ZERO_RETURN:
360*e7be843bSPierre Pronchery return 1;
361*e7be843bSPierre Pronchery default:
362*e7be843bSPierre Pronchery ERR_print_errors_fp(stderr);
363*e7be843bSPierre Pronchery return -1;
364*e7be843bSPierre Pronchery }
365*e7be843bSPierre Pronchery return -1;
366*e7be843bSPierre Pronchery }
367*e7be843bSPierre Pronchery
368*e7be843bSPierre Pronchery /* XXX: work around nghttp3_conn_read_stream returning -607 on stream 2 */
369*e7be843bSPierre Pronchery if (!h3ssl->received_from_two && id != 2) {
370*e7be843bSPierre Pronchery r = nghttp3_conn_read_stream(h3conn, id, msg2, ret, 0);
371*e7be843bSPierre Pronchery } else {
372*e7be843bSPierre Pronchery r = ret; /* ignore it for the moment ... */
373*e7be843bSPierre Pronchery }
374*e7be843bSPierre Pronchery
375*e7be843bSPierre Pronchery printf("nghttp3_conn_read_stream used %d of %d on %llu\n", r,
376*e7be843bSPierre Pronchery ret, (unsigned long long) id);
377*e7be843bSPierre Pronchery if (r != ret) {
378*e7be843bSPierre Pronchery /* chrome returns -607 on stream 2 */
379*e7be843bSPierre Pronchery if (!nghttp3_err_is_fatal(r)) {
380*e7be843bSPierre Pronchery printf("nghttp3_conn_read_stream used %d of %d (not fatal) on %llu\n", r,
381*e7be843bSPierre Pronchery ret, (unsigned long long) id);
382*e7be843bSPierre Pronchery if (id == 2)
383*e7be843bSPierre Pronchery h3ssl->received_from_two = 1;
384*e7be843bSPierre Pronchery return 1;
385*e7be843bSPierre Pronchery }
386*e7be843bSPierre Pronchery return -1;
387*e7be843bSPierre Pronchery }
388*e7be843bSPierre Pronchery return 1;
389*e7be843bSPierre Pronchery }
390*e7be843bSPierre Pronchery
391*e7be843bSPierre Pronchery /*
392*e7be843bSPierre Pronchery * creates the control stream, the encoding and decoding streams.
393*e7be843bSPierre Pronchery * nghttp3_conn_bind_control_stream() is for the control stream.
394*e7be843bSPierre Pronchery */
quic_server_h3streams(nghttp3_conn * h3conn,struct h3ssl * h3ssl)395*e7be843bSPierre Pronchery static int quic_server_h3streams(nghttp3_conn *h3conn, struct h3ssl *h3ssl)
396*e7be843bSPierre Pronchery {
397*e7be843bSPierre Pronchery SSL *rstream = NULL;
398*e7be843bSPierre Pronchery SSL *pstream = NULL;
399*e7be843bSPierre Pronchery SSL *cstream = NULL;
400*e7be843bSPierre Pronchery SSL *conn;
401*e7be843bSPierre Pronchery uint64_t r_streamid, p_streamid, c_streamid;
402*e7be843bSPierre Pronchery
403*e7be843bSPierre Pronchery conn = get_ids_connection(h3ssl);
404*e7be843bSPierre Pronchery if (conn == NULL) {
405*e7be843bSPierre Pronchery fprintf(stderr, "quic_server_h3streams no connection\n");
406*e7be843bSPierre Pronchery fflush(stderr);
407*e7be843bSPierre Pronchery return -1;
408*e7be843bSPierre Pronchery }
409*e7be843bSPierre Pronchery rstream = SSL_new_stream(conn, SSL_STREAM_FLAG_UNI);
410*e7be843bSPierre Pronchery if (rstream != NULL) {
411*e7be843bSPierre Pronchery printf("=> Opened on %llu\n",
412*e7be843bSPierre Pronchery (unsigned long long)SSL_get_stream_id(rstream));
413*e7be843bSPierre Pronchery } else {
414*e7be843bSPierre Pronchery fprintf(stderr, "=> Stream == NULL!\n");
415*e7be843bSPierre Pronchery goto err;
416*e7be843bSPierre Pronchery }
417*e7be843bSPierre Pronchery pstream = SSL_new_stream(conn, SSL_STREAM_FLAG_UNI);
418*e7be843bSPierre Pronchery if (pstream != NULL) {
419*e7be843bSPierre Pronchery printf("=> Opened on %llu\n",
420*e7be843bSPierre Pronchery (unsigned long long)SSL_get_stream_id(pstream));
421*e7be843bSPierre Pronchery } else {
422*e7be843bSPierre Pronchery fprintf(stderr, "=> Stream == NULL!\n");
423*e7be843bSPierre Pronchery goto err;
424*e7be843bSPierre Pronchery }
425*e7be843bSPierre Pronchery cstream = SSL_new_stream(conn, SSL_STREAM_FLAG_UNI);
426*e7be843bSPierre Pronchery if (cstream != NULL) {
427*e7be843bSPierre Pronchery fprintf(stderr, "=> Opened on %llu\n",
428*e7be843bSPierre Pronchery (unsigned long long)SSL_get_stream_id(cstream));
429*e7be843bSPierre Pronchery fflush(stderr);
430*e7be843bSPierre Pronchery } else {
431*e7be843bSPierre Pronchery fprintf(stderr, "=> Stream == NULL!\n");
432*e7be843bSPierre Pronchery goto err;
433*e7be843bSPierre Pronchery }
434*e7be843bSPierre Pronchery r_streamid = SSL_get_stream_id(rstream);
435*e7be843bSPierre Pronchery p_streamid = SSL_get_stream_id(pstream);
436*e7be843bSPierre Pronchery c_streamid = SSL_get_stream_id(cstream);
437*e7be843bSPierre Pronchery if (nghttp3_conn_bind_qpack_streams(h3conn, p_streamid, r_streamid)) {
438*e7be843bSPierre Pronchery fprintf(stderr, "nghttp3_conn_bind_qpack_streams failed!\n");
439*e7be843bSPierre Pronchery goto err;
440*e7be843bSPierre Pronchery }
441*e7be843bSPierre Pronchery if (nghttp3_conn_bind_control_stream(h3conn, c_streamid)) {
442*e7be843bSPierre Pronchery fprintf(stderr, "nghttp3_conn_bind_qpack_streams failed!\n");
443*e7be843bSPierre Pronchery goto err;
444*e7be843bSPierre Pronchery }
445*e7be843bSPierre Pronchery printf("control: %llu enc %llu dec %llu\n",
446*e7be843bSPierre Pronchery (unsigned long long)c_streamid,
447*e7be843bSPierre Pronchery (unsigned long long)p_streamid,
448*e7be843bSPierre Pronchery (unsigned long long)r_streamid);
449*e7be843bSPierre Pronchery add_id(SSL_get_stream_id(rstream), rstream, h3ssl);
450*e7be843bSPierre Pronchery add_id(SSL_get_stream_id(pstream), pstream, h3ssl);
451*e7be843bSPierre Pronchery add_id(SSL_get_stream_id(cstream), cstream, h3ssl);
452*e7be843bSPierre Pronchery
453*e7be843bSPierre Pronchery return 0;
454*e7be843bSPierre Pronchery err:
455*e7be843bSPierre Pronchery fflush(stderr);
456*e7be843bSPierre Pronchery SSL_free(rstream);
457*e7be843bSPierre Pronchery SSL_free(pstream);
458*e7be843bSPierre Pronchery SSL_free(cstream);
459*e7be843bSPierre Pronchery return -1;
460*e7be843bSPierre Pronchery }
461*e7be843bSPierre Pronchery
462*e7be843bSPierre Pronchery /* Try to read from the streams we have */
read_from_ssl_ids(nghttp3_conn ** curh3conn,struct h3ssl * h3ssl)463*e7be843bSPierre Pronchery static int read_from_ssl_ids(nghttp3_conn **curh3conn, struct h3ssl *h3ssl)
464*e7be843bSPierre Pronchery {
465*e7be843bSPierre Pronchery int hassomething = 0, i;
466*e7be843bSPierre Pronchery struct ssl_id *ssl_ids = h3ssl->ssl_ids;
467*e7be843bSPierre Pronchery SSL_POLL_ITEM items[MAXSSL_IDS] = {0}, *item = items;
468*e7be843bSPierre Pronchery static const struct timeval nz_timeout = {0, 0};
469*e7be843bSPierre Pronchery size_t result_count = SIZE_MAX;
470*e7be843bSPierre Pronchery int numitem = 0, ret;
471*e7be843bSPierre Pronchery uint64_t processed_event = 0;
472*e7be843bSPierre Pronchery int has_ids_to_remove = 0;
473*e7be843bSPierre Pronchery nghttp3_conn *h3conn = *curh3conn;
474*e7be843bSPierre Pronchery
475*e7be843bSPierre Pronchery /*
476*e7be843bSPierre Pronchery * Process all the streams
477*e7be843bSPierre Pronchery * the first one is the connection if we get something here is a new stream
478*e7be843bSPierre Pronchery */
479*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
480*e7be843bSPierre Pronchery if (ssl_ids[i].s != NULL) {
481*e7be843bSPierre Pronchery item->desc = SSL_as_poll_descriptor(ssl_ids[i].s);
482*e7be843bSPierre Pronchery item->events = UINT64_MAX; /* TODO adjust to the event we need process */
483*e7be843bSPierre Pronchery item->revents = UINT64_MAX; /* TODO adjust to the event we need process */
484*e7be843bSPierre Pronchery numitem++;
485*e7be843bSPierre Pronchery item++;
486*e7be843bSPierre Pronchery }
487*e7be843bSPierre Pronchery }
488*e7be843bSPierre Pronchery
489*e7be843bSPierre Pronchery /*
490*e7be843bSPierre Pronchery * SSL_POLL_FLAG_NO_HANDLE_EVENTS would require to use:
491*e7be843bSPierre Pronchery * SSL_get_event_timeout on the connection stream
492*e7be843bSPierre Pronchery * select/wait using the timeout value (which could be no wait time)
493*e7be843bSPierre Pronchery * SSL_handle_events
494*e7be843bSPierre Pronchery * SSL_poll
495*e7be843bSPierre Pronchery * for the moment we let SSL_poll to performs ticking internally
496*e7be843bSPierre Pronchery * on an automatic basis.
497*e7be843bSPierre Pronchery */
498*e7be843bSPierre Pronchery ret = SSL_poll(items, numitem, sizeof(SSL_POLL_ITEM), &nz_timeout,
499*e7be843bSPierre Pronchery SSL_POLL_FLAG_NO_HANDLE_EVENTS, &result_count);
500*e7be843bSPierre Pronchery if (!ret) {
501*e7be843bSPierre Pronchery fprintf(stderr, "SSL_poll failed\n");
502*e7be843bSPierre Pronchery printf("SSL_poll failed\n");
503*e7be843bSPierre Pronchery return -1; /* something is wrong */
504*e7be843bSPierre Pronchery }
505*e7be843bSPierre Pronchery printf("read_from_ssl_ids %ld events\n", (unsigned long)result_count);
506*e7be843bSPierre Pronchery if (result_count == 0) {
507*e7be843bSPierre Pronchery /* Timeout may be something somewhere */
508*e7be843bSPierre Pronchery return 0;
509*e7be843bSPierre Pronchery }
510*e7be843bSPierre Pronchery
511*e7be843bSPierre Pronchery /* reset the states */
512*e7be843bSPierre Pronchery h3ssl->new_conn = 0;
513*e7be843bSPierre Pronchery h3ssl->restart = 0;
514*e7be843bSPierre Pronchery h3ssl->done = 0;
515*e7be843bSPierre Pronchery
516*e7be843bSPierre Pronchery /* Process all the item we have polled */
517*e7be843bSPierre Pronchery for (i = 0, item = items; i < numitem; i++, item++) {
518*e7be843bSPierre Pronchery SSL *s;
519*e7be843bSPierre Pronchery
520*e7be843bSPierre Pronchery if (item->revents == SSL_POLL_EVENT_NONE)
521*e7be843bSPierre Pronchery continue;
522*e7be843bSPierre Pronchery processed_event = 0;
523*e7be843bSPierre Pronchery /* get the stream */
524*e7be843bSPierre Pronchery s = item->desc.value.ssl;
525*e7be843bSPierre Pronchery
526*e7be843bSPierre Pronchery /* New connection */
527*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_IC) {
528*e7be843bSPierre Pronchery SSL *conn = SSL_accept_connection(item->desc.value.ssl, 0);
529*e7be843bSPierre Pronchery SSL *oldconn;
530*e7be843bSPierre Pronchery
531*e7be843bSPierre Pronchery printf("SSL_accept_connection\n");
532*e7be843bSPierre Pronchery if (conn == NULL) {
533*e7be843bSPierre Pronchery fprintf(stderr, "error while accepting connection\n");
534*e7be843bSPierre Pronchery ret = -1;
535*e7be843bSPierre Pronchery goto err;
536*e7be843bSPierre Pronchery }
537*e7be843bSPierre Pronchery
538*e7be843bSPierre Pronchery /* the previous might be still there */
539*e7be843bSPierre Pronchery oldconn = get_ids_connection(h3ssl);
540*e7be843bSPierre Pronchery if (oldconn != NULL) {
541*e7be843bSPierre Pronchery /* XXX we support only one connection for the moment */
542*e7be843bSPierre Pronchery printf("SSL_accept_connection closing previous\n");
543*e7be843bSPierre Pronchery SSL_free(oldconn);
544*e7be843bSPierre Pronchery replace_ids_connection(h3ssl, oldconn, conn);
545*e7be843bSPierre Pronchery reuse_h3ssl(h3ssl);
546*e7be843bSPierre Pronchery close_all_ids(h3ssl);
547*e7be843bSPierre Pronchery h3ssl->id_bidi = UINT64_MAX;
548*e7be843bSPierre Pronchery h3ssl->has_uni = 0;
549*e7be843bSPierre Pronchery } else {
550*e7be843bSPierre Pronchery printf("SSL_accept_connection first connection\n");
551*e7be843bSPierre Pronchery add_ids_connection(h3ssl, conn);
552*e7be843bSPierre Pronchery }
553*e7be843bSPierre Pronchery h3ssl->new_conn = 1;
554*e7be843bSPierre Pronchery /* create the new h3conn */
555*e7be843bSPierre Pronchery nghttp3_conn_del(*curh3conn);
556*e7be843bSPierre Pronchery nghttp3_settings_default(&settings);
557*e7be843bSPierre Pronchery if (nghttp3_conn_server_new(curh3conn, &callbacks, &settings, mem,
558*e7be843bSPierre Pronchery h3ssl)) {
559*e7be843bSPierre Pronchery fprintf(stderr, "nghttp3_conn_client_new failed!\n");
560*e7be843bSPierre Pronchery exit(1);
561*e7be843bSPierre Pronchery }
562*e7be843bSPierre Pronchery h3conn = *curh3conn;
563*e7be843bSPierre Pronchery hassomething++;
564*e7be843bSPierre Pronchery
565*e7be843bSPierre Pronchery if (!SSL_set_incoming_stream_policy(conn,
566*e7be843bSPierre Pronchery SSL_INCOMING_STREAM_POLICY_ACCEPT, 0)) {
567*e7be843bSPierre Pronchery fprintf(stderr, "error while setting inccoming stream policy\n");
568*e7be843bSPierre Pronchery ret = -1;
569*e7be843bSPierre Pronchery goto err;
570*e7be843bSPierre Pronchery }
571*e7be843bSPierre Pronchery
572*e7be843bSPierre Pronchery printf("SSL_accept_connection\n");
573*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_IC;
574*e7be843bSPierre Pronchery }
575*e7be843bSPierre Pronchery /* SSL_accept_stream if SSL_POLL_EVENT_ISB or SSL_POLL_EVENT_ISU */
576*e7be843bSPierre Pronchery if ((item->revents & SSL_POLL_EVENT_ISB) ||
577*e7be843bSPierre Pronchery (item->revents & SSL_POLL_EVENT_ISU)) {
578*e7be843bSPierre Pronchery SSL *stream = SSL_accept_stream(item->desc.value.ssl, 0);
579*e7be843bSPierre Pronchery uint64_t new_id;
580*e7be843bSPierre Pronchery int r;
581*e7be843bSPierre Pronchery
582*e7be843bSPierre Pronchery if (stream == NULL) {
583*e7be843bSPierre Pronchery ret = -1;
584*e7be843bSPierre Pronchery goto err;
585*e7be843bSPierre Pronchery }
586*e7be843bSPierre Pronchery new_id = SSL_get_stream_id(stream);
587*e7be843bSPierre Pronchery printf("=> Received connection on %lld %d\n", (unsigned long long) new_id,
588*e7be843bSPierre Pronchery SSL_get_stream_type(stream));
589*e7be843bSPierre Pronchery add_id(new_id, stream, h3ssl);
590*e7be843bSPierre Pronchery if (h3ssl->close_wait) {
591*e7be843bSPierre Pronchery printf("in close_wait so we will have a new request\n");
592*e7be843bSPierre Pronchery reuse_h3ssl(h3ssl);
593*e7be843bSPierre Pronchery h3ssl->restart = 1; /* Checked in wait_close loop */
594*e7be843bSPierre Pronchery }
595*e7be843bSPierre Pronchery if (SSL_get_stream_type(stream) == SSL_STREAM_TYPE_BIDI) {
596*e7be843bSPierre Pronchery /* bidi that is the id where we have to send the response */
597*e7be843bSPierre Pronchery if (h3ssl->id_bidi != UINT64_MAX) {
598*e7be843bSPierre Pronchery set_id_status(h3ssl->id_bidi, TOBEREMOVED, h3ssl);
599*e7be843bSPierre Pronchery has_ids_to_remove++;
600*e7be843bSPierre Pronchery }
601*e7be843bSPierre Pronchery h3ssl->id_bidi = new_id;
602*e7be843bSPierre Pronchery reuse_h3ssl(h3ssl);
603*e7be843bSPierre Pronchery h3ssl->restart = 1;
604*e7be843bSPierre Pronchery } else {
605*e7be843bSPierre Pronchery set_id_status(new_id, CLIENTUNIOPEN, h3ssl);
606*e7be843bSPierre Pronchery }
607*e7be843bSPierre Pronchery
608*e7be843bSPierre Pronchery r = quic_server_read(h3conn, stream, new_id, h3ssl);
609*e7be843bSPierre Pronchery if (r == -1) {
610*e7be843bSPierre Pronchery ret = -1;
611*e7be843bSPierre Pronchery goto err;
612*e7be843bSPierre Pronchery }
613*e7be843bSPierre Pronchery if (r == 1)
614*e7be843bSPierre Pronchery hassomething++;
615*e7be843bSPierre Pronchery
616*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_ISB)
617*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_ISB;
618*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_ISU)
619*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_ISU;
620*e7be843bSPierre Pronchery }
621*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_OSB) {
622*e7be843bSPierre Pronchery /* Create new streams when allowed */
623*e7be843bSPierre Pronchery /* at least one bidi */
624*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_OSB;
625*e7be843bSPierre Pronchery printf("Create bidi?\n");
626*e7be843bSPierre Pronchery }
627*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_OSU) {
628*e7be843bSPierre Pronchery /* at least one uni */
629*e7be843bSPierre Pronchery /* we have 4 streams from the client 2, 6 , 10 and 0 */
630*e7be843bSPierre Pronchery /* need 3 streams to the client */
631*e7be843bSPierre Pronchery printf("Create uni?\n");
632*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_OSU;
633*e7be843bSPierre Pronchery if (!h3ssl->has_uni) {
634*e7be843bSPierre Pronchery printf("Create uni\n");
635*e7be843bSPierre Pronchery ret = quic_server_h3streams(h3conn, h3ssl);
636*e7be843bSPierre Pronchery if (ret == -1) {
637*e7be843bSPierre Pronchery fprintf(stderr, "quic_server_h3streams failed!\n");
638*e7be843bSPierre Pronchery goto err;
639*e7be843bSPierre Pronchery }
640*e7be843bSPierre Pronchery h3ssl->has_uni = 1;
641*e7be843bSPierre Pronchery hassomething++;
642*e7be843bSPierre Pronchery }
643*e7be843bSPierre Pronchery }
644*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_EC) {
645*e7be843bSPierre Pronchery /* the connection begins terminating */
646*e7be843bSPierre Pronchery printf("Connection terminating\n");
647*e7be843bSPierre Pronchery printf("Connection terminating restart %d\n", h3ssl->restart);
648*e7be843bSPierre Pronchery if (!h3ssl->close_done) {
649*e7be843bSPierre Pronchery h3ssl->close_done = 1;
650*e7be843bSPierre Pronchery } else {
651*e7be843bSPierre Pronchery h3ssl->done = 1;
652*e7be843bSPierre Pronchery }
653*e7be843bSPierre Pronchery hassomething++;
654*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_EC;
655*e7be843bSPierre Pronchery }
656*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_ECD) {
657*e7be843bSPierre Pronchery /* the connection is terminated */
658*e7be843bSPierre Pronchery printf("Connection terminated\n");
659*e7be843bSPierre Pronchery h3ssl->done = 1;
660*e7be843bSPierre Pronchery hassomething++;
661*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_ECD;
662*e7be843bSPierre Pronchery }
663*e7be843bSPierre Pronchery
664*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_R) {
665*e7be843bSPierre Pronchery /* try to read */
666*e7be843bSPierre Pronchery uint64_t id = UINT64_MAX;
667*e7be843bSPierre Pronchery int r;
668*e7be843bSPierre Pronchery
669*e7be843bSPierre Pronchery /* get the id, well the connection has no id... */
670*e7be843bSPierre Pronchery id = SSL_get_stream_id(item->desc.value.ssl);
671*e7be843bSPierre Pronchery printf("revent READ on %llu\n", (unsigned long long)id);
672*e7be843bSPierre Pronchery r = quic_server_read(h3conn, s, id, h3ssl);
673*e7be843bSPierre Pronchery if (r == 0) {
674*e7be843bSPierre Pronchery uint8_t msg[1];
675*e7be843bSPierre Pronchery size_t l = sizeof(msg);
676*e7be843bSPierre Pronchery
677*e7be843bSPierre Pronchery /* check that the other side is closed */
678*e7be843bSPierre Pronchery r = SSL_read(s, msg, l);
679*e7be843bSPierre Pronchery printf("SSL_read tells %d\n", r);
680*e7be843bSPierre Pronchery if (r > 0) {
681*e7be843bSPierre Pronchery ret = -1;
682*e7be843bSPierre Pronchery goto err;
683*e7be843bSPierre Pronchery }
684*e7be843bSPierre Pronchery r = SSL_get_error(s, r);
685*e7be843bSPierre Pronchery if (r != SSL_ERROR_ZERO_RETURN) {
686*e7be843bSPierre Pronchery ret = -1;
687*e7be843bSPierre Pronchery goto err;
688*e7be843bSPierre Pronchery }
689*e7be843bSPierre Pronchery set_id_status(id, TOBEREMOVED, h3ssl);
690*e7be843bSPierre Pronchery has_ids_to_remove++;
691*e7be843bSPierre Pronchery continue;
692*e7be843bSPierre Pronchery }
693*e7be843bSPierre Pronchery if (r == -1) {
694*e7be843bSPierre Pronchery ret = -1;
695*e7be843bSPierre Pronchery goto err;
696*e7be843bSPierre Pronchery }
697*e7be843bSPierre Pronchery hassomething++;
698*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_R;
699*e7be843bSPierre Pronchery }
700*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_ER) {
701*e7be843bSPierre Pronchery /* mark it closed */
702*e7be843bSPierre Pronchery uint64_t id = UINT64_MAX;
703*e7be843bSPierre Pronchery int status;
704*e7be843bSPierre Pronchery
705*e7be843bSPierre Pronchery id = SSL_get_stream_id(item->desc.value.ssl);
706*e7be843bSPierre Pronchery status = get_id_status(id, h3ssl);
707*e7be843bSPierre Pronchery
708*e7be843bSPierre Pronchery printf("revent exception READ on %llu\n", (unsigned long long)id);
709*e7be843bSPierre Pronchery if (status & CLIENTUNIOPEN) {
710*e7be843bSPierre Pronchery set_id_status(id, CLIENTCLOSED, h3ssl);
711*e7be843bSPierre Pronchery hassomething++;
712*e7be843bSPierre Pronchery }
713*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_ER;
714*e7be843bSPierre Pronchery }
715*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_W) {
716*e7be843bSPierre Pronchery /* we ignore those for the moment */
717*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_W;
718*e7be843bSPierre Pronchery }
719*e7be843bSPierre Pronchery if (item->revents & SSL_POLL_EVENT_EW) {
720*e7be843bSPierre Pronchery /* write part received a STOP_SENDING */
721*e7be843bSPierre Pronchery uint64_t id = UINT64_MAX;
722*e7be843bSPierre Pronchery int status;
723*e7be843bSPierre Pronchery
724*e7be843bSPierre Pronchery id = SSL_get_stream_id(item->desc.value.ssl);
725*e7be843bSPierre Pronchery status = get_id_status(id, h3ssl);
726*e7be843bSPierre Pronchery
727*e7be843bSPierre Pronchery if (status & SERVERCLOSED) {
728*e7be843bSPierre Pronchery printf("both sides closed on %llu\n", (unsigned long long)id);
729*e7be843bSPierre Pronchery set_id_status(id, TOBEREMOVED, h3ssl);
730*e7be843bSPierre Pronchery has_ids_to_remove++;
731*e7be843bSPierre Pronchery hassomething++;
732*e7be843bSPierre Pronchery }
733*e7be843bSPierre Pronchery processed_event = processed_event | SSL_POLL_EVENT_EW;
734*e7be843bSPierre Pronchery }
735*e7be843bSPierre Pronchery if (item->revents != processed_event) {
736*e7be843bSPierre Pronchery /* Figure out ??? */
737*e7be843bSPierre Pronchery uint64_t id = UINT64_MAX;
738*e7be843bSPierre Pronchery
739*e7be843bSPierre Pronchery id = SSL_get_stream_id(item->desc.value.ssl);
740*e7be843bSPierre Pronchery printf("revent %llu (%d) on %llu NOT PROCESSED!\n",
741*e7be843bSPierre Pronchery (unsigned long long)item->revents, SSL_POLL_EVENT_W,
742*e7be843bSPierre Pronchery (unsigned long long)id);
743*e7be843bSPierre Pronchery }
744*e7be843bSPierre Pronchery }
745*e7be843bSPierre Pronchery ret = hassomething;
746*e7be843bSPierre Pronchery err:
747*e7be843bSPierre Pronchery if (has_ids_to_remove)
748*e7be843bSPierre Pronchery remove_marked_ids(h3ssl);
749*e7be843bSPierre Pronchery return ret;
750*e7be843bSPierre Pronchery }
751*e7be843bSPierre Pronchery
handle_events_from_ids(struct h3ssl * h3ssl)752*e7be843bSPierre Pronchery static void handle_events_from_ids(struct h3ssl *h3ssl)
753*e7be843bSPierre Pronchery {
754*e7be843bSPierre Pronchery struct ssl_id *ssl_ids = h3ssl->ssl_ids;
755*e7be843bSPierre Pronchery int i;
756*e7be843bSPierre Pronchery
757*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
758*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
759*e7be843bSPierre Pronchery if (ssl_ids[i].s != NULL &&
760*e7be843bSPierre Pronchery (ssl_ids[i].status & ISCONNECTION || ssl_ids[i].status & ISLISTENER)) {
761*e7be843bSPierre Pronchery if (SSL_handle_events(ssl_ids[i].s))
762*e7be843bSPierre Pronchery ERR_print_errors_fp(stderr);
763*e7be843bSPierre Pronchery }
764*e7be843bSPierre Pronchery }
765*e7be843bSPierre Pronchery }
766*e7be843bSPierre Pronchery
get_file_length(struct h3ssl * h3ssl)767*e7be843bSPierre Pronchery static size_t get_file_length(struct h3ssl *h3ssl)
768*e7be843bSPierre Pronchery {
769*e7be843bSPierre Pronchery char filename[PATH_MAX];
770*e7be843bSPierre Pronchery struct stat st;
771*e7be843bSPierre Pronchery
772*e7be843bSPierre Pronchery memset(filename, 0, PATH_MAX);
773*e7be843bSPierre Pronchery if (h3ssl->fileprefix != NULL)
774*e7be843bSPierre Pronchery strcat(filename, h3ssl->fileprefix);
775*e7be843bSPierre Pronchery strcat(filename, h3ssl->url);
776*e7be843bSPierre Pronchery
777*e7be843bSPierre Pronchery if (strcmp(h3ssl->url, "big") == 0) {
778*e7be843bSPierre Pronchery printf("big!!!\n");
779*e7be843bSPierre Pronchery return (size_t)INT_MAX;
780*e7be843bSPierre Pronchery }
781*e7be843bSPierre Pronchery if (stat(filename, &st) == 0) {
782*e7be843bSPierre Pronchery /* Only process regular files */
783*e7be843bSPierre Pronchery if (S_ISREG(st.st_mode)) {
784*e7be843bSPierre Pronchery printf("get_file_length %s %lld\n", filename, (unsigned long long) st.st_size);
785*e7be843bSPierre Pronchery return (size_t)st.st_size;
786*e7be843bSPierre Pronchery }
787*e7be843bSPierre Pronchery }
788*e7be843bSPierre Pronchery printf("Can't get_file_length %s\n", filename);
789*e7be843bSPierre Pronchery return 0;
790*e7be843bSPierre Pronchery }
791*e7be843bSPierre Pronchery
get_file_data(struct h3ssl * h3ssl)792*e7be843bSPierre Pronchery static char *get_file_data(struct h3ssl *h3ssl)
793*e7be843bSPierre Pronchery {
794*e7be843bSPierre Pronchery char filename[PATH_MAX];
795*e7be843bSPierre Pronchery size_t size = get_file_length(h3ssl);
796*e7be843bSPierre Pronchery char *res;
797*e7be843bSPierre Pronchery int fd;
798*e7be843bSPierre Pronchery
799*e7be843bSPierre Pronchery if (size == 0)
800*e7be843bSPierre Pronchery return NULL;
801*e7be843bSPierre Pronchery
802*e7be843bSPierre Pronchery memset(filename, 0, PATH_MAX);
803*e7be843bSPierre Pronchery if (h3ssl->fileprefix != NULL)
804*e7be843bSPierre Pronchery strcat(filename, h3ssl->fileprefix);
805*e7be843bSPierre Pronchery strcat(filename, h3ssl->url);
806*e7be843bSPierre Pronchery
807*e7be843bSPierre Pronchery res = malloc(size+1);
808*e7be843bSPierre Pronchery res[size] = '\0';
809*e7be843bSPierre Pronchery fd = open(filename, O_RDONLY);
810*e7be843bSPierre Pronchery if (read(fd, res, size) == -1) {
811*e7be843bSPierre Pronchery close(fd);
812*e7be843bSPierre Pronchery free(res);
813*e7be843bSPierre Pronchery return NULL;
814*e7be843bSPierre Pronchery }
815*e7be843bSPierre Pronchery close(fd);
816*e7be843bSPierre Pronchery printf("read from %s : %zu\n", filename, size);
817*e7be843bSPierre Pronchery return res;
818*e7be843bSPierre Pronchery }
819*e7be843bSPierre Pronchery
step_read_data(nghttp3_conn * conn,int64_t stream_id,nghttp3_vec * vec,size_t veccnt,uint32_t * pflags,void * user_data,void * stream_user_data)820*e7be843bSPierre Pronchery static nghttp3_ssize step_read_data(nghttp3_conn *conn, int64_t stream_id,
821*e7be843bSPierre Pronchery nghttp3_vec *vec, size_t veccnt,
822*e7be843bSPierre Pronchery uint32_t *pflags, void *user_data,
823*e7be843bSPierre Pronchery void *stream_user_data)
824*e7be843bSPierre Pronchery {
825*e7be843bSPierre Pronchery struct h3ssl *h3ssl = (struct h3ssl *)user_data;
826*e7be843bSPierre Pronchery
827*e7be843bSPierre Pronchery if (h3ssl->datadone) {
828*e7be843bSPierre Pronchery *pflags = NGHTTP3_DATA_FLAG_EOF;
829*e7be843bSPierre Pronchery return 0;
830*e7be843bSPierre Pronchery }
831*e7be843bSPierre Pronchery /* send the data */
832*e7be843bSPierre Pronchery printf("step_read_data for %s %zu\n", h3ssl->url, h3ssl->ldata);
833*e7be843bSPierre Pronchery if (h3ssl->ldata <= 4096) {
834*e7be843bSPierre Pronchery vec[0].base = &(h3ssl->ptr_data[h3ssl->offset_data]);
835*e7be843bSPierre Pronchery vec[0].len = h3ssl->ldata;
836*e7be843bSPierre Pronchery h3ssl->datadone++;
837*e7be843bSPierre Pronchery *pflags = NGHTTP3_DATA_FLAG_EOF;
838*e7be843bSPierre Pronchery } else {
839*e7be843bSPierre Pronchery vec[0].base = &(h3ssl->ptr_data[h3ssl->offset_data]);
840*e7be843bSPierre Pronchery vec[0].len = 4096;
841*e7be843bSPierre Pronchery if (h3ssl->ldata == INT_MAX) {
842*e7be843bSPierre Pronchery printf("big = endless!\n");
843*e7be843bSPierre Pronchery } else {
844*e7be843bSPierre Pronchery h3ssl->offset_data = h3ssl->offset_data + 4096;
845*e7be843bSPierre Pronchery h3ssl->ldata = h3ssl->ldata - 4096;
846*e7be843bSPierre Pronchery }
847*e7be843bSPierre Pronchery }
848*e7be843bSPierre Pronchery
849*e7be843bSPierre Pronchery return 1;
850*e7be843bSPierre Pronchery }
851*e7be843bSPierre Pronchery
quic_server_write(struct h3ssl * h3ssl,uint64_t streamid,uint8_t * buff,size_t len,uint64_t flags,size_t * written)852*e7be843bSPierre Pronchery static int quic_server_write(struct h3ssl *h3ssl, uint64_t streamid,
853*e7be843bSPierre Pronchery uint8_t *buff, size_t len, uint64_t flags,
854*e7be843bSPierre Pronchery size_t *written)
855*e7be843bSPierre Pronchery {
856*e7be843bSPierre Pronchery struct ssl_id *ssl_ids;
857*e7be843bSPierre Pronchery int i;
858*e7be843bSPierre Pronchery
859*e7be843bSPierre Pronchery ssl_ids = h3ssl->ssl_ids;
860*e7be843bSPierre Pronchery for (i = 0; i < MAXSSL_IDS; i++) {
861*e7be843bSPierre Pronchery if (ssl_ids[i].id == streamid) {
862*e7be843bSPierre Pronchery if (!SSL_write_ex2(ssl_ids[i].s, buff, len, flags, written) ||
863*e7be843bSPierre Pronchery *written != len) {
864*e7be843bSPierre Pronchery fprintf(stderr, "couldn't write on connection\n");
865*e7be843bSPierre Pronchery ERR_print_errors_fp(stderr);
866*e7be843bSPierre Pronchery return 0;
867*e7be843bSPierre Pronchery }
868*e7be843bSPierre Pronchery printf("written %lld on %lld flags %lld\n", (unsigned long long)len,
869*e7be843bSPierre Pronchery (unsigned long long)streamid, (unsigned long long)flags);
870*e7be843bSPierre Pronchery return 1;
871*e7be843bSPierre Pronchery }
872*e7be843bSPierre Pronchery }
873*e7be843bSPierre Pronchery printf("quic_server_write %lld on %lld (NOT FOUND!)\n", (unsigned long long)len,
874*e7be843bSPierre Pronchery (unsigned long long)streamid);
875*e7be843bSPierre Pronchery return 0;
876*e7be843bSPierre Pronchery }
877*e7be843bSPierre Pronchery
878*e7be843bSPierre Pronchery #define OSSL_NELEM(x) (sizeof(x) / sizeof((x)[0]))
879*e7be843bSPierre Pronchery
880*e7be843bSPierre Pronchery /*
881*e7be843bSPierre Pronchery * This is a basic demo of QUIC server functionality in which one connection at
882*e7be843bSPierre Pronchery * a time is accepted in a blocking loop.
883*e7be843bSPierre Pronchery */
884*e7be843bSPierre Pronchery
885*e7be843bSPierre Pronchery /* ALPN string for TLS handshake. We pretent h3-29 and h3 */
886*e7be843bSPierre Pronchery static const unsigned char alpn_ossltest[] = { 5, 'h', '3', '-', '2',
887*e7be843bSPierre Pronchery '9', 2, 'h', '3' };
888*e7be843bSPierre Pronchery
889*e7be843bSPierre Pronchery /*
890*e7be843bSPierre Pronchery * This callback validates and negotiates the desired ALPN on the server side.
891*e7be843bSPierre Pronchery */
select_alpn(SSL * ssl,const unsigned char ** out,unsigned char * out_len,const unsigned char * in,unsigned int in_len,void * arg)892*e7be843bSPierre Pronchery static int select_alpn(SSL *ssl, const unsigned char **out,
893*e7be843bSPierre Pronchery unsigned char *out_len, const unsigned char *in,
894*e7be843bSPierre Pronchery unsigned int in_len, void *arg)
895*e7be843bSPierre Pronchery {
896*e7be843bSPierre Pronchery if (SSL_select_next_proto((unsigned char **)out, out_len, alpn_ossltest,
897*e7be843bSPierre Pronchery sizeof(alpn_ossltest), in,
898*e7be843bSPierre Pronchery in_len) != OPENSSL_NPN_NEGOTIATED)
899*e7be843bSPierre Pronchery return SSL_TLSEXT_ERR_ALERT_FATAL;
900*e7be843bSPierre Pronchery
901*e7be843bSPierre Pronchery return SSL_TLSEXT_ERR_OK;
902*e7be843bSPierre Pronchery }
903*e7be843bSPierre Pronchery
904*e7be843bSPierre Pronchery /* Create SSL_CTX. */
create_ctx(const char * cert_path,const char * key_path)905*e7be843bSPierre Pronchery static SSL_CTX *create_ctx(const char *cert_path, const char *key_path)
906*e7be843bSPierre Pronchery {
907*e7be843bSPierre Pronchery SSL_CTX *ctx;
908*e7be843bSPierre Pronchery
909*e7be843bSPierre Pronchery ctx = SSL_CTX_new(OSSL_QUIC_server_method());
910*e7be843bSPierre Pronchery if (ctx == NULL)
911*e7be843bSPierre Pronchery goto err;
912*e7be843bSPierre Pronchery
913*e7be843bSPierre Pronchery /* Load certificate and corresponding private key. */
914*e7be843bSPierre Pronchery if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) <= 0) {
915*e7be843bSPierre Pronchery fprintf(stderr, "couldn't load certificate file: %s\n", cert_path);
916*e7be843bSPierre Pronchery goto err;
917*e7be843bSPierre Pronchery }
918*e7be843bSPierre Pronchery
919*e7be843bSPierre Pronchery if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) <= 0) {
920*e7be843bSPierre Pronchery fprintf(stderr, "couldn't load key file: %s\n", key_path);
921*e7be843bSPierre Pronchery goto err;
922*e7be843bSPierre Pronchery }
923*e7be843bSPierre Pronchery
924*e7be843bSPierre Pronchery if (!SSL_CTX_check_private_key(ctx)) {
925*e7be843bSPierre Pronchery fprintf(stderr, "private key check failed\n");
926*e7be843bSPierre Pronchery goto err;
927*e7be843bSPierre Pronchery }
928*e7be843bSPierre Pronchery
929*e7be843bSPierre Pronchery /* Setup ALPN negotiation callback. */
930*e7be843bSPierre Pronchery SSL_CTX_set_alpn_select_cb(ctx, select_alpn, NULL);
931*e7be843bSPierre Pronchery return ctx;
932*e7be843bSPierre Pronchery
933*e7be843bSPierre Pronchery err:
934*e7be843bSPierre Pronchery SSL_CTX_free(ctx);
935*e7be843bSPierre Pronchery return NULL;
936*e7be843bSPierre Pronchery }
937*e7be843bSPierre Pronchery
938*e7be843bSPierre Pronchery /* Create UDP socket using given port. */
create_socket(uint16_t port)939*e7be843bSPierre Pronchery static int create_socket(uint16_t port)
940*e7be843bSPierre Pronchery {
941*e7be843bSPierre Pronchery int fd = -1;
942*e7be843bSPierre Pronchery struct sockaddr_in sa = {0};
943*e7be843bSPierre Pronchery
944*e7be843bSPierre Pronchery if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
945*e7be843bSPierre Pronchery fprintf(stderr, "cannot create socket");
946*e7be843bSPierre Pronchery goto err;
947*e7be843bSPierre Pronchery }
948*e7be843bSPierre Pronchery
949*e7be843bSPierre Pronchery sa.sin_family = AF_INET;
950*e7be843bSPierre Pronchery sa.sin_port = htons(port);
951*e7be843bSPierre Pronchery
952*e7be843bSPierre Pronchery if (bind(fd, (const struct sockaddr *)&sa, sizeof(sa)) < 0) {
953*e7be843bSPierre Pronchery fprintf(stderr, "cannot bind to %u\n", port);
954*e7be843bSPierre Pronchery goto err;
955*e7be843bSPierre Pronchery }
956*e7be843bSPierre Pronchery
957*e7be843bSPierre Pronchery return fd;
958*e7be843bSPierre Pronchery
959*e7be843bSPierre Pronchery err:
960*e7be843bSPierre Pronchery if (fd >= 0)
961*e7be843bSPierre Pronchery BIO_closesocket(fd);
962*e7be843bSPierre Pronchery
963*e7be843bSPierre Pronchery return -1;
964*e7be843bSPierre Pronchery }
965*e7be843bSPierre Pronchery
966*e7be843bSPierre Pronchery /* Copied from demos/guide/quic-server-non-block.c */
967*e7be843bSPierre Pronchery /**
968*e7be843bSPierre Pronchery * @brief Waits for activity on the SSL socket, either for reading or writing.
969*e7be843bSPierre Pronchery *
970*e7be843bSPierre Pronchery * This function monitors the underlying file descriptor of the given SSL
971*e7be843bSPierre Pronchery * connection to determine when it is ready for reading or writing, or both.
972*e7be843bSPierre Pronchery * It uses the select function to wait until the socket is either readable
973*e7be843bSPierre Pronchery * or writable, depending on what the SSL connection requires.
974*e7be843bSPierre Pronchery *
975*e7be843bSPierre Pronchery * @param ssl A pointer to the SSL object representing the connection.
976*e7be843bSPierre Pronchery *
977*e7be843bSPierre Pronchery * @note This function blocks until there is activity on the socket. In a real
978*e7be843bSPierre Pronchery * application, you might want to perform other tasks while waiting, such as
979*e7be843bSPierre Pronchery * updating a GUI or handling other connections.
980*e7be843bSPierre Pronchery *
981*e7be843bSPierre Pronchery * @note This function uses select for simplicity and portability. Depending
982*e7be843bSPierre Pronchery * on your application's requirements, you might consider using other
983*e7be843bSPierre Pronchery * mechanisms like poll or epoll for handling multiple file descriptors.
984*e7be843bSPierre Pronchery */
wait_for_activity(SSL * ssl)985*e7be843bSPierre Pronchery static int wait_for_activity(SSL *ssl)
986*e7be843bSPierre Pronchery {
987*e7be843bSPierre Pronchery int sock, isinfinite;
988*e7be843bSPierre Pronchery fd_set read_fd, write_fd;
989*e7be843bSPierre Pronchery struct timeval tv;
990*e7be843bSPierre Pronchery struct timeval *tvp = NULL;
991*e7be843bSPierre Pronchery
992*e7be843bSPierre Pronchery /* Get hold of the underlying file descriptor for the socket */
993*e7be843bSPierre Pronchery if ((sock = SSL_get_fd(ssl)) == -1) {
994*e7be843bSPierre Pronchery fprintf(stderr, "Unable to get file descriptor");
995*e7be843bSPierre Pronchery return -1;
996*e7be843bSPierre Pronchery }
997*e7be843bSPierre Pronchery
998*e7be843bSPierre Pronchery /* Initialize the fd_set structure */
999*e7be843bSPierre Pronchery FD_ZERO(&read_fd);
1000*e7be843bSPierre Pronchery FD_ZERO(&write_fd);
1001*e7be843bSPierre Pronchery
1002*e7be843bSPierre Pronchery /*
1003*e7be843bSPierre Pronchery * Determine if we would like to write to the socket, read from it, or both.
1004*e7be843bSPierre Pronchery */
1005*e7be843bSPierre Pronchery if (SSL_net_write_desired(ssl))
1006*e7be843bSPierre Pronchery FD_SET(sock, &write_fd);
1007*e7be843bSPierre Pronchery if (SSL_net_read_desired(ssl))
1008*e7be843bSPierre Pronchery FD_SET(sock, &read_fd);
1009*e7be843bSPierre Pronchery
1010*e7be843bSPierre Pronchery /* Add the socket file descriptor to the fd_set */
1011*e7be843bSPierre Pronchery FD_SET(sock, &read_fd);
1012*e7be843bSPierre Pronchery
1013*e7be843bSPierre Pronchery /*
1014*e7be843bSPierre Pronchery * Find out when OpenSSL would next like to be called, regardless of
1015*e7be843bSPierre Pronchery * whether the state of the underlying socket has changed or not.
1016*e7be843bSPierre Pronchery */
1017*e7be843bSPierre Pronchery if (SSL_get_event_timeout(ssl, &tv, &isinfinite) && !isinfinite)
1018*e7be843bSPierre Pronchery tvp = &tv;
1019*e7be843bSPierre Pronchery
1020*e7be843bSPierre Pronchery /*
1021*e7be843bSPierre Pronchery * Wait until the socket is writeable or readable. We use select here
1022*e7be843bSPierre Pronchery * for the sake of simplicity and portability, but you could equally use
1023*e7be843bSPierre Pronchery * poll/epoll or similar functions
1024*e7be843bSPierre Pronchery *
1025*e7be843bSPierre Pronchery * NOTE: For the purposes of this demonstration code this effectively
1026*e7be843bSPierre Pronchery * makes this demo block until it has something more useful to do. In a
1027*e7be843bSPierre Pronchery * real application you probably want to go and do other work here (e.g.
1028*e7be843bSPierre Pronchery * update a GUI, or service other connections).
1029*e7be843bSPierre Pronchery *
1030*e7be843bSPierre Pronchery * Let's say for example that you want to update the progress counter on
1031*e7be843bSPierre Pronchery * a GUI every 100ms. One way to do that would be to use the timeout in
1032*e7be843bSPierre Pronchery * the last parameter to "select" below. If the tvp value is greater
1033*e7be843bSPierre Pronchery * than 100ms then use 100ms instead. Then, when select returns, you
1034*e7be843bSPierre Pronchery * check if it did so because of activity on the file descriptors or
1035*e7be843bSPierre Pronchery * because of the timeout. If the 100ms GUI timeout has expired but the
1036*e7be843bSPierre Pronchery * tvp timeout has not then go and update the GUI and then restart the
1037*e7be843bSPierre Pronchery * "select" (with updated timeouts).
1038*e7be843bSPierre Pronchery */
1039*e7be843bSPierre Pronchery
1040*e7be843bSPierre Pronchery return (select(sock + 1, &read_fd, &write_fd, NULL, tvp));
1041*e7be843bSPierre Pronchery }
1042*e7be843bSPierre Pronchery
1043*e7be843bSPierre Pronchery /* Main loop for server to accept QUIC connections. */
run_quic_server(SSL_CTX * ctx,int fd)1044*e7be843bSPierre Pronchery static int run_quic_server(SSL_CTX *ctx, int fd)
1045*e7be843bSPierre Pronchery {
1046*e7be843bSPierre Pronchery int ok = 0;
1047*e7be843bSPierre Pronchery int hassomething = 0;
1048*e7be843bSPierre Pronchery SSL *listener = NULL;
1049*e7be843bSPierre Pronchery nghttp3_conn *h3conn = NULL;
1050*e7be843bSPierre Pronchery struct h3ssl h3ssl;
1051*e7be843bSPierre Pronchery SSL *ssl;
1052*e7be843bSPierre Pronchery char *fileprefix = getenv("FILEPREFIX");
1053*e7be843bSPierre Pronchery
1054*e7be843bSPierre Pronchery /* Create a new QUIC listener. */
1055*e7be843bSPierre Pronchery if ((listener = SSL_new_listener(ctx, 0)) == NULL)
1056*e7be843bSPierre Pronchery goto err;
1057*e7be843bSPierre Pronchery
1058*e7be843bSPierre Pronchery /* Provide the listener with our UDP socket. */
1059*e7be843bSPierre Pronchery if (!SSL_set_fd(listener, fd))
1060*e7be843bSPierre Pronchery goto err;
1061*e7be843bSPierre Pronchery
1062*e7be843bSPierre Pronchery /* Begin listening. */
1063*e7be843bSPierre Pronchery if (!SSL_listen(listener))
1064*e7be843bSPierre Pronchery goto err;
1065*e7be843bSPierre Pronchery
1066*e7be843bSPierre Pronchery /*
1067*e7be843bSPierre Pronchery * Listeners, and other QUIC objects, default to operating in blocking mode.
1068*e7be843bSPierre Pronchery * The configured behaviour is inherited by child objects.
1069*e7be843bSPierre Pronchery * Make sure we won't block as we use select().
1070*e7be843bSPierre Pronchery */
1071*e7be843bSPierre Pronchery if (!SSL_set_blocking_mode(listener, 0))
1072*e7be843bSPierre Pronchery goto err;
1073*e7be843bSPierre Pronchery
1074*e7be843bSPierre Pronchery /* Setup callbacks. */
1075*e7be843bSPierre Pronchery callbacks.recv_header = on_recv_header;
1076*e7be843bSPierre Pronchery callbacks.end_headers = on_end_headers;
1077*e7be843bSPierre Pronchery callbacks.recv_data = on_recv_data;
1078*e7be843bSPierre Pronchery callbacks.end_stream = on_end_stream;
1079*e7be843bSPierre Pronchery
1080*e7be843bSPierre Pronchery /* mem default */
1081*e7be843bSPierre Pronchery mem = nghttp3_mem_default();
1082*e7be843bSPierre Pronchery
1083*e7be843bSPierre Pronchery for (;;) {
1084*e7be843bSPierre Pronchery nghttp3_nv resp[10];
1085*e7be843bSPierre Pronchery size_t num_nv;
1086*e7be843bSPierre Pronchery nghttp3_data_reader dr;
1087*e7be843bSPierre Pronchery int ret;
1088*e7be843bSPierre Pronchery int numtimeout;
1089*e7be843bSPierre Pronchery char slength[22];
1090*e7be843bSPierre Pronchery int hasnothing;
1091*e7be843bSPierre Pronchery
1092*e7be843bSPierre Pronchery init_ids(&h3ssl);
1093*e7be843bSPierre Pronchery h3ssl.fileprefix = fileprefix;
1094*e7be843bSPierre Pronchery printf("listener: %p\n", (void *)listener);
1095*e7be843bSPierre Pronchery add_ids_listener(listener, &h3ssl);
1096*e7be843bSPierre Pronchery
1097*e7be843bSPierre Pronchery if (!hassomething) {
1098*e7be843bSPierre Pronchery printf("waiting on socket\n");
1099*e7be843bSPierre Pronchery fflush(stdout);
1100*e7be843bSPierre Pronchery ret = wait_for_activity(listener);
1101*e7be843bSPierre Pronchery if (ret == -1) {
1102*e7be843bSPierre Pronchery fprintf(stderr, "wait_for_activity failed!\n");
1103*e7be843bSPierre Pronchery goto err;
1104*e7be843bSPierre Pronchery }
1105*e7be843bSPierre Pronchery }
1106*e7be843bSPierre Pronchery /*
1107*e7be843bSPierre Pronchery * Service the connection. In a real application this would be done
1108*e7be843bSPierre Pronchery * concurrently. In this demonstration program a single connection is
1109*e7be843bSPierre Pronchery * accepted and serviced at a time.
1110*e7be843bSPierre Pronchery */
1111*e7be843bSPierre Pronchery newconn:
1112*e7be843bSPierre Pronchery
1113*e7be843bSPierre Pronchery printf("process_server starting...\n");
1114*e7be843bSPierre Pronchery fflush(stdout);
1115*e7be843bSPierre Pronchery
1116*e7be843bSPierre Pronchery /* wait until we have received the headers */
1117*e7be843bSPierre Pronchery restart:
1118*e7be843bSPierre Pronchery numtimeout = 0;
1119*e7be843bSPierre Pronchery num_nv = 0;
1120*e7be843bSPierre Pronchery while (!h3ssl.end_headers_received) {
1121*e7be843bSPierre Pronchery if (!hassomething) {
1122*e7be843bSPierre Pronchery if (wait_for_activity(listener) == 0) {
1123*e7be843bSPierre Pronchery printf("waiting for end_headers_received timeout %d\n", numtimeout);
1124*e7be843bSPierre Pronchery numtimeout++;
1125*e7be843bSPierre Pronchery if (numtimeout == 25)
1126*e7be843bSPierre Pronchery goto err;
1127*e7be843bSPierre Pronchery }
1128*e7be843bSPierre Pronchery handle_events_from_ids(&h3ssl);
1129*e7be843bSPierre Pronchery }
1130*e7be843bSPierre Pronchery hassomething = read_from_ssl_ids(&h3conn, &h3ssl);
1131*e7be843bSPierre Pronchery if (hassomething == -1) {
1132*e7be843bSPierre Pronchery fprintf(stderr, "read_from_ssl_ids hassomething failed\n");
1133*e7be843bSPierre Pronchery goto err;
1134*e7be843bSPierre Pronchery } else if (hassomething == 0) {
1135*e7be843bSPierre Pronchery printf("read_from_ssl_ids hassomething nothing...\n");
1136*e7be843bSPierre Pronchery } else {
1137*e7be843bSPierre Pronchery numtimeout = 0;
1138*e7be843bSPierre Pronchery printf("read_from_ssl_ids hassomething %d...\n", hassomething);
1139*e7be843bSPierre Pronchery if (h3ssl.close_done) {
1140*e7be843bSPierre Pronchery /* Other side has closed */
1141*e7be843bSPierre Pronchery break;
1142*e7be843bSPierre Pronchery }
1143*e7be843bSPierre Pronchery h3ssl.restart = 0;
1144*e7be843bSPierre Pronchery }
1145*e7be843bSPierre Pronchery }
1146*e7be843bSPierre Pronchery if (h3ssl.close_done) {
1147*e7be843bSPierre Pronchery printf("Other side close without request\n");
1148*e7be843bSPierre Pronchery goto wait_close;
1149*e7be843bSPierre Pronchery }
1150*e7be843bSPierre Pronchery printf("end_headers_received!!!\n");
1151*e7be843bSPierre Pronchery if (!h3ssl.has_uni) {
1152*e7be843bSPierre Pronchery /* time to create those otherwise we can't push anything to the client */
1153*e7be843bSPierre Pronchery printf("Create uni\n");
1154*e7be843bSPierre Pronchery if (quic_server_h3streams(h3conn, &h3ssl) == -1) {
1155*e7be843bSPierre Pronchery fprintf(stderr, "quic_server_h3streams failed!\n");
1156*e7be843bSPierre Pronchery goto err;
1157*e7be843bSPierre Pronchery }
1158*e7be843bSPierre Pronchery h3ssl.has_uni = 1;
1159*e7be843bSPierre Pronchery }
1160*e7be843bSPierre Pronchery
1161*e7be843bSPierre Pronchery /* we have receive the request build the response and send it */
1162*e7be843bSPierre Pronchery /* XXX add MAKE_NV("connection", "close"), to resp[] and recheck */
1163*e7be843bSPierre Pronchery make_nv(&resp[num_nv++], ":status", "200");
1164*e7be843bSPierre Pronchery h3ssl.ldata = get_file_length(&h3ssl);
1165*e7be843bSPierre Pronchery if (h3ssl.ldata == 0) {
1166*e7be843bSPierre Pronchery /* We don't find the file: use default test string */
1167*e7be843bSPierre Pronchery h3ssl.ptr_data = nulldata;
1168*e7be843bSPierre Pronchery h3ssl.ldata = nulldata_sz;
1169*e7be843bSPierre Pronchery sprintf(slength, "%zu", h3ssl.ldata);
1170*e7be843bSPierre Pronchery /* content-type: text/html */
1171*e7be843bSPierre Pronchery make_nv(&resp[num_nv++], "content-type", "text/html");
1172*e7be843bSPierre Pronchery } else if (h3ssl.ldata == INT_MAX) {
1173*e7be843bSPierre Pronchery /* endless file for tests */
1174*e7be843bSPierre Pronchery sprintf(slength, "%zu", h3ssl.ldata);
1175*e7be843bSPierre Pronchery h3ssl.ptr_data = (uint8_t *) malloc(4096);
1176*e7be843bSPierre Pronchery memset(h3ssl.ptr_data, 'A', 4096);
1177*e7be843bSPierre Pronchery } else {
1178*e7be843bSPierre Pronchery /* normal file we have opened */
1179*e7be843bSPierre Pronchery sprintf(slength, "%zu", h3ssl.ldata);
1180*e7be843bSPierre Pronchery h3ssl.ptr_data = (uint8_t *) get_file_data(&h3ssl);
1181*e7be843bSPierre Pronchery if (h3ssl.ptr_data == NULL)
1182*e7be843bSPierre Pronchery abort();
1183*e7be843bSPierre Pronchery printf("before nghttp3_conn_submit_response on %llu for %s ...\n",
1184*e7be843bSPierre Pronchery (unsigned long long) h3ssl.id_bidi, h3ssl.url);
1185*e7be843bSPierre Pronchery if (strstr(h3ssl.url, ".png"))
1186*e7be843bSPierre Pronchery make_nv(&resp[num_nv++], "content-type", "image/png");
1187*e7be843bSPierre Pronchery else if (strstr(h3ssl.url, ".ico"))
1188*e7be843bSPierre Pronchery make_nv(&resp[num_nv++], "content-type", "image/vnd.microsoft.icon");
1189*e7be843bSPierre Pronchery else if (strstr(h3ssl.url, ".htm"))
1190*e7be843bSPierre Pronchery make_nv(&resp[num_nv++], "content-type", "text/html");
1191*e7be843bSPierre Pronchery else
1192*e7be843bSPierre Pronchery make_nv(&resp[num_nv++], "content-type", "application/octet-stream");
1193*e7be843bSPierre Pronchery make_nv(&resp[num_nv++], "content-length", slength);
1194*e7be843bSPierre Pronchery }
1195*e7be843bSPierre Pronchery
1196*e7be843bSPierre Pronchery dr.read_data = step_read_data;
1197*e7be843bSPierre Pronchery if (nghttp3_conn_submit_response(h3conn, h3ssl.id_bidi, resp, num_nv, &dr)) {
1198*e7be843bSPierre Pronchery fprintf(stderr, "nghttp3_conn_submit_response failed!\n");
1199*e7be843bSPierre Pronchery goto err;
1200*e7be843bSPierre Pronchery }
1201*e7be843bSPierre Pronchery printf("nghttp3_conn_submit_response on %llu...\n", (unsigned long long) h3ssl.id_bidi);
1202*e7be843bSPierre Pronchery for (;;) {
1203*e7be843bSPierre Pronchery nghttp3_vec vec[256];
1204*e7be843bSPierre Pronchery nghttp3_ssize sveccnt;
1205*e7be843bSPierre Pronchery int fin, i;
1206*e7be843bSPierre Pronchery int64_t streamid;
1207*e7be843bSPierre Pronchery
1208*e7be843bSPierre Pronchery sveccnt = nghttp3_conn_writev_stream(h3conn, &streamid, &fin, vec,
1209*e7be843bSPierre Pronchery nghttp3_arraylen(vec));
1210*e7be843bSPierre Pronchery if (sveccnt <= 0) {
1211*e7be843bSPierre Pronchery printf("nghttp3_conn_writev_stream done: %ld stream: %llu fin %d\n",
1212*e7be843bSPierre Pronchery (long int)sveccnt,
1213*e7be843bSPierre Pronchery (unsigned long long)streamid,
1214*e7be843bSPierre Pronchery fin);
1215*e7be843bSPierre Pronchery if (streamid != -1 && fin) {
1216*e7be843bSPierre Pronchery printf("Sending end data on %llu fin %d\n",
1217*e7be843bSPierre Pronchery (unsigned long long) streamid, fin);
1218*e7be843bSPierre Pronchery nghttp3_conn_add_write_offset(h3conn, streamid, 0);
1219*e7be843bSPierre Pronchery continue;
1220*e7be843bSPierre Pronchery }
1221*e7be843bSPierre Pronchery if (!h3ssl.datadone)
1222*e7be843bSPierre Pronchery goto err;
1223*e7be843bSPierre Pronchery else
1224*e7be843bSPierre Pronchery break; /* Done */
1225*e7be843bSPierre Pronchery }
1226*e7be843bSPierre Pronchery printf("nghttp3_conn_writev_stream: %ld fin: %d\n", (long int)sveccnt, fin);
1227*e7be843bSPierre Pronchery for (i = 0; i < sveccnt; i++) {
1228*e7be843bSPierre Pronchery size_t numbytes = vec[i].len;
1229*e7be843bSPierre Pronchery int flagwrite = 0;
1230*e7be843bSPierre Pronchery
1231*e7be843bSPierre Pronchery printf("quic_server_write on %llu for %ld\n",
1232*e7be843bSPierre Pronchery (unsigned long long)streamid, (unsigned long)vec[i].len);
1233*e7be843bSPierre Pronchery if (fin && i == sveccnt - 1)
1234*e7be843bSPierre Pronchery flagwrite = SSL_WRITE_FLAG_CONCLUDE;
1235*e7be843bSPierre Pronchery if (!quic_server_write(&h3ssl, streamid, vec[i].base,
1236*e7be843bSPierre Pronchery vec[i].len, flagwrite, &numbytes)) {
1237*e7be843bSPierre Pronchery fprintf(stderr, "quic_server_write failed!\n");
1238*e7be843bSPierre Pronchery goto err;
1239*e7be843bSPierre Pronchery }
1240*e7be843bSPierre Pronchery }
1241*e7be843bSPierre Pronchery if (nghttp3_conn_add_write_offset(
1242*e7be843bSPierre Pronchery h3conn, streamid,
1243*e7be843bSPierre Pronchery (size_t)nghttp3_vec_len(vec, (size_t)sveccnt))) {
1244*e7be843bSPierre Pronchery fprintf(stderr, "nghttp3_conn_add_write_offset failed!\n");
1245*e7be843bSPierre Pronchery goto err;
1246*e7be843bSPierre Pronchery }
1247*e7be843bSPierre Pronchery }
1248*e7be843bSPierre Pronchery printf("nghttp3_conn_submit_response DONE!!!\n");
1249*e7be843bSPierre Pronchery
1250*e7be843bSPierre Pronchery if (h3ssl.datadone) {
1251*e7be843bSPierre Pronchery /*
1252*e7be843bSPierre Pronchery * All the data was sent.
1253*e7be843bSPierre Pronchery * close stream zero
1254*e7be843bSPierre Pronchery */
1255*e7be843bSPierre Pronchery if (!h3ssl.close_done) {
1256*e7be843bSPierre Pronchery set_id_status(h3ssl.id_bidi, SERVERCLOSED, &h3ssl);
1257*e7be843bSPierre Pronchery h3ssl.close_wait = 1;
1258*e7be843bSPierre Pronchery }
1259*e7be843bSPierre Pronchery } else {
1260*e7be843bSPierre Pronchery printf("nghttp3_conn_submit_response still not finished\n");
1261*e7be843bSPierre Pronchery }
1262*e7be843bSPierre Pronchery
1263*e7be843bSPierre Pronchery /* wait until closed */
1264*e7be843bSPierre Pronchery wait_close:
1265*e7be843bSPierre Pronchery hasnothing = 0;
1266*e7be843bSPierre Pronchery for (;;) {
1267*e7be843bSPierre Pronchery
1268*e7be843bSPierre Pronchery if (!hasnothing) {
1269*e7be843bSPierre Pronchery SSL *newssl = get_ids_connection(&h3ssl);
1270*e7be843bSPierre Pronchery
1271*e7be843bSPierre Pronchery printf("hasnothing nothing WAIT %d!!!\n", h3ssl.close_done);
1272*e7be843bSPierre Pronchery if (newssl == NULL)
1273*e7be843bSPierre Pronchery newssl = listener;
1274*e7be843bSPierre Pronchery ret = wait_for_activity(newssl);
1275*e7be843bSPierre Pronchery if (ret == -1)
1276*e7be843bSPierre Pronchery goto err;
1277*e7be843bSPierre Pronchery if (ret == 0)
1278*e7be843bSPierre Pronchery printf("hasnothing timeout\n");
1279*e7be843bSPierre Pronchery /* we have something or a timeout */
1280*e7be843bSPierre Pronchery handle_events_from_ids(&h3ssl);
1281*e7be843bSPierre Pronchery }
1282*e7be843bSPierre Pronchery hasnothing = read_from_ssl_ids(&h3conn, &h3ssl);
1283*e7be843bSPierre Pronchery if (hasnothing == -1) {
1284*e7be843bSPierre Pronchery printf("hasnothing failed\n");
1285*e7be843bSPierre Pronchery break;
1286*e7be843bSPierre Pronchery /* goto err; well in fact not */
1287*e7be843bSPierre Pronchery } else if (hasnothing == 0) {
1288*e7be843bSPierre Pronchery printf("hasnothing nothing\n");
1289*e7be843bSPierre Pronchery continue;
1290*e7be843bSPierre Pronchery } else {
1291*e7be843bSPierre Pronchery printf("hasnothing something\n");
1292*e7be843bSPierre Pronchery if (h3ssl.done) {
1293*e7be843bSPierre Pronchery printf("hasnothing something... DONE\n");
1294*e7be843bSPierre Pronchery /* we might already have the next connection to accept */
1295*e7be843bSPierre Pronchery hassomething = 1;
1296*e7be843bSPierre Pronchery break;
1297*e7be843bSPierre Pronchery }
1298*e7be843bSPierre Pronchery if (h3ssl.new_conn) {
1299*e7be843bSPierre Pronchery printf("hasnothing something... NEW CONN\n");
1300*e7be843bSPierre Pronchery h3ssl.new_conn = 0;
1301*e7be843bSPierre Pronchery goto newconn;
1302*e7be843bSPierre Pronchery }
1303*e7be843bSPierre Pronchery if (h3ssl.restart) {
1304*e7be843bSPierre Pronchery printf("hasnothing something... RESTART\n");
1305*e7be843bSPierre Pronchery h3ssl.restart = 0;
1306*e7be843bSPierre Pronchery goto restart;
1307*e7be843bSPierre Pronchery }
1308*e7be843bSPierre Pronchery if (are_all_clientid_closed(&h3ssl)) {
1309*e7be843bSPierre Pronchery printf("hasnothing something... DONE other side closed\n");
1310*e7be843bSPierre Pronchery /* there might 2 or 3 message we will ignore */
1311*e7be843bSPierre Pronchery hassomething = 0;
1312*e7be843bSPierre Pronchery break;
1313*e7be843bSPierre Pronchery }
1314*e7be843bSPierre Pronchery }
1315*e7be843bSPierre Pronchery }
1316*e7be843bSPierre Pronchery
1317*e7be843bSPierre Pronchery /*
1318*e7be843bSPierre Pronchery * Free the streams, then loop again, accepting another connection.
1319*e7be843bSPierre Pronchery */
1320*e7be843bSPierre Pronchery close_all_ids(&h3ssl);
1321*e7be843bSPierre Pronchery ssl = get_ids_connection(&h3ssl);
1322*e7be843bSPierre Pronchery if (ssl != NULL) {
1323*e7be843bSPierre Pronchery SSL_free(ssl);
1324*e7be843bSPierre Pronchery replace_ids_connection(&h3ssl, ssl, NULL);
1325*e7be843bSPierre Pronchery }
1326*e7be843bSPierre Pronchery hassomething = 0;
1327*e7be843bSPierre Pronchery }
1328*e7be843bSPierre Pronchery
1329*e7be843bSPierre Pronchery ok = 1;
1330*e7be843bSPierre Pronchery err:
1331*e7be843bSPierre Pronchery if (!ok)
1332*e7be843bSPierre Pronchery ERR_print_errors_fp(stderr);
1333*e7be843bSPierre Pronchery
1334*e7be843bSPierre Pronchery SSL_free(listener);
1335*e7be843bSPierre Pronchery return ok;
1336*e7be843bSPierre Pronchery }
1337*e7be843bSPierre Pronchery
1338*e7be843bSPierre Pronchery /*
1339*e7be843bSPierre Pronchery * demo server... just return a 20 bytes ascii string as response for any
1340*e7be843bSPierre Pronchery * request single h3 connection and single threaded.
1341*e7be843bSPierre Pronchery */
main(int argc,char ** argv)1342*e7be843bSPierre Pronchery int main(int argc, char **argv)
1343*e7be843bSPierre Pronchery {
1344*e7be843bSPierre Pronchery int rc = 1;
1345*e7be843bSPierre Pronchery SSL_CTX *ctx = NULL;
1346*e7be843bSPierre Pronchery int fd = -1;
1347*e7be843bSPierre Pronchery unsigned long port;
1348*e7be843bSPierre Pronchery
1349*e7be843bSPierre Pronchery if (argc < 4) {
1350*e7be843bSPierre Pronchery fprintf(stderr, "usage: %s <port> <server.crt> <server.key>\n",
1351*e7be843bSPierre Pronchery argv[0]);
1352*e7be843bSPierre Pronchery goto err;
1353*e7be843bSPierre Pronchery }
1354*e7be843bSPierre Pronchery
1355*e7be843bSPierre Pronchery /* Create SSL_CTX. */
1356*e7be843bSPierre Pronchery if ((ctx = create_ctx(argv[2], argv[3])) == NULL)
1357*e7be843bSPierre Pronchery goto err;
1358*e7be843bSPierre Pronchery
1359*e7be843bSPierre Pronchery /* Parse port number from command line arguments. */
1360*e7be843bSPierre Pronchery port = strtoul(argv[1], NULL, 0);
1361*e7be843bSPierre Pronchery if (port == 0 || port > UINT16_MAX) {
1362*e7be843bSPierre Pronchery fprintf(stderr, "invalid port: %lu\n", port);
1363*e7be843bSPierre Pronchery goto err;
1364*e7be843bSPierre Pronchery }
1365*e7be843bSPierre Pronchery
1366*e7be843bSPierre Pronchery /* Create UDP socket. */
1367*e7be843bSPierre Pronchery if ((fd = create_socket((uint16_t)port)) < 0)
1368*e7be843bSPierre Pronchery goto err;
1369*e7be843bSPierre Pronchery
1370*e7be843bSPierre Pronchery /* Enter QUIC server connection acceptance loop. */
1371*e7be843bSPierre Pronchery if (!run_quic_server(ctx, fd))
1372*e7be843bSPierre Pronchery goto err;
1373*e7be843bSPierre Pronchery
1374*e7be843bSPierre Pronchery rc = 0;
1375*e7be843bSPierre Pronchery err:
1376*e7be843bSPierre Pronchery if (rc != 0)
1377*e7be843bSPierre Pronchery ERR_print_errors_fp(stderr);
1378*e7be843bSPierre Pronchery
1379*e7be843bSPierre Pronchery SSL_CTX_free(ctx);
1380*e7be843bSPierre Pronchery
1381*e7be843bSPierre Pronchery if (fd != -1)
1382*e7be843bSPierre Pronchery BIO_closesocket(fd);
1383*e7be843bSPierre Pronchery
1384*e7be843bSPierre Pronchery return rc;
1385*e7be843bSPierre Pronchery }
1386