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