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