| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385 |
- /*
- * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
- #include <assert.h>
- #include <netinet/in.h>
- #include <nghttp3/nghttp3.h>
- #include <openssl/err.h>
- #include <openssl/quic.h>
- #include <openssl/ssl.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/socket.h>
- #ifndef PATH_MAX
- # define PATH_MAX 255
- #endif
- #define nghttp3_arraylen(A) (sizeof(A) / sizeof(*(A)))
- /* The crappy test wants 20 bytes */
- #define NULL_PAYLOAD "12345678901234567890"
- static uint8_t *nulldata = (uint8_t *) NULL_PAYLOAD;
- static size_t nulldata_sz = sizeof(NULL_PAYLOAD) - 1;
- /* The nghttp3 variable we need in the main part and read_from_ssl_ids */
- static nghttp3_settings settings;
- static const nghttp3_mem *mem;
- static nghttp3_callbacks callbacks = {0};
- /* 3 streams created by the server and 4 by the client (one is bidi) */
- struct ssl_id {
- SSL *s; /* the stream openssl uses in SSL_read(), SSL_write etc */
- uint64_t id; /* the stream identifier the nghttp3 uses */
- int status; /* 0 or one the below status and origin */
- };
- /* status and origin of the streams the possible values are: */
- #define CLIENTUNIOPEN 0x01 /* unidirectional open by the client (2, 6 and 10) */
- #define CLIENTCLOSED 0x02 /* closed by the client */
- #define CLIENTBIDIOPEN 0x04 /* bidirectional open by the client (something like 0, 4, 8 ...) */
- #define SERVERUNIOPEN 0x08 /* unidirectional open by the server (3, 7 and 11) */
- #define SERVERCLOSED 0x10 /* closed by the server (us) */
- #define TOBEREMOVED 0x20 /* marked for removing in read_from_ssl_ids, */
- /* it will be removed after processing all events */
- #define ISLISTENER 0x40 /* the stream is a listener from SSL_new_listener() */
- #define ISCONNECTION 0x80 /* the stream is a connection from SSL_accept_connection() */
- #define MAXSSL_IDS 20
- #define MAXURL 255
- struct h3ssl {
- struct ssl_id ssl_ids[MAXSSL_IDS];
- int end_headers_received; /* h3 header received call back called */
- int datadone; /* h3 has given openssl all the data of the response */
- int has_uni; /* we have the 3 uni directional stream needed */
- int close_done; /* connection begins terminating EVENT_EC */
- int close_wait; /* we are waiting for a close or a new request */
- int done; /* connection terminated EVENT_ECD, after EVENT_EC */
- int new_conn; /* a new connection has been received */
- int received_from_two; /* workaround for -607 on nghttp3_conn_read_stream on stream 2 */
- int restart; /* new request/response cycle started */
- uint64_t id_bidi; /* the id of the stream used to read request and send response */
- char *fileprefix; /* prefix of the directory to fetch files from */
- char url[MAXURL]; /* url to serve the request */
- uint8_t *ptr_data; /* pointer to the data to send */
- size_t ldata; /* amount of bytes to send */
- int offset_data; /* offset to next data to send */
- };
- static void make_nv(nghttp3_nv *nv, const char *name, const char *value)
- {
- nv->name = (uint8_t *)name;
- nv->value = (uint8_t *)value;
- nv->namelen = strlen(name);
- nv->valuelen = strlen(value);
- nv->flags = NGHTTP3_NV_FLAG_NONE;
- }
- static void init_ids(struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids;
- int i;
- char *prior_fileprefix = h3ssl->fileprefix;
- if (h3ssl->ptr_data != NULL && h3ssl->ptr_data != nulldata)
- free(h3ssl->ptr_data);
- memset(h3ssl, 0, sizeof(struct h3ssl));
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++)
- ssl_ids[i].id = UINT64_MAX;
- h3ssl->id_bidi = UINT64_MAX;
- /* restore the fileprefix */
- h3ssl->fileprefix = prior_fileprefix;
- }
- static void reuse_h3ssl(struct h3ssl *h3ssl)
- {
- h3ssl->end_headers_received = 0;
- h3ssl->datadone = 0;
- h3ssl->close_done = 0;
- h3ssl->close_wait = 0;
- h3ssl->done = 0;
- memset(h3ssl->url, '\0', sizeof(h3ssl->url));
- if (h3ssl->ptr_data != NULL && h3ssl->ptr_data != nulldata)
- free(h3ssl->ptr_data);
- h3ssl->ptr_data = NULL;
- h3ssl->offset_data = 0;
- h3ssl->ldata = 0;
- }
- static void add_id_status(uint64_t id, SSL *ssl, struct h3ssl *h3ssl, int status)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].s == NULL) {
- ssl_ids[i].s = ssl;
- ssl_ids[i].id = id;
- ssl_ids[i].status = status;
- return;
- }
- }
- printf("Oops too many streams to add!!!\n");
- exit(1);
- }
- static void add_id(uint64_t id, SSL *ssl, struct h3ssl *h3ssl)
- {
- add_id_status(id, ssl, h3ssl, 0);
- }
- /* Add listener and connection */
- static void add_ids_listener(SSL *ssl, struct h3ssl *h3ssl)
- {
- add_id_status(UINT64_MAX, ssl, h3ssl, ISLISTENER);
- }
- static void add_ids_connection(struct h3ssl *h3ssl, SSL *ssl)
- {
- add_id_status(UINT64_MAX, ssl, h3ssl, ISCONNECTION);
- }
- static SSL *get_ids_connection(struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].status & ISCONNECTION) {
- printf("get_ids_connection\n");
- return ssl_ids[i].s;
- }
- }
- return NULL;
- }
- static void replace_ids_connection(struct h3ssl *h3ssl, SSL *oldstream, SSL *newstream)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].status & ISCONNECTION && ssl_ids[i].s == oldstream) {
- printf("replace_ids_connection\n");
- ssl_ids[i].s = newstream;
- }
- }
- }
- /* remove the ids marked for removal */
- static void remove_marked_ids(struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].status & TOBEREMOVED) {
- printf("remove_id %llu\n", (unsigned long long) ssl_ids[i].id);
- SSL_free(ssl_ids[i].s);
- ssl_ids[i].s = NULL;
- ssl_ids[i].id = UINT64_MAX;
- ssl_ids[i].status = 0;
- return;
- }
- }
- }
- /* add the status bytes to the status */
- static void set_id_status(uint64_t id, int status, struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].id == id) {
- printf("set_id_status: %llu to %d\n", (unsigned long long) ssl_ids[i].id, status);
- ssl_ids[i].status = ssl_ids[i].status | status;
- return;
- }
- }
- printf("Oops can't set status, can't find stream!!!\n");
- assert(0);
- }
- static int get_id_status(uint64_t id, struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].id == id) {
- printf("get_id_status: %llu to %d\n",
- (unsigned long long) ssl_ids[i].id, ssl_ids[i].status);
- return ssl_ids[i].status;
- }
- }
- printf("Oops can't get status, can't find stream!!!\n");
- assert(0);
- return -1;
- }
- /* check that all streams opened by the client are closed */
- static int are_all_clientid_closed(struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].id == UINT64_MAX)
- continue;
- printf("are_all_clientid_closed: %llu status %d : %d\n",
- (unsigned long long) ssl_ids[i].id, ssl_ids[i].status, CLIENTUNIOPEN | CLIENTCLOSED);
- if (ssl_ids[i].status & CLIENTUNIOPEN) {
- if (ssl_ids[i].status & CLIENTCLOSED) {
- printf("are_all_clientid_closed: %llu closed\n",
- (unsigned long long) ssl_ids[i].id);
- SSL_free(ssl_ids[i].s);
- ssl_ids[i].s = NULL;
- ssl_ids[i].id = UINT64_MAX;
- continue;
- }
- printf("are_all_clientid_closed: %llu open\n", (unsigned long long) ssl_ids[i].id);
- return 0;
- }
- }
- return 1;
- }
- /* free all the ids except listener and connection */
- static void close_all_ids(struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].id == UINT64_MAX)
- continue;
- SSL_free(ssl_ids[i].s);
- ssl_ids[i].s = NULL;
- ssl_ids[i].id = UINT64_MAX;
- }
- }
- static int on_recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token,
- nghttp3_rcbuf *name, nghttp3_rcbuf *value,
- uint8_t flags, void *user_data,
- void *stream_user_data)
- {
- nghttp3_vec vname, vvalue;
- struct h3ssl *h3ssl = (struct h3ssl *)user_data;
- /* Received a single HTTP header. */
- vname = nghttp3_rcbuf_get_buf(name);
- vvalue = nghttp3_rcbuf_get_buf(value);
- fwrite(vname.base, vname.len, 1, stdout);
- fprintf(stdout, ": ");
- fwrite(vvalue.base, vvalue.len, 1, stdout);
- fprintf(stdout, "\n");
- if (token == NGHTTP3_QPACK_TOKEN__PATH) {
- int len = (((vvalue.len) < (MAXURL)) ? (vvalue.len) : (MAXURL));
- memset(h3ssl->url, 0, sizeof(h3ssl->url));
- if (vvalue.base[0] == '/') {
- if (vvalue.base[1] == '\0') {
- strncpy(h3ssl->url, "index.html", MAXURL);
- } else {
- memcpy(h3ssl->url, vvalue.base + 1, len - 1);
- h3ssl->url[len - 1] = '\0';
- }
- } else {
- memcpy(h3ssl->url, vvalue.base, len);
- }
- }
- return 0;
- }
- static int on_end_headers(nghttp3_conn *conn, int64_t stream_id, int fin,
- void *user_data, void *stream_user_data)
- {
- struct h3ssl *h3ssl = (struct h3ssl *)user_data;
- fprintf(stderr, "on_end_headers!\n");
- h3ssl->end_headers_received = 1;
- return 0;
- }
- static int on_recv_data(nghttp3_conn *conn, int64_t stream_id,
- const uint8_t *data, size_t datalen,
- void *conn_user_data, void *stream_user_data)
- {
- fprintf(stderr, "on_recv_data! %ld\n", (unsigned long)datalen);
- fprintf(stderr, "on_recv_data! %.*s\n", (int)datalen, data);
- return 0;
- }
- static int on_end_stream(nghttp3_conn *h3conn, int64_t stream_id,
- void *conn_user_data, void *stream_user_data)
- {
- struct h3ssl *h3ssl = (struct h3ssl *)conn_user_data;
- printf("on_end_stream!\n");
- h3ssl->done = 1;
- return 0;
- }
- /* Read from the stream and push to the h3conn */
- static int quic_server_read(nghttp3_conn *h3conn, SSL *stream, uint64_t id, struct h3ssl *h3ssl)
- {
- int ret, r;
- uint8_t msg2[16000];
- size_t l = sizeof(msg2);
- if (!SSL_has_pending(stream))
- return 0; /* Nothing to read */
- ret = SSL_read(stream, msg2, l);
- if (ret <= 0) {
- fprintf(stderr, "SSL_read %d on %llu failed\n",
- SSL_get_error(stream, ret),
- (unsigned long long) id);
- switch (SSL_get_error(stream, ret)) {
- case SSL_ERROR_WANT_READ:
- return 0;
- case SSL_ERROR_ZERO_RETURN:
- return 1;
- default:
- ERR_print_errors_fp(stderr);
- return -1;
- }
- return -1;
- }
- /* XXX: work around nghttp3_conn_read_stream returning -607 on stream 2 */
- if (!h3ssl->received_from_two && id != 2) {
- r = nghttp3_conn_read_stream(h3conn, id, msg2, ret, 0);
- } else {
- r = ret; /* ignore it for the moment ... */
- }
- printf("nghttp3_conn_read_stream used %d of %d on %llu\n", r,
- ret, (unsigned long long) id);
- if (r != ret) {
- /* chrome returns -607 on stream 2 */
- if (!nghttp3_err_is_fatal(r)) {
- printf("nghttp3_conn_read_stream used %d of %d (not fatal) on %llu\n", r,
- ret, (unsigned long long) id);
- if (id == 2)
- h3ssl->received_from_two = 1;
- return 1;
- }
- return -1;
- }
- return 1;
- }
- /*
- * creates the control stream, the encoding and decoding streams.
- * nghttp3_conn_bind_control_stream() is for the control stream.
- */
- static int quic_server_h3streams(nghttp3_conn *h3conn, struct h3ssl *h3ssl)
- {
- SSL *rstream = NULL;
- SSL *pstream = NULL;
- SSL *cstream = NULL;
- SSL *conn;
- uint64_t r_streamid, p_streamid, c_streamid;
- conn = get_ids_connection(h3ssl);
- if (conn == NULL) {
- fprintf(stderr, "quic_server_h3streams no connection\n");
- fflush(stderr);
- return -1;
- }
- rstream = SSL_new_stream(conn, SSL_STREAM_FLAG_UNI);
- if (rstream != NULL) {
- printf("=> Opened on %llu\n",
- (unsigned long long)SSL_get_stream_id(rstream));
- } else {
- fprintf(stderr, "=> Stream == NULL!\n");
- goto err;
- }
- pstream = SSL_new_stream(conn, SSL_STREAM_FLAG_UNI);
- if (pstream != NULL) {
- printf("=> Opened on %llu\n",
- (unsigned long long)SSL_get_stream_id(pstream));
- } else {
- fprintf(stderr, "=> Stream == NULL!\n");
- goto err;
- }
- cstream = SSL_new_stream(conn, SSL_STREAM_FLAG_UNI);
- if (cstream != NULL) {
- fprintf(stderr, "=> Opened on %llu\n",
- (unsigned long long)SSL_get_stream_id(cstream));
- fflush(stderr);
- } else {
- fprintf(stderr, "=> Stream == NULL!\n");
- goto err;
- }
- r_streamid = SSL_get_stream_id(rstream);
- p_streamid = SSL_get_stream_id(pstream);
- c_streamid = SSL_get_stream_id(cstream);
- if (nghttp3_conn_bind_qpack_streams(h3conn, p_streamid, r_streamid)) {
- fprintf(stderr, "nghttp3_conn_bind_qpack_streams failed!\n");
- goto err;
- }
- if (nghttp3_conn_bind_control_stream(h3conn, c_streamid)) {
- fprintf(stderr, "nghttp3_conn_bind_qpack_streams failed!\n");
- goto err;
- }
- printf("control: %llu enc %llu dec %llu\n",
- (unsigned long long)c_streamid,
- (unsigned long long)p_streamid,
- (unsigned long long)r_streamid);
- add_id(SSL_get_stream_id(rstream), rstream, h3ssl);
- add_id(SSL_get_stream_id(pstream), pstream, h3ssl);
- add_id(SSL_get_stream_id(cstream), cstream, h3ssl);
- return 0;
- err:
- fflush(stderr);
- SSL_free(rstream);
- SSL_free(pstream);
- SSL_free(cstream);
- return -1;
- }
- /* Try to read from the streams we have */
- static int read_from_ssl_ids(nghttp3_conn **curh3conn, struct h3ssl *h3ssl)
- {
- int hassomething = 0, i;
- struct ssl_id *ssl_ids = h3ssl->ssl_ids;
- SSL_POLL_ITEM items[MAXSSL_IDS] = {0}, *item = items;
- static const struct timeval nz_timeout = {0, 0};
- size_t result_count = SIZE_MAX;
- int numitem = 0, ret;
- uint64_t processed_event = 0;
- int has_ids_to_remove = 0;
- nghttp3_conn *h3conn = *curh3conn;
- /*
- * Process all the streams
- * the first one is the connection if we get something here is a new stream
- */
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].s != NULL) {
- item->desc = SSL_as_poll_descriptor(ssl_ids[i].s);
- item->events = UINT64_MAX; /* TODO adjust to the event we need process */
- item->revents = UINT64_MAX; /* TODO adjust to the event we need process */
- numitem++;
- item++;
- }
- }
- /*
- * SSL_POLL_FLAG_NO_HANDLE_EVENTS would require to use:
- * SSL_get_event_timeout on the connection stream
- * select/wait using the timeout value (which could be no wait time)
- * SSL_handle_events
- * SSL_poll
- * for the moment we let SSL_poll to performs ticking internally
- * on an automatic basis.
- */
- ret = SSL_poll(items, numitem, sizeof(SSL_POLL_ITEM), &nz_timeout,
- SSL_POLL_FLAG_NO_HANDLE_EVENTS, &result_count);
- if (!ret) {
- fprintf(stderr, "SSL_poll failed\n");
- printf("SSL_poll failed\n");
- return -1; /* something is wrong */
- }
- printf("read_from_ssl_ids %ld events\n", (unsigned long)result_count);
- if (result_count == 0) {
- /* Timeout may be something somewhere */
- return 0;
- }
- /* reset the states */
- h3ssl->new_conn = 0;
- h3ssl->restart = 0;
- h3ssl->done = 0;
- /* Process all the item we have polled */
- for (i = 0, item = items; i < numitem; i++, item++) {
- SSL *s;
- if (item->revents == SSL_POLL_EVENT_NONE)
- continue;
- processed_event = 0;
- /* get the stream */
- s = item->desc.value.ssl;
- /* New connection */
- if (item->revents & SSL_POLL_EVENT_IC) {
- SSL *conn = SSL_accept_connection(item->desc.value.ssl, 0);
- SSL *oldconn;
- printf("SSL_accept_connection\n");
- if (conn == NULL) {
- fprintf(stderr, "error while accepting connection\n");
- ret = -1;
- goto err;
- }
- /* the previous might be still there */
- oldconn = get_ids_connection(h3ssl);
- if (oldconn != NULL) {
- /* XXX we support only one connection for the moment */
- printf("SSL_accept_connection closing previous\n");
- SSL_free(oldconn);
- replace_ids_connection(h3ssl, oldconn, conn);
- reuse_h3ssl(h3ssl);
- close_all_ids(h3ssl);
- h3ssl->id_bidi = UINT64_MAX;
- h3ssl->has_uni = 0;
- } else {
- printf("SSL_accept_connection first connection\n");
- add_ids_connection(h3ssl, conn);
- }
- h3ssl->new_conn = 1;
- /* create the new h3conn */
- nghttp3_conn_del(*curh3conn);
- nghttp3_settings_default(&settings);
- if (nghttp3_conn_server_new(curh3conn, &callbacks, &settings, mem,
- h3ssl)) {
- fprintf(stderr, "nghttp3_conn_client_new failed!\n");
- exit(1);
- }
- h3conn = *curh3conn;
- hassomething++;
- if (!SSL_set_incoming_stream_policy(conn,
- SSL_INCOMING_STREAM_POLICY_ACCEPT, 0)) {
- fprintf(stderr, "error while setting inccoming stream policy\n");
- ret = -1;
- goto err;
- }
- printf("SSL_accept_connection\n");
- processed_event = processed_event | SSL_POLL_EVENT_IC;
- }
- /* SSL_accept_stream if SSL_POLL_EVENT_ISB or SSL_POLL_EVENT_ISU */
- if ((item->revents & SSL_POLL_EVENT_ISB) ||
- (item->revents & SSL_POLL_EVENT_ISU)) {
- SSL *stream = SSL_accept_stream(item->desc.value.ssl, 0);
- uint64_t new_id;
- int r;
- if (stream == NULL) {
- ret = -1;
- goto err;
- }
- new_id = SSL_get_stream_id(stream);
- printf("=> Received connection on %lld %d\n", (unsigned long long) new_id,
- SSL_get_stream_type(stream));
- add_id(new_id, stream, h3ssl);
- if (h3ssl->close_wait) {
- printf("in close_wait so we will have a new request\n");
- reuse_h3ssl(h3ssl);
- h3ssl->restart = 1; /* Checked in wait_close loop */
- }
- if (SSL_get_stream_type(stream) == SSL_STREAM_TYPE_BIDI) {
- /* bidi that is the id where we have to send the response */
- if (h3ssl->id_bidi != UINT64_MAX) {
- set_id_status(h3ssl->id_bidi, TOBEREMOVED, h3ssl);
- has_ids_to_remove++;
- }
- h3ssl->id_bidi = new_id;
- reuse_h3ssl(h3ssl);
- h3ssl->restart = 1;
- } else {
- set_id_status(new_id, CLIENTUNIOPEN, h3ssl);
- }
- r = quic_server_read(h3conn, stream, new_id, h3ssl);
- if (r == -1) {
- ret = -1;
- goto err;
- }
- if (r == 1)
- hassomething++;
- if (item->revents & SSL_POLL_EVENT_ISB)
- processed_event = processed_event | SSL_POLL_EVENT_ISB;
- if (item->revents & SSL_POLL_EVENT_ISU)
- processed_event = processed_event | SSL_POLL_EVENT_ISU;
- }
- if (item->revents & SSL_POLL_EVENT_OSB) {
- /* Create new streams when allowed */
- /* at least one bidi */
- processed_event = processed_event | SSL_POLL_EVENT_OSB;
- printf("Create bidi?\n");
- }
- if (item->revents & SSL_POLL_EVENT_OSU) {
- /* at least one uni */
- /* we have 4 streams from the client 2, 6 , 10 and 0 */
- /* need 3 streams to the client */
- printf("Create uni?\n");
- processed_event = processed_event | SSL_POLL_EVENT_OSU;
- if (!h3ssl->has_uni) {
- printf("Create uni\n");
- ret = quic_server_h3streams(h3conn, h3ssl);
- if (ret == -1) {
- fprintf(stderr, "quic_server_h3streams failed!\n");
- goto err;
- }
- h3ssl->has_uni = 1;
- hassomething++;
- }
- }
- if (item->revents & SSL_POLL_EVENT_EC) {
- /* the connection begins terminating */
- printf("Connection terminating\n");
- printf("Connection terminating restart %d\n", h3ssl->restart);
- if (!h3ssl->close_done) {
- h3ssl->close_done = 1;
- } else {
- h3ssl->done = 1;
- }
- hassomething++;
- processed_event = processed_event | SSL_POLL_EVENT_EC;
- }
- if (item->revents & SSL_POLL_EVENT_ECD) {
- /* the connection is terminated */
- printf("Connection terminated\n");
- h3ssl->done = 1;
- hassomething++;
- processed_event = processed_event | SSL_POLL_EVENT_ECD;
- }
- if (item->revents & SSL_POLL_EVENT_R) {
- /* try to read */
- uint64_t id = UINT64_MAX;
- int r;
- /* get the id, well the connection has no id... */
- id = SSL_get_stream_id(item->desc.value.ssl);
- printf("revent READ on %llu\n", (unsigned long long)id);
- r = quic_server_read(h3conn, s, id, h3ssl);
- if (r == 0) {
- uint8_t msg[1];
- size_t l = sizeof(msg);
- /* check that the other side is closed */
- r = SSL_read(s, msg, l);
- printf("SSL_read tells %d\n", r);
- if (r > 0) {
- ret = -1;
- goto err;
- }
- r = SSL_get_error(s, r);
- if (r != SSL_ERROR_ZERO_RETURN) {
- ret = -1;
- goto err;
- }
- set_id_status(id, TOBEREMOVED, h3ssl);
- has_ids_to_remove++;
- continue;
- }
- if (r == -1) {
- ret = -1;
- goto err;
- }
- hassomething++;
- processed_event = processed_event | SSL_POLL_EVENT_R;
- }
- if (item->revents & SSL_POLL_EVENT_ER) {
- /* mark it closed */
- uint64_t id = UINT64_MAX;
- int status;
- id = SSL_get_stream_id(item->desc.value.ssl);
- status = get_id_status(id, h3ssl);
- printf("revent exception READ on %llu\n", (unsigned long long)id);
- if (status & CLIENTUNIOPEN) {
- set_id_status(id, CLIENTCLOSED, h3ssl);
- hassomething++;
- }
- processed_event = processed_event | SSL_POLL_EVENT_ER;
- }
- if (item->revents & SSL_POLL_EVENT_W) {
- /* we ignore those for the moment */
- processed_event = processed_event | SSL_POLL_EVENT_W;
- }
- if (item->revents & SSL_POLL_EVENT_EW) {
- /* write part received a STOP_SENDING */
- uint64_t id = UINT64_MAX;
- int status;
- id = SSL_get_stream_id(item->desc.value.ssl);
- status = get_id_status(id, h3ssl);
- if (status & SERVERCLOSED) {
- printf("both sides closed on %llu\n", (unsigned long long)id);
- set_id_status(id, TOBEREMOVED, h3ssl);
- has_ids_to_remove++;
- hassomething++;
- }
- processed_event = processed_event | SSL_POLL_EVENT_EW;
- }
- if (item->revents != processed_event) {
- /* Figure out ??? */
- uint64_t id = UINT64_MAX;
- id = SSL_get_stream_id(item->desc.value.ssl);
- printf("revent %llu (%d) on %llu NOT PROCESSED!\n",
- (unsigned long long)item->revents, SSL_POLL_EVENT_W,
- (unsigned long long)id);
- }
- }
- ret = hassomething;
- err:
- if (has_ids_to_remove)
- remove_marked_ids(h3ssl);
- return ret;
- }
- static void handle_events_from_ids(struct h3ssl *h3ssl)
- {
- struct ssl_id *ssl_ids = h3ssl->ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].s != NULL &&
- (ssl_ids[i].status & ISCONNECTION || ssl_ids[i].status & ISLISTENER)) {
- if (SSL_handle_events(ssl_ids[i].s))
- ERR_print_errors_fp(stderr);
- }
- }
- }
- static size_t get_file_length(struct h3ssl *h3ssl)
- {
- char filename[PATH_MAX];
- struct stat st;
- memset(filename, 0, PATH_MAX);
- if (h3ssl->fileprefix != NULL)
- strcat(filename, h3ssl->fileprefix);
- strcat(filename, h3ssl->url);
- if (strcmp(h3ssl->url, "big") == 0) {
- printf("big!!!\n");
- return (size_t)INT_MAX;
- }
- if (stat(filename, &st) == 0) {
- /* Only process regular files */
- if (S_ISREG(st.st_mode)) {
- printf("get_file_length %s %lld\n", filename, (unsigned long long) st.st_size);
- return (size_t)st.st_size;
- }
- }
- printf("Can't get_file_length %s\n", filename);
- return 0;
- }
- static char *get_file_data(struct h3ssl *h3ssl)
- {
- char filename[PATH_MAX];
- size_t size = get_file_length(h3ssl);
- char *res;
- int fd;
- if (size == 0)
- return NULL;
- memset(filename, 0, PATH_MAX);
- if (h3ssl->fileprefix != NULL)
- strcat(filename, h3ssl->fileprefix);
- strcat(filename, h3ssl->url);
- res = malloc(size+1);
- res[size] = '\0';
- fd = open(filename, O_RDONLY);
- if (read(fd, res, size) == -1) {
- close(fd);
- free(res);
- return NULL;
- }
- close(fd);
- printf("read from %s : %zu\n", filename, size);
- return res;
- }
- static nghttp3_ssize step_read_data(nghttp3_conn *conn, int64_t stream_id,
- nghttp3_vec *vec, size_t veccnt,
- uint32_t *pflags, void *user_data,
- void *stream_user_data)
- {
- struct h3ssl *h3ssl = (struct h3ssl *)user_data;
- if (h3ssl->datadone) {
- *pflags = NGHTTP3_DATA_FLAG_EOF;
- return 0;
- }
- /* send the data */
- printf("step_read_data for %s %zu\n", h3ssl->url, h3ssl->ldata);
- if (h3ssl->ldata <= 4096) {
- vec[0].base = &(h3ssl->ptr_data[h3ssl->offset_data]);
- vec[0].len = h3ssl->ldata;
- h3ssl->datadone++;
- *pflags = NGHTTP3_DATA_FLAG_EOF;
- } else {
- vec[0].base = &(h3ssl->ptr_data[h3ssl->offset_data]);
- vec[0].len = 4096;
- if (h3ssl->ldata == INT_MAX) {
- printf("big = endless!\n");
- } else {
- h3ssl->offset_data = h3ssl->offset_data + 4096;
- h3ssl->ldata = h3ssl->ldata - 4096;
- }
- }
- return 1;
- }
- static int quic_server_write(struct h3ssl *h3ssl, uint64_t streamid,
- uint8_t *buff, size_t len, uint64_t flags,
- size_t *written)
- {
- struct ssl_id *ssl_ids;
- int i;
- ssl_ids = h3ssl->ssl_ids;
- for (i = 0; i < MAXSSL_IDS; i++) {
- if (ssl_ids[i].id == streamid) {
- if (!SSL_write_ex2(ssl_ids[i].s, buff, len, flags, written) ||
- *written != len) {
- fprintf(stderr, "couldn't write on connection\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
- printf("written %lld on %lld flags %lld\n", (unsigned long long)len,
- (unsigned long long)streamid, (unsigned long long)flags);
- return 1;
- }
- }
- printf("quic_server_write %lld on %lld (NOT FOUND!)\n", (unsigned long long)len,
- (unsigned long long)streamid);
- return 0;
- }
- #define OSSL_NELEM(x) (sizeof(x) / sizeof((x)[0]))
- /*
- * This is a basic demo of QUIC server functionality in which one connection at
- * a time is accepted in a blocking loop.
- */
- /* ALPN string for TLS handshake. We pretent h3-29 and h3 */
- static const unsigned char alpn_ossltest[] = { 5, 'h', '3', '-', '2',
- '9', 2, 'h', '3' };
- /*
- * This callback validates and negotiates the desired ALPN on the server side.
- */
- static int select_alpn(SSL *ssl, const unsigned char **out,
- unsigned char *out_len, const unsigned char *in,
- unsigned int in_len, void *arg)
- {
- if (SSL_select_next_proto((unsigned char **)out, out_len, alpn_ossltest,
- sizeof(alpn_ossltest), in,
- in_len) != OPENSSL_NPN_NEGOTIATED)
- return SSL_TLSEXT_ERR_ALERT_FATAL;
- return SSL_TLSEXT_ERR_OK;
- }
- /* Create SSL_CTX. */
- static SSL_CTX *create_ctx(const char *cert_path, const char *key_path)
- {
- SSL_CTX *ctx;
- ctx = SSL_CTX_new(OSSL_QUIC_server_method());
- if (ctx == NULL)
- goto err;
- /* Load certificate and corresponding private key. */
- if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) <= 0) {
- fprintf(stderr, "couldn't load certificate file: %s\n", cert_path);
- goto err;
- }
- if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) <= 0) {
- fprintf(stderr, "couldn't load key file: %s\n", key_path);
- goto err;
- }
- if (!SSL_CTX_check_private_key(ctx)) {
- fprintf(stderr, "private key check failed\n");
- goto err;
- }
- /* Setup ALPN negotiation callback. */
- SSL_CTX_set_alpn_select_cb(ctx, select_alpn, NULL);
- return ctx;
- err:
- SSL_CTX_free(ctx);
- return NULL;
- }
- /* Create UDP socket using given port. */
- static int create_socket(uint16_t port)
- {
- int fd = -1;
- struct sockaddr_in sa = {0};
- if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- fprintf(stderr, "cannot create socket");
- goto err;
- }
- sa.sin_family = AF_INET;
- sa.sin_port = htons(port);
- if (bind(fd, (const struct sockaddr *)&sa, sizeof(sa)) < 0) {
- fprintf(stderr, "cannot bind to %u\n", port);
- goto err;
- }
- return fd;
- err:
- if (fd >= 0)
- BIO_closesocket(fd);
- return -1;
- }
- /* Copied from demos/guide/quic-server-non-block.c */
- /**
- * @brief Waits for activity on the SSL socket, either for reading or writing.
- *
- * This function monitors the underlying file descriptor of the given SSL
- * connection to determine when it is ready for reading or writing, or both.
- * It uses the select function to wait until the socket is either readable
- * or writable, depending on what the SSL connection requires.
- *
- * @param ssl A pointer to the SSL object representing the connection.
- *
- * @note This function blocks until there is activity on the socket. In a real
- * application, you might want to perform other tasks while waiting, such as
- * updating a GUI or handling other connections.
- *
- * @note This function uses select for simplicity and portability. Depending
- * on your application's requirements, you might consider using other
- * mechanisms like poll or epoll for handling multiple file descriptors.
- */
- static int wait_for_activity(SSL *ssl)
- {
- int sock, isinfinite;
- fd_set read_fd, write_fd;
- struct timeval tv;
- struct timeval *tvp = NULL;
- /* Get hold of the underlying file descriptor for the socket */
- if ((sock = SSL_get_fd(ssl)) == -1) {
- fprintf(stderr, "Unable to get file descriptor");
- return -1;
- }
- /* Initialize the fd_set structure */
- FD_ZERO(&read_fd);
- FD_ZERO(&write_fd);
- /*
- * Determine if we would like to write to the socket, read from it, or both.
- */
- if (SSL_net_write_desired(ssl))
- FD_SET(sock, &write_fd);
- if (SSL_net_read_desired(ssl))
- FD_SET(sock, &read_fd);
- /* Add the socket file descriptor to the fd_set */
- FD_SET(sock, &read_fd);
- /*
- * Find out when OpenSSL would next like to be called, regardless of
- * whether the state of the underlying socket has changed or not.
- */
- if (SSL_get_event_timeout(ssl, &tv, &isinfinite) && !isinfinite)
- tvp = &tv;
- /*
- * Wait until the socket is writeable or readable. We use select here
- * for the sake of simplicity and portability, but you could equally use
- * poll/epoll or similar functions
- *
- * NOTE: For the purposes of this demonstration code this effectively
- * makes this demo block until it has something more useful to do. In a
- * real application you probably want to go and do other work here (e.g.
- * update a GUI, or service other connections).
- *
- * Let's say for example that you want to update the progress counter on
- * a GUI every 100ms. One way to do that would be to use the timeout in
- * the last parameter to "select" below. If the tvp value is greater
- * than 100ms then use 100ms instead. Then, when select returns, you
- * check if it did so because of activity on the file descriptors or
- * because of the timeout. If the 100ms GUI timeout has expired but the
- * tvp timeout has not then go and update the GUI and then restart the
- * "select" (with updated timeouts).
- */
- return (select(sock + 1, &read_fd, &write_fd, NULL, tvp));
- }
- /* Main loop for server to accept QUIC connections. */
- static int run_quic_server(SSL_CTX *ctx, int fd)
- {
- int ok = 0;
- int hassomething = 0;
- SSL *listener = NULL;
- nghttp3_conn *h3conn = NULL;
- struct h3ssl h3ssl;
- SSL *ssl;
- char *fileprefix = getenv("FILEPREFIX");
- /* Create a new QUIC listener. */
- if ((listener = SSL_new_listener(ctx, 0)) == NULL)
- goto err;
- /* Provide the listener with our UDP socket. */
- if (!SSL_set_fd(listener, fd))
- goto err;
- /* Begin listening. */
- if (!SSL_listen(listener))
- goto err;
- /*
- * Listeners, and other QUIC objects, default to operating in blocking mode.
- * The configured behaviour is inherited by child objects.
- * Make sure we won't block as we use select().
- */
- if (!SSL_set_blocking_mode(listener, 0))
- goto err;
- /* Setup callbacks. */
- callbacks.recv_header = on_recv_header;
- callbacks.end_headers = on_end_headers;
- callbacks.recv_data = on_recv_data;
- callbacks.end_stream = on_end_stream;
- /* mem default */
- mem = nghttp3_mem_default();
- for (;;) {
- nghttp3_nv resp[10];
- size_t num_nv;
- nghttp3_data_reader dr;
- int ret;
- int numtimeout;
- char slength[22];
- int hasnothing;
- init_ids(&h3ssl);
- h3ssl.fileprefix = fileprefix;
- printf("listener: %p\n", (void *)listener);
- add_ids_listener(listener, &h3ssl);
- if (!hassomething) {
- printf("waiting on socket\n");
- fflush(stdout);
- ret = wait_for_activity(listener);
- if (ret == -1) {
- fprintf(stderr, "wait_for_activity failed!\n");
- goto err;
- }
- }
- /*
- * Service the connection. In a real application this would be done
- * concurrently. In this demonstration program a single connection is
- * accepted and serviced at a time.
- */
- newconn:
- printf("process_server starting...\n");
- fflush(stdout);
- /* wait until we have received the headers */
- restart:
- numtimeout = 0;
- num_nv = 0;
- while (!h3ssl.end_headers_received) {
- if (!hassomething) {
- if (wait_for_activity(listener) == 0) {
- printf("waiting for end_headers_received timeout %d\n", numtimeout);
- numtimeout++;
- if (numtimeout == 25)
- goto err;
- }
- handle_events_from_ids(&h3ssl);
- }
- hassomething = read_from_ssl_ids(&h3conn, &h3ssl);
- if (hassomething == -1) {
- fprintf(stderr, "read_from_ssl_ids hassomething failed\n");
- goto err;
- } else if (hassomething == 0) {
- printf("read_from_ssl_ids hassomething nothing...\n");
- } else {
- numtimeout = 0;
- printf("read_from_ssl_ids hassomething %d...\n", hassomething);
- if (h3ssl.close_done) {
- /* Other side has closed */
- break;
- }
- h3ssl.restart = 0;
- }
- }
- if (h3ssl.close_done) {
- printf("Other side close without request\n");
- goto wait_close;
- }
- printf("end_headers_received!!!\n");
- if (!h3ssl.has_uni) {
- /* time to create those otherwise we can't push anything to the client */
- printf("Create uni\n");
- if (quic_server_h3streams(h3conn, &h3ssl) == -1) {
- fprintf(stderr, "quic_server_h3streams failed!\n");
- goto err;
- }
- h3ssl.has_uni = 1;
- }
- /* we have receive the request build the response and send it */
- /* XXX add MAKE_NV("connection", "close"), to resp[] and recheck */
- make_nv(&resp[num_nv++], ":status", "200");
- h3ssl.ldata = get_file_length(&h3ssl);
- if (h3ssl.ldata == 0) {
- /* We don't find the file: use default test string */
- h3ssl.ptr_data = nulldata;
- h3ssl.ldata = nulldata_sz;
- sprintf(slength, "%zu", h3ssl.ldata);
- /* content-type: text/html */
- make_nv(&resp[num_nv++], "content-type", "text/html");
- } else if (h3ssl.ldata == INT_MAX) {
- /* endless file for tests */
- sprintf(slength, "%zu", h3ssl.ldata);
- h3ssl.ptr_data = (uint8_t *) malloc(4096);
- memset(h3ssl.ptr_data, 'A', 4096);
- } else {
- /* normal file we have opened */
- sprintf(slength, "%zu", h3ssl.ldata);
- h3ssl.ptr_data = (uint8_t *) get_file_data(&h3ssl);
- if (h3ssl.ptr_data == NULL)
- abort();
- printf("before nghttp3_conn_submit_response on %llu for %s ...\n",
- (unsigned long long) h3ssl.id_bidi, h3ssl.url);
- if (strstr(h3ssl.url, ".png"))
- make_nv(&resp[num_nv++], "content-type", "image/png");
- else if (strstr(h3ssl.url, ".ico"))
- make_nv(&resp[num_nv++], "content-type", "image/vnd.microsoft.icon");
- else if (strstr(h3ssl.url, ".htm"))
- make_nv(&resp[num_nv++], "content-type", "text/html");
- else
- make_nv(&resp[num_nv++], "content-type", "application/octet-stream");
- make_nv(&resp[num_nv++], "content-length", slength);
- }
- dr.read_data = step_read_data;
- if (nghttp3_conn_submit_response(h3conn, h3ssl.id_bidi, resp, num_nv, &dr)) {
- fprintf(stderr, "nghttp3_conn_submit_response failed!\n");
- goto err;
- }
- printf("nghttp3_conn_submit_response on %llu...\n", (unsigned long long) h3ssl.id_bidi);
- for (;;) {
- nghttp3_vec vec[256];
- nghttp3_ssize sveccnt;
- int fin, i;
- int64_t streamid;
- sveccnt = nghttp3_conn_writev_stream(h3conn, &streamid, &fin, vec,
- nghttp3_arraylen(vec));
- if (sveccnt <= 0) {
- printf("nghttp3_conn_writev_stream done: %ld stream: %llu fin %d\n",
- (long int)sveccnt,
- (unsigned long long)streamid,
- fin);
- if (streamid != -1 && fin) {
- printf("Sending end data on %llu fin %d\n",
- (unsigned long long) streamid, fin);
- nghttp3_conn_add_write_offset(h3conn, streamid, 0);
- continue;
- }
- if (!h3ssl.datadone)
- goto err;
- else
- break; /* Done */
- }
- printf("nghttp3_conn_writev_stream: %ld fin: %d\n", (long int)sveccnt, fin);
- for (i = 0; i < sveccnt; i++) {
- size_t numbytes = vec[i].len;
- int flagwrite = 0;
- printf("quic_server_write on %llu for %ld\n",
- (unsigned long long)streamid, (unsigned long)vec[i].len);
- if (fin && i == sveccnt - 1)
- flagwrite = SSL_WRITE_FLAG_CONCLUDE;
- if (!quic_server_write(&h3ssl, streamid, vec[i].base,
- vec[i].len, flagwrite, &numbytes)) {
- fprintf(stderr, "quic_server_write failed!\n");
- goto err;
- }
- }
- if (nghttp3_conn_add_write_offset(
- h3conn, streamid,
- (size_t)nghttp3_vec_len(vec, (size_t)sveccnt))) {
- fprintf(stderr, "nghttp3_conn_add_write_offset failed!\n");
- goto err;
- }
- }
- printf("nghttp3_conn_submit_response DONE!!!\n");
- if (h3ssl.datadone) {
- /*
- * All the data was sent.
- * close stream zero
- */
- if (!h3ssl.close_done) {
- set_id_status(h3ssl.id_bidi, SERVERCLOSED, &h3ssl);
- h3ssl.close_wait = 1;
- }
- } else {
- printf("nghttp3_conn_submit_response still not finished\n");
- }
- /* wait until closed */
- wait_close:
- hasnothing = 0;
- for (;;) {
- if (!hasnothing) {
- SSL *newssl = get_ids_connection(&h3ssl);
- printf("hasnothing nothing WAIT %d!!!\n", h3ssl.close_done);
- if (newssl == NULL)
- newssl = listener;
- ret = wait_for_activity(newssl);
- if (ret == -1)
- goto err;
- if (ret == 0)
- printf("hasnothing timeout\n");
- /* we have something or a timeout */
- handle_events_from_ids(&h3ssl);
- }
- hasnothing = read_from_ssl_ids(&h3conn, &h3ssl);
- if (hasnothing == -1) {
- printf("hasnothing failed\n");
- break;
- /* goto err; well in fact not */
- } else if (hasnothing == 0) {
- printf("hasnothing nothing\n");
- continue;
- } else {
- printf("hasnothing something\n");
- if (h3ssl.done) {
- printf("hasnothing something... DONE\n");
- /* we might already have the next connection to accept */
- hassomething = 1;
- break;
- }
- if (h3ssl.new_conn) {
- printf("hasnothing something... NEW CONN\n");
- h3ssl.new_conn = 0;
- goto newconn;
- }
- if (h3ssl.restart) {
- printf("hasnothing something... RESTART\n");
- h3ssl.restart = 0;
- goto restart;
- }
- if (are_all_clientid_closed(&h3ssl)) {
- printf("hasnothing something... DONE other side closed\n");
- /* there might 2 or 3 message we will ignore */
- hassomething = 0;
- break;
- }
- }
- }
- /*
- * Free the streams, then loop again, accepting another connection.
- */
- close_all_ids(&h3ssl);
- ssl = get_ids_connection(&h3ssl);
- if (ssl != NULL) {
- SSL_free(ssl);
- replace_ids_connection(&h3ssl, ssl, NULL);
- }
- hassomething = 0;
- }
- ok = 1;
- err:
- if (!ok)
- ERR_print_errors_fp(stderr);
- SSL_free(listener);
- return ok;
- }
- /*
- * demo server... just return a 20 bytes ascii string as response for any
- * request single h3 connection and single threaded.
- */
- int main(int argc, char **argv)
- {
- int rc = 1;
- SSL_CTX *ctx = NULL;
- int fd = -1;
- unsigned long port;
- if (argc < 4) {
- fprintf(stderr, "usage: %s <port> <server.crt> <server.key>\n",
- argv[0]);
- goto err;
- }
- /* Create SSL_CTX. */
- if ((ctx = create_ctx(argv[2], argv[3])) == NULL)
- goto err;
- /* Parse port number from command line arguments. */
- port = strtoul(argv[1], NULL, 0);
- if (port == 0 || port > UINT16_MAX) {
- fprintf(stderr, "invalid port: %lu\n", port);
- goto err;
- }
- /* Create UDP socket. */
- if ((fd = create_socket((uint16_t)port)) < 0)
- goto err;
- /* Enter QUIC server connection acceptance loop. */
- if (!run_quic_server(ctx, fd))
- goto err;
- rc = 0;
- err:
- if (rc != 0)
- ERR_print_errors_fp(stderr);
- SSL_CTX_free(ctx);
- if (fd != -1)
- BIO_closesocket(fd);
- return rc;
- }
|