Home | History | Annotate | Line # | Download | only in http3
      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