526 lines
20 KiB
Plaintext
526 lines
20 KiB
Plaintext
.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
|
|
.\"
|
|
.\" Standard preamble:
|
|
.\" ========================================================================
|
|
.de Sp \" Vertical space (when we can't use .PP)
|
|
.if t .sp .5v
|
|
.if n .sp
|
|
..
|
|
.de Vb \" Begin verbatim text
|
|
.ft CW
|
|
.nf
|
|
.ne \\$1
|
|
..
|
|
.de Ve \" End verbatim text
|
|
.ft R
|
|
.fi
|
|
..
|
|
.\" Set up some character translations and predefined strings. \*(-- will
|
|
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
|
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
|
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
|
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
|
.\" nothing in troff, for use with C<>.
|
|
.tr \(*W-
|
|
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
|
.ie n \{\
|
|
. ds -- \(*W-
|
|
. ds PI pi
|
|
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
|
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
|
. ds L" ""
|
|
. ds R" ""
|
|
. ds C` ""
|
|
. ds C' ""
|
|
'br\}
|
|
.el\{\
|
|
. ds -- \|\(em\|
|
|
. ds PI \(*p
|
|
. ds L" ``
|
|
. ds R" ''
|
|
. ds C`
|
|
. ds C'
|
|
'br\}
|
|
.\"
|
|
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
|
.ie \n(.g .ds Aq \(aq
|
|
.el .ds Aq '
|
|
.\"
|
|
.\" If the F register is turned on, we'll generate index entries on stderr for
|
|
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
|
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
|
.\" output yourself in some meaningful fashion.
|
|
.\"
|
|
.\" Avoid warning from groff about undefined register 'F'.
|
|
.de IX
|
|
..
|
|
.nr rF 0
|
|
.if \n(.g .if rF .nr rF 1
|
|
.if (\n(rF:(\n(.g==0)) \{
|
|
. if \nF \{
|
|
. de IX
|
|
. tm Index:\\$1\t\\n%\t"\\$2"
|
|
..
|
|
. if !\nF==2 \{
|
|
. nr % 0
|
|
. nr F 2
|
|
. \}
|
|
. \}
|
|
.\}
|
|
.rr rF
|
|
.\"
|
|
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
|
|
.\" Fear. Run. Save yourself. No user-serviceable parts.
|
|
. \" fudge factors for nroff and troff
|
|
.if n \{\
|
|
. ds #H 0
|
|
. ds #V .8m
|
|
. ds #F .3m
|
|
. ds #[ \f1
|
|
. ds #] \fP
|
|
.\}
|
|
.if t \{\
|
|
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
|
|
. ds #V .6m
|
|
. ds #F 0
|
|
. ds #[ \&
|
|
. ds #] \&
|
|
.\}
|
|
. \" simple accents for nroff and troff
|
|
.if n \{\
|
|
. ds ' \&
|
|
. ds ` \&
|
|
. ds ^ \&
|
|
. ds , \&
|
|
. ds ~ ~
|
|
. ds /
|
|
.\}
|
|
.if t \{\
|
|
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
|
|
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
|
|
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
|
|
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
|
|
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
|
|
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
|
|
.\}
|
|
. \" troff and (daisy-wheel) nroff accents
|
|
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
|
|
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
|
|
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
|
|
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
|
|
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
|
|
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
|
|
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
|
|
.ds ae a\h'-(\w'a'u*4/10)'e
|
|
.ds Ae A\h'-(\w'A'u*4/10)'E
|
|
. \" corrections for vroff
|
|
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
|
|
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
|
|
. \" for low resolution devices (crt and lpr)
|
|
.if \n(.H>23 .if \n(.V>19 \
|
|
\{\
|
|
. ds : e
|
|
. ds 8 ss
|
|
. ds o a
|
|
. ds d- d\h'-1'\(ga
|
|
. ds D- D\h'-1'\(hy
|
|
. ds th \o'bp'
|
|
. ds Th \o'LP'
|
|
. ds ae ae
|
|
. ds Ae AE
|
|
.\}
|
|
.rm #[ #] #H #V #F C
|
|
.\" ========================================================================
|
|
.\"
|
|
.IX Title "OSSL-GUIDE-QUIC-SERVER-NON-BLOCK 7ossl"
|
|
.TH OSSL-GUIDE-QUIC-SERVER-NON-BLOCK 7ossl "2025-04-23" "3.5.1-dev" "OpenSSL"
|
|
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
|
.\" way too many mistakes in technical documents.
|
|
.if n .ad l
|
|
.nh
|
|
.SH "NAME"
|
|
ossl\-guide\-quic\-server\-non\-block
|
|
\&\- OpenSSL Guide: Writing a simple nonblocking QUIC server
|
|
.SH "SIMPLE NONBLOCKING QUIC SERVER EXAMPLE"
|
|
.IX Header "SIMPLE NONBLOCKING QUIC SERVER EXAMPLE"
|
|
This page presents various source code samples demonstrating how to write a
|
|
simple, non-concurrent, \s-1QUIC \s0\*(L"echo\*(R" server application which accepts one client
|
|
connection at a time, echoing input from the client back to the same client.
|
|
Once the current client disconnects, the next client connection is accepted.
|
|
.PP
|
|
The server only accepts \f(CW\*(C`http/1.0\*(C'\fR and \f(CW\*(C`hq\-interop\*(C'\fR \s-1ALPN\s0's and doesn't actually
|
|
implement \s-1HTTP\s0 but only does a simple echo. This is non-standard and will not
|
|
be supported by real world servers. This is for demonstration purposes only.
|
|
.PP
|
|
There are various methods to test this server: \fBquic\-client\-block.c\fR and
|
|
\&\fBquic\-client\-non\-block.c\fR will send a basic \s-1HTTP/1.0\s0 request, which the server
|
|
will echo back. You can also test this server by running
|
|
\&\f(CW\*(C`openssl s_client \-connect localhost:4443 \-4 \-quic \-alpn http/1.0\*(C'\fR and entering
|
|
text that will be echoed back by the server.
|
|
.PP
|
|
Both the listening socket and connected socket are \*(L"nonblocking\*(R". However,
|
|
we use \fIselect()\fR to make the listening socket block when it cannot read/write.
|
|
Rather than stopping and waiting, your application may need to go and do other
|
|
tasks whilst the \fB\s-1SSL\s0\fR object is unable to read/write. For example: updating a
|
|
\&\s-1GUI\s0 or performing operations on some other connection or stream.
|
|
.PP
|
|
The complete source code for this example nonblocking \s-1QUIC\s0 server is available
|
|
in the \fBdemos/guide\fR directory of the OpenSSL source distribution in the file
|
|
\&\fBquic\-server\-non\-block.c\fR. It is also available online at
|
|
<https://github.com/openssl/openssl/blob/master/demos/guide/quic\-server\-non\-block.c>.
|
|
.PP
|
|
We assume that you already have OpenSSL installed on your system; that you
|
|
already have some fundamental understanding of OpenSSL concepts and \s-1QUIC \s0(see
|
|
\&\fIossl\-guide\-libraries\-introduction\fR\|(7) and \fIossl\-guide\-quic\-introduction\fR\|(7));
|
|
and that you know how to write and build C code and link it against the
|
|
libcrypto and libssl libraries that are provided by OpenSSL. It also assumes
|
|
that you have a basic understanding of \s-1UDP/IP\s0 and sockets.
|
|
.SS "Creating the \s-1SSL_CTX\s0 and \s-1SSL\s0 objects"
|
|
.IX Subsection "Creating the SSL_CTX and SSL objects"
|
|
The first step is to create an \fB\s-1SSL_CTX\s0\fR object for our server. We use the
|
|
\&\fISSL_CTX_new\fR\|(3) function for this purpose. We pass as an argument the return
|
|
value of the function \fIOSSL_QUIC_server_method\fR\|(3). You should use this method
|
|
whenever you are writing a \s-1QUIC\s0 server.
|
|
.PP
|
|
.Vb 8
|
|
\& /*
|
|
\& * An SSL_CTX holds shared configuration information for multiple
|
|
\& * subsequent per\-client SSL connections. We specifically load a QUIC
|
|
\& * server method here.
|
|
\& */
|
|
\& ctx = SSL_CTX_new(OSSL_QUIC_server_method());
|
|
\& if (ctx == NULL)
|
|
\& goto err;
|
|
.Ve
|
|
.PP
|
|
Servers need a private key and certificate. Intermediate issuer \s-1CA\s0
|
|
certificates are often required, and both the server (end-entity or \s-1EE\s0)
|
|
certificate and the issuer (\*(L"chain\*(R") certificates are most easily configured in
|
|
a single \*(L"chain file\*(R". Below we load such a chain file (the \s-1EE\s0 certificate
|
|
must appear first), and then load the corresponding private key, checking that
|
|
it matches the server certificate. No checks are performed to check the
|
|
integrity of the chain (\s-1CA\s0 signatures or certificate expiration dates, for
|
|
example), but we do verify the consistency of the private key with the
|
|
corresponding certificate.
|
|
.PP
|
|
.Vb 10
|
|
\& /*
|
|
\& * Load the server\*(Aqs certificate *chain* file (PEM format), which includes
|
|
\& * not only the leaf (end\-entity) server certificate, but also any
|
|
\& * intermediate issuer\-CA certificates. The leaf certificate must be the
|
|
\& * first certificate in the file.
|
|
\& *
|
|
\& * In advanced use\-cases this can be called multiple times, once per public
|
|
\& * key algorithm for which the server has a corresponding certificate.
|
|
\& * However, the corresponding private key (see below) must be loaded first,
|
|
\& * *before* moving on to the next chain file.
|
|
\& */
|
|
\& if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) <= 0) {
|
|
\& fprintf(stderr, "couldn\*(Aqt load certificate file: %s\en", cert_path);
|
|
\& goto err;
|
|
\& }
|
|
\&
|
|
\& /*
|
|
\& * Load the corresponding private key, this also checks that the private
|
|
\& * key matches the just loaded end\-entity certificate. It does not check
|
|
\& * whether the certificate chain is valid, the certificates could be
|
|
\& * expired, or may otherwise fail to form a chain that a client can
|
|
\& * validate.
|
|
\& */
|
|
\& if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) <= 0) {
|
|
\& fprintf(stderr, "couldn\*(Aqt load key file: %s\en", key_path);
|
|
\& goto err;
|
|
\& }
|
|
.Ve
|
|
.PP
|
|
Most servers, including this one, do not solicit client certificates. We
|
|
therefore do not need a \*(L"trust store\*(R" and allow the handshake to complete even
|
|
when the client does not present a certificate. Note: Even if a client did
|
|
present a trusted certificate, for it to be useful, the server application
|
|
would still need custom code to use the verified identity to grant nondefault
|
|
access to that particular client. Some servers grant access to all clients
|
|
with certificates from a private \s-1CA,\s0 this then requires processing of
|
|
certificate revocation lists to deauthorise a client. It is often simpler and
|
|
more secure to instead keep a list of authorised public keys.
|
|
.PP
|
|
Though this is the default setting, we explicitly call the
|
|
\&\fISSL_CTX_set_verify\fR\|(3) function and pass the \fB\s-1SSL_VERIFY_NONE\s0\fR value to it.
|
|
The final argument to this function is a callback that you can optionally
|
|
supply to override the default handling for certificate verification. Most
|
|
applications do not need to do this so this can safely be set to \s-1NULL\s0 to get
|
|
the default handling.
|
|
.PP
|
|
.Vb 12
|
|
\& /*
|
|
\& * Clients rarely employ certificate\-based authentication, and so we don\*(Aqt
|
|
\& * require "mutual" TLS authentication (indeed there\*(Aqs no way to know
|
|
\& * whether or how the client authenticated the server, so the term "mutual"
|
|
\& * is potentially misleading).
|
|
\& *
|
|
\& * Since we\*(Aqre not soliciting or processing client certificates, we don\*(Aqt
|
|
\& * need to configure a trusted\-certificate store, so no call to
|
|
\& * SSL_CTX_set_default_verify_paths() is needed. The server\*(Aqs own
|
|
\& * certificate chain is assumed valid.
|
|
\& */
|
|
\& SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
|
|
.Ve
|
|
.PP
|
|
\&\s-1QUIC\s0 also dictates using Application-Layer Protocol Negotiation (\s-1ALPN\s0) to select
|
|
an application protocol. We use \fISSL_CTX_set_alpn_select_cb\fR\|(3) for this
|
|
purpose. We can pass a callback which will be called for each connection to
|
|
select an \s-1ALPN\s0 the server considers acceptable.
|
|
.PP
|
|
.Vb 2
|
|
\& /* Setup ALPN negotiation callback to decide which ALPN is accepted. */
|
|
\& SSL_CTX_set_alpn_select_cb(ctx, select_alpn, NULL);
|
|
.Ve
|
|
.PP
|
|
In this case, we only accept \*(L"http/1.0\*(R" and \*(L"hq-interop\*(R".
|
|
.PP
|
|
.Vb 8
|
|
\& /*
|
|
\& * ALPN strings for TLS handshake. Only \*(Aqhttp/1.0\*(Aq and \*(Aqhq\-interop\*(Aq
|
|
\& * are accepted.
|
|
\& */
|
|
\& static const unsigned char alpn_ossltest[] = {
|
|
\& 8, \*(Aqh\*(Aq, \*(Aqt\*(Aq, \*(Aqt\*(Aq, \*(Aqp\*(Aq, \*(Aq/\*(Aq, \*(Aq1\*(Aq, \*(Aq.\*(Aq, \*(Aq0\*(Aq,
|
|
\& 10, \*(Aqh\*(Aq, \*(Aqq\*(Aq, \*(Aq\-\*(Aq, \*(Aqi\*(Aq, \*(Aqn\*(Aq, \*(Aqt\*(Aq, \*(Aqe\*(Aq, \*(Aqr\*(Aq, \*(Aqo\*(Aq, \*(Aqp\*(Aq,
|
|
\& };
|
|
\&
|
|
\& 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_OK;
|
|
\& return SSL_TLSEXT_ERR_ALERT_FATAL;
|
|
\& }
|
|
.Ve
|
|
.PP
|
|
That is all the setup that we need to do for the \fB\s-1SSL_CTX\s0\fR. Next, we create a
|
|
\&\s-1UDP\s0 socket and bind to it on localhost.
|
|
.PP
|
|
.Vb 5
|
|
\& /* Retrieve the file descriptor for a new UDP socket */
|
|
\& if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
|
\& fprintf(stderr, "cannot create socket");
|
|
\& return \-1;
|
|
\& }
|
|
\&
|
|
\& sa.sin_family = AF_INET;
|
|
\& sa.sin_port = htons(port);
|
|
\&
|
|
\& /* Bind to the new UDP socket on localhost */
|
|
\& if (bind(fd, (const struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
|
\& fprintf(stderr, "cannot bind to %u\en", port);
|
|
\& BIO_closesocket(fd);
|
|
\& return \-1;
|
|
\& }
|
|
\&
|
|
\& /* Set port to nonblocking mode */
|
|
\& if (BIO_socket_nbio(fd, 1) <= 0) {
|
|
\& fprintf(stderr, "Unable to set port to nonblocking mode");
|
|
\& BIO_closesocket(fd);
|
|
\& return \-1;
|
|
\& }
|
|
.Ve
|
|
.PP
|
|
To run the \s-1QUIC\s0 server, we create an \fB\s-1SSL_LISTENER\s0\fR to listen for incoming
|
|
connections. We provide it with the bound \s-1UDP\s0 port to then explicitly begin
|
|
listening for new connections.
|
|
.PP
|
|
.Vb 3
|
|
\& /* 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;
|
|
\&
|
|
\& /* Set the listener mode to nonblocking, which is inherited by
|
|
\& * child objects.
|
|
\& */
|
|
\& if (!SSL_set_blocking_mode(listener, 0))
|
|
\& goto err;
|
|
\&
|
|
\& /*
|
|
\& * Begin listening. Note that is not usually needed as SSL_accept_connection
|
|
\& * will implicitly start listening. It is only needed if a server wishes to
|
|
\& * ensure it has started to accept incoming connections but does not wish to
|
|
\& * actually call SSL_accept_connection yet.
|
|
\& */
|
|
\& if (!SSL_listen(listener))
|
|
\& goto err;
|
|
.Ve
|
|
.SS "Server loop"
|
|
.IX Subsection "Server loop"
|
|
The server now enters a \*(L"forever\*(R" loop, handling one client connection at a
|
|
time. Before each connection, we clear the OpenSSL error stack so that any
|
|
error reports are related to just the new connection.
|
|
.PP
|
|
.Vb 2
|
|
\& /* Pristine error stack for each new connection */
|
|
\& ERR_clear_error();
|
|
.Ve
|
|
.PP
|
|
We then wait until a connection is ready for reading.
|
|
It uses the select function to wait until the socket is either readable
|
|
or writable, depending on what the \s-1SSL\s0 connection requires.
|
|
.PP
|
|
We then accept a new connection in which the handshake will have already
|
|
occurred. However, since we are in nonblocking mode, \fISSL_accept_connection\fR\|(3)
|
|
will return immediately. Therefore, we use a helper function to essentially
|
|
block until a connection is established.
|
|
.PP
|
|
.Vb 5
|
|
\& printf("Waiting for connection\en");
|
|
\& while ((conn = SSL_accept_connection(listener, 0)) == NULL) {
|
|
\& wait_for_activity(listener);
|
|
\& }
|
|
\& printf("Accepted new connection\en");
|
|
.Ve
|
|
.PP
|
|
The helper function wait_for_activity uses \fIselect()\fR to block until the file
|
|
descriptor belonging to the passed \s-1SSL\s0 object is readable. As mentioned earlier,
|
|
a more real-world application would likely use this time to perform other tasks.
|
|
.PP
|
|
.Vb 3
|
|
\& /* 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);
|
|
\&
|
|
\& /*
|
|
\& * 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\*(Aqs 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).
|
|
\& */
|
|
\&
|
|
\& select(sock + 1, &read_fd, &write_fd, NULL, tvp);
|
|
.Ve
|
|
.PP
|
|
With the handshake complete, the server reads all the client input.
|
|
.PP
|
|
.Vb 10
|
|
\& /* Read from client until the client sends a end of stream packet */
|
|
\& while (!eof) {
|
|
\& ret = SSL_read_ex(conn, buf + total_read, sizeof(buf) \- total_read,
|
|
\& &nread);
|
|
\& total_read += nread;
|
|
\& if (total_read >= 8192) {
|
|
\& fprintf(stderr, "Could not fit all data into buffer\en");
|
|
\& goto err;
|
|
\& }
|
|
\& switch (handle_io_failure(conn, ret)) {
|
|
\& case 1:
|
|
\& continue; /* Retry */
|
|
\& case 0:
|
|
\& /* Reached end of stream */
|
|
\& if (!SSL_has_pending(conn))
|
|
\& eof = 1;
|
|
\& break;
|
|
\& default:
|
|
\& fprintf(stderr, "Failed reading remaining data\en");
|
|
\& goto err;
|
|
\& }
|
|
\& }
|
|
.Ve
|
|
.PP
|
|
Finally, we echo the received data back to the client. We can use
|
|
\&\fISSL_write_ex2\fR\|(3) to pass in a special flag \s-1SSL_WRITE_FLAG_CONCLUDE\s0 that will
|
|
send a \s-1FIN\s0 packet once the write has successfully finished writing all the data
|
|
to the peer.
|
|
.PP
|
|
.Vb 9
|
|
\& /* Echo client input */
|
|
\& while (!SSL_write_ex2(conn, buf,
|
|
\& total_read,
|
|
\& SSL_WRITE_FLAG_CONCLUDE, &total_written)) {
|
|
\& if (handle_io_failure(conn, 0) == 1)
|
|
\& continue;
|
|
\& fprintf(stderr, "Failed to write data\en");
|
|
\& goto err;
|
|
\& }
|
|
.Ve
|
|
.PP
|
|
We then shut down the connection with \fISSL_shutdown\fR\|(3), which may need
|
|
to be called multiple times to ensure the connection is shutdown completely.
|
|
.PP
|
|
.Vb 8
|
|
\& /*
|
|
\& * Shut down the connection. We may need to call this multiple times
|
|
\& * to ensure the connection is shutdown completely.
|
|
\& */
|
|
\& while ((ret = SSL_shutdown(conn)) != 1) {
|
|
\& if (ret < 0 && handle_io_failure(conn, ret) == 1)
|
|
\& continue; /* Retry */
|
|
\& }
|
|
.Ve
|
|
.PP
|
|
Finally, we free the \s-1SSL\s0 connection, and the server is now ready to accept the
|
|
next client connection.
|
|
.PP
|
|
.Vb 1
|
|
\& SSL_free(conn);
|
|
.Ve
|
|
.SS "Final clean up"
|
|
.IX Subsection "Final clean up"
|
|
If the server somehow manages to break out of the infinite loop and
|
|
be ready to exit, it would deallocate the constructed \fB\s-1SSL\s0\fR.
|
|
.PP
|
|
.Vb 1
|
|
\& SSL_free(listener);
|
|
.Ve
|
|
.PP
|
|
And in the main function, it would deallocate the constructed \fB\s-1SSL_CTX\s0\fR.
|
|
.PP
|
|
.Vb 2
|
|
\& SSL_CTX_free(ctx);
|
|
\& BIO_closesocket(fd);
|
|
.Ve
|
|
.SH "SEE ALSO"
|
|
.IX Header "SEE ALSO"
|
|
\&\fIossl\-guide\-introduction\fR\|(7), \fIossl\-guide\-libraries\-introduction\fR\|(7),
|
|
\&\fIossl\-guide\-libssl\-introduction\fR\|(7), \fIossl\-guide\-quic\-introduction\fR\|(7),
|
|
\&\fIossl\-guide\-quic\-client\-non\-block\fR\|(7), \fIossl\-guide\-quic\-client\-block\fR\|(7),
|
|
\&\fIossl\-guide\-tls\-server\-block\fR\|(7), \fIossl\-guide\-quic\-server\-block\fR\|(7)
|
|
.SH "COPYRIGHT"
|
|
.IX Header "COPYRIGHT"
|
|
Copyright 2024\-2025 The OpenSSL Project Authors. All Rights Reserved.
|
|
.PP
|
|
Licensed under the Apache License 2.0 (the \*(L"License\*(R"). You may not use
|
|
this file except in compliance with the License. You can obtain a copy
|
|
in the file \s-1LICENSE\s0 in the source distribution or at
|
|
<https://www.openssl.org/source/license.html>.
|