xref: /freebsd/crypto/openssl/doc/man7/ossl-guide-quic-multi-stream.pod (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery=pod
2*e7be843bSPierre Pronchery
3*e7be843bSPierre Pronchery=begin comment
4*e7be843bSPierre Pronchery
5*e7be843bSPierre ProncheryNB: Changes to the source code samples in this file should also be reflected in
6*e7be843bSPierre Proncherydemos/guide/quic-multi-stream.c
7*e7be843bSPierre Pronchery
8*e7be843bSPierre Pronchery=end comment
9*e7be843bSPierre Pronchery
10*e7be843bSPierre Pronchery=head1 NAME
11*e7be843bSPierre Pronchery
12*e7be843bSPierre Proncheryossl-guide-quic-multi-stream
13*e7be843bSPierre Pronchery- OpenSSL Guide: Writing a simple multi-stream QUIC client
14*e7be843bSPierre Pronchery
15*e7be843bSPierre Pronchery=head1 INTRODUCTION
16*e7be843bSPierre Pronchery
17*e7be843bSPierre ProncheryThis page will introduce some important concepts required to write a simple
18*e7be843bSPierre ProncheryQUIC multi-stream application. It assumes a basic understanding of QUIC and how
19*e7be843bSPierre Proncheryit is used in OpenSSL. See L<ossl-guide-quic-introduction(7)> and
20*e7be843bSPierre ProncheryL<ossl-guide-quic-client-block(7)>.
21*e7be843bSPierre Pronchery
22*e7be843bSPierre Pronchery=head1 QUIC STREAMS
23*e7be843bSPierre Pronchery
24*e7be843bSPierre ProncheryIn a QUIC multi-stream application we separate out the concepts of a QUIC
25*e7be843bSPierre Pronchery"connection" and a QUIC "stream". A connection object represents the overarching
26*e7be843bSPierre Proncherydetails of the connection between a client and a server including all its
27*e7be843bSPierre Proncherynegotiated and configured parameters. We use the B<SSL> object for that in an
28*e7be843bSPierre ProncheryOpenSSL application (known as the connection B<SSL> object). It is created by an
29*e7be843bSPierre Proncheryapplication calling L<SSL_new(3)>.
30*e7be843bSPierre Pronchery
31*e7be843bSPierre ProncherySeparately a connection can have zero or more streams associated with it
32*e7be843bSPierre Pronchery(although a connection with zero streams is probably not very useful, so
33*e7be843bSPierre Proncherynormally you would have at least one). A stream is used to send and receive
34*e7be843bSPierre Proncherydata between the two peers. Each stream is also represented by an B<SSL>
35*e7be843bSPierre Proncheryobject. A stream is logically independent of all the other streams associated
36*e7be843bSPierre Proncherywith the same connection. Data sent on a stream is guaranteed to be delivered
37*e7be843bSPierre Proncheryin the order that it was sent within that stream. The same is not true across
38*e7be843bSPierre Proncherystreams, e.g. if an application sends data on stream 1 first and then sends some
39*e7be843bSPierre Proncherymore data on stream 2 second, then the remote peer may receive the data sent on
40*e7be843bSPierre Proncherystream 2 before it receives the data sent on stream 1.
41*e7be843bSPierre Pronchery
42*e7be843bSPierre ProncheryOnce the connection B<SSL> object has completed its handshake (i.e.
43*e7be843bSPierre ProncheryL<SSL_connect(3)> has returned 1), stream B<SSL> objects are created by the
44*e7be843bSPierre Proncheryapplication calling L<SSL_new_stream(3)> or L<SSL_accept_stream(3)> (see
45*e7be843bSPierre ProncheryL</CREATING NEW STREAMS> below).
46*e7be843bSPierre Pronchery
47*e7be843bSPierre ProncheryThe same threading rules apply to B<SSL> objects as for most OpenSSL objects
48*e7be843bSPierre Pronchery(see L<ossl-guide-libraries-introduction(7)>). In particular most OpenSSL
49*e7be843bSPierre Proncheryfunctions are thread safe, but the B<SSL> object is not. This means that you can
50*e7be843bSPierre Proncheryuse an B<SSL> object representing one stream at the same time as another thread
51*e7be843bSPierre Proncheryis using a different B<SSL> object for a different stream on the same
52*e7be843bSPierre Proncheryconnection. But you cannot use the same B<SSL> object on two different threads
53*e7be843bSPierre Proncheryat the same time (without additional application level locking).
54*e7be843bSPierre Pronchery
55*e7be843bSPierre Pronchery=head1 THE DEFAULT STREAM
56*e7be843bSPierre Pronchery
57*e7be843bSPierre ProncheryA connection B<SSL> object may also (optionally) be associated with a stream.
58*e7be843bSPierre ProncheryThis stream is known as the default stream. The default stream is automatically
59*e7be843bSPierre Proncherycreated and associated with the B<SSL> object when the application calls
60*e7be843bSPierre ProncheryL<SSL_read_ex(3)>, L<SSL_read(3)>, L<SSL_write_ex(3)> or L<SSL_write(3)> and
61*e7be843bSPierre Proncherypasses the connection B<SSL> object as a parameter.
62*e7be843bSPierre Pronchery
63*e7be843bSPierre ProncheryIf a client application calls L<SSL_write_ex(3)> or L<SSL_write(3)> first then
64*e7be843bSPierre Pronchery(by default) the default stream will be a client-initiated bi-directional
65*e7be843bSPierre Proncherystream. If a client application calls L<SSL_read_ex(3)> or L<SSL_read(3)>
66*e7be843bSPierre Proncheryfirst then the first stream initiated by the server will be used as the default
67*e7be843bSPierre Proncherystream (whether it is bi-directional or uni-directional).
68*e7be843bSPierre Pronchery
69*e7be843bSPierre ProncheryThis behaviour can be controlled via the default stream mode. See
70*e7be843bSPierre ProncheryL<SSL_set_default_stream_mode(3)> for further details.
71*e7be843bSPierre Pronchery
72*e7be843bSPierre ProncheryIt is recommended that new multi-stream applications should not use a default
73*e7be843bSPierre Proncherystream at all and instead should use a separate stream B<SSL> object for each
74*e7be843bSPierre Proncherystream that is used. This requires calling L<SSL_set_default_stream_mode(3)>
75*e7be843bSPierre Proncheryand setting the mode to B<SSL_DEFAULT_STREAM_MODE_NONE>.
76*e7be843bSPierre Pronchery
77*e7be843bSPierre Pronchery=head1 CREATING NEW STREAMS
78*e7be843bSPierre Pronchery
79*e7be843bSPierre ProncheryAn endpoint can create a new stream by calling L<SSL_new_stream(3)>. This
80*e7be843bSPierre Proncherycreates a locally initiated stream. In order to do so you must pass the QUIC
81*e7be843bSPierre Proncheryconnection B<SSL> object as a parameter. You can also specify whether you want a
82*e7be843bSPierre Proncherybi-directional or a uni-directional stream.
83*e7be843bSPierre Pronchery
84*e7be843bSPierre ProncheryThe function returns a new QUIC stream B<SSL> object for sending and receiving
85*e7be843bSPierre Proncherydata on that stream.
86*e7be843bSPierre Pronchery
87*e7be843bSPierre ProncheryThe peer may also initiate streams. An application can use the function
88*e7be843bSPierre ProncheryL<SSL_get_accept_stream_queue_len(3)> to determine the number of streams that
89*e7be843bSPierre Proncherythe peer has initiated that are waiting for the application to handle. An
90*e7be843bSPierre Proncheryapplication can call L<SSL_accept_stream(3)> to create a new B<SSL> object for
91*e7be843bSPierre Proncherya remotely initiated stream. If the peer has not initiated any then this call
92*e7be843bSPierre Proncherywill block until one is available if the connection object is in blocking mode
93*e7be843bSPierre Pronchery(see L<SSL_set_blocking_mode(3)>).
94*e7be843bSPierre Pronchery
95*e7be843bSPierre ProncheryWhen using a default stream OpenSSL will prevent new streams from being
96*e7be843bSPierre Proncheryaccepted. To override this behaviour you must call
97*e7be843bSPierre ProncheryL<SSL_set_incoming_stream_policy(3)> to set the policy to
98*e7be843bSPierre ProncheryB<SSL_INCOMING_STREAM_POLICY_ACCEPT>. See the man page for further details. This
99*e7be843bSPierre Proncheryis not relevant if the default stream has been disabled as described in
100*e7be843bSPierre ProncheryL</THE DEFAULT STREAM> above.
101*e7be843bSPierre Pronchery
102*e7be843bSPierre ProncheryAny stream may be bi-directional or uni-directional. If it is uni-directional
103*e7be843bSPierre Proncherythen the initiator can write to it but not read from it, and vice-versa for the
104*e7be843bSPierre Proncherypeer. You can determine what type of stream an B<SSL> object represents by
105*e7be843bSPierre Proncherycalling L<SSL_get_stream_type(3)>. See the man page for further details.
106*e7be843bSPierre Pronchery
107*e7be843bSPierre Pronchery=head1 USING A STREAM TO SEND AND RECEIVE DATA
108*e7be843bSPierre Pronchery
109*e7be843bSPierre ProncheryOnce you have a stream B<SSL> object (which includes the connection B<SSL>
110*e7be843bSPierre Proncheryobject if a default stream is in use) then you can send and receive data over it
111*e7be843bSPierre Proncheryusing the L<SSL_write_ex(3)>, L<SSL_write(3)>, L<SSL_read_ex(3)> or
112*e7be843bSPierre ProncheryL<SSL_read(3)> functions. See the man pages for further details.
113*e7be843bSPierre Pronchery
114*e7be843bSPierre ProncheryIn the event of one of these functions not returning a success code then
115*e7be843bSPierre Proncheryyou should call L<SSL_get_error(3)> to find out further details about the error.
116*e7be843bSPierre ProncheryIn blocking mode this will either be a fatal error (e.g. B<SSL_ERROR_SYSCALL>
117*e7be843bSPierre Proncheryor B<SSL_ERROR_SSL>), or it will be B<SSL_ERROR_ZERO_RETURN> which can occur
118*e7be843bSPierre Proncherywhen attempting to read data from a stream and the peer has indicated that the
119*e7be843bSPierre Proncherystream is concluded (i.e. "FIN" has been signalled on the stream). This means
120*e7be843bSPierre Proncherythat the peer will send no more data on that stream. Note that the
121*e7be843bSPierre Proncheryinterpretation of B<SSL_ERROR_ZERO_RETURN> is slightly different for a QUIC
122*e7be843bSPierre Proncheryapplication compared to a TLS application. In TLS it occurs when the connection
123*e7be843bSPierre Proncheryhas been shutdown by the peer. In QUIC this only tells you that the current
124*e7be843bSPierre Proncherystream has been concluded by the peer. It tells you nothing about the underlying
125*e7be843bSPierre Proncheryconnection. If the peer has concluded the stream then no more data will be
126*e7be843bSPierre Proncheryreceived on it, however an application can still send data to the peer until
127*e7be843bSPierre Proncherythe send side of the stream has also been concluded. This can happen by the
128*e7be843bSPierre Proncheryapplication calling L<SSL_stream_conclude(3)>. It is an error to attempt to
129*e7be843bSPierre Proncherysend more data on a stream after L<SSL_stream_conclude(3)> has been called.
130*e7be843bSPierre Pronchery
131*e7be843bSPierre ProncheryIt is also possible to abandon a stream abnormally by calling
132*e7be843bSPierre ProncheryL<SSL_stream_reset(3)>.
133*e7be843bSPierre Pronchery
134*e7be843bSPierre ProncheryOnce a stream object is no longer needed it should be freed via a call to
135*e7be843bSPierre ProncheryL<SSL_free(3)>. An application should not call L<SSL_shutdown(3)> on it since
136*e7be843bSPierre Proncherythis is only meaningful for connection level B<SSL> objects. Freeing the stream
137*e7be843bSPierre Proncherywill automatically signal STOP_SENDING to the peer.
138*e7be843bSPierre Pronchery
139*e7be843bSPierre Pronchery=head1 STREAMS AND CONNECTIONS
140*e7be843bSPierre Pronchery
141*e7be843bSPierre ProncheryGiven a stream object it is possible to get the B<SSL> object corresponding to
142*e7be843bSPierre Proncherythe connection via a call to L<SSL_get0_connection(3)>. Multi-threaded
143*e7be843bSPierre Proncheryrestrictions apply so care should be taken when using the returned connection
144*e7be843bSPierre Proncheryobject. Specifically, if you are handling each of your stream objects in a
145*e7be843bSPierre Proncherydifferent thread and call L<SSL_get0_connection(3)> from within that thread then
146*e7be843bSPierre Proncheryyou must be careful to not to call any function that uses the connection object
147*e7be843bSPierre Proncheryat the same time as one of the other threads is also using that connection
148*e7be843bSPierre Proncheryobject (with the exception of L<SSL_accept_stream(3)> and
149*e7be843bSPierre ProncheryL<SSL_get_accept_stream_queue_len(3)> which are thread-safe).
150*e7be843bSPierre Pronchery
151*e7be843bSPierre ProncheryA stream object does not inherit all its settings and values from its parent
152*e7be843bSPierre ProncheryB<SSL> connection object. Therefore certain function calls that are relevant to
153*e7be843bSPierre Proncherythe connection as a whole will not work on a stream. For example the function
154*e7be843bSPierre ProncheryL<SSL_get_certificate(3)> can be used to obtain a handle on the peer certificate
155*e7be843bSPierre Proncherywhen called with a connection B<SSL> object. When called with a stream B<SSL>
156*e7be843bSPierre Proncheryobject it will return NULL.
157*e7be843bSPierre Pronchery
158*e7be843bSPierre Pronchery=head1 SIMPLE MULTI-STREAM QUIC CLIENT EXAMPLE
159*e7be843bSPierre Pronchery
160*e7be843bSPierre ProncheryThis section will present various source code samples demonstrating how to write
161*e7be843bSPierre Proncherya simple multi-stream QUIC client application which connects to a server, send
162*e7be843bSPierre Proncherysome HTTP/1.0 requests to it, and read back the responses. Note that HTTP/1.0
163*e7be843bSPierre Proncheryover QUIC is non-standard and will not be supported by real world servers. This
164*e7be843bSPierre Proncheryis for demonstration purposes only.
165*e7be843bSPierre Pronchery
166*e7be843bSPierre ProncheryWe will build on the example code for the simple blocking QUIC client that is
167*e7be843bSPierre Proncherycovered on the L<ossl-guide-quic-client-block(7)> page and we assume that you
168*e7be843bSPierre Proncheryare familiar with it. We will only describe the differences between the simple
169*e7be843bSPierre Proncheryblocking QUIC client and the multi-stream QUIC client. Although the example code
170*e7be843bSPierre Proncheryuses blocking B<SSL> objects, you can equally use nonblocking B<SSL> objects.
171*e7be843bSPierre ProncherySee L<ossl-guide-quic-client-non-block(7)> for more information about writing a
172*e7be843bSPierre Proncherynonblocking QUIC client.
173*e7be843bSPierre Pronchery
174*e7be843bSPierre ProncheryThe complete source code for this example multi-stream QUIC client is available
175*e7be843bSPierre Proncheryin the C<demos/guide> directory of the OpenSSL source distribution in the file
176*e7be843bSPierre ProncheryC<quic-multi-stream.c>. It is also available online at
177*e7be843bSPierre ProncheryL<https://github.com/openssl/openssl/blob/master/demos/guide/quic-multi-stream.c>.
178*e7be843bSPierre Pronchery
179*e7be843bSPierre Pronchery=head2 Disabling the default stream
180*e7be843bSPierre Pronchery
181*e7be843bSPierre ProncheryAs discussed above in L</THE DEFAULT STREAM> we will follow the recommendation
182*e7be843bSPierre Proncheryto disable the default stream for our multi-stream client. To do this we call
183*e7be843bSPierre Proncherythe L<SSL_set_default_stream_mode(3)> function and pass in our connection B<SSL>
184*e7be843bSPierre Proncheryobject and the value B<SSL_DEFAULT_STREAM_MODE_NONE>.
185*e7be843bSPierre Pronchery
186*e7be843bSPierre Pronchery    /*
187*e7be843bSPierre Pronchery     * We will use multiple streams so we will disable the default stream mode.
188*e7be843bSPierre Pronchery     * This is not a requirement for using multiple streams but is recommended.
189*e7be843bSPierre Pronchery     */
190*e7be843bSPierre Pronchery    if (!SSL_set_default_stream_mode(ssl, SSL_DEFAULT_STREAM_MODE_NONE)) {
191*e7be843bSPierre Pronchery        printf("Failed to disable the default stream mode\n");
192*e7be843bSPierre Pronchery        goto end;
193*e7be843bSPierre Pronchery    }
194*e7be843bSPierre Pronchery
195*e7be843bSPierre Pronchery=head2 Creating the request streams
196*e7be843bSPierre Pronchery
197*e7be843bSPierre ProncheryFor the purposes of this example we will create two different streams to send
198*e7be843bSPierre Proncherytwo different HTTP requests to the server. For the purposes of demonstration the
199*e7be843bSPierre Proncheryfirst of these will be a bi-directional stream and the second one will be a
200*e7be843bSPierre Proncheryuni-directional one:
201*e7be843bSPierre Pronchery
202*e7be843bSPierre Pronchery    /*
203*e7be843bSPierre Pronchery     * We create two new client initiated streams. The first will be
204*e7be843bSPierre Pronchery     * bi-directional, and the second will be uni-directional.
205*e7be843bSPierre Pronchery     */
206*e7be843bSPierre Pronchery    stream1 = SSL_new_stream(ssl, 0);
207*e7be843bSPierre Pronchery    stream2 = SSL_new_stream(ssl, SSL_STREAM_FLAG_UNI);
208*e7be843bSPierre Pronchery    if (stream1 == NULL || stream2 == NULL) {
209*e7be843bSPierre Pronchery        printf("Failed to create streams\n");
210*e7be843bSPierre Pronchery        goto end;
211*e7be843bSPierre Pronchery    }
212*e7be843bSPierre Pronchery
213*e7be843bSPierre Pronchery=head2 Writing data to the streams
214*e7be843bSPierre Pronchery
215*e7be843bSPierre ProncheryOnce the streams are successfully created we can start writing data to them. In
216*e7be843bSPierre Proncherythis example we will be sending a different HTTP request on each stream. To
217*e7be843bSPierre Proncheryavoid repeating too much code we write a simple helper function to send an HTTP
218*e7be843bSPierre Proncheryrequest to a stream:
219*e7be843bSPierre Pronchery
220*e7be843bSPierre Pronchery    int write_a_request(SSL *stream, const char *request_start,
221*e7be843bSPierre Pronchery                        const char *hostname)
222*e7be843bSPierre Pronchery    {
223*e7be843bSPierre Pronchery        const char *request_end = "\r\n\r\n";
224*e7be843bSPierre Pronchery        size_t written;
225*e7be843bSPierre Pronchery
226*e7be843bSPierre Pronchery        if (!SSL_write_ex(stream, request_start, strlen(request_start), &written))
227*e7be843bSPierre Pronchery            return 0;
228*e7be843bSPierre Pronchery        if (!SSL_write_ex(stream, hostname, strlen(hostname), &written))
229*e7be843bSPierre Pronchery            return 0;
230*e7be843bSPierre Pronchery        if (!SSL_write_ex(stream, request_end, strlen(request_end), &written))
231*e7be843bSPierre Pronchery            return 0;
232*e7be843bSPierre Pronchery
233*e7be843bSPierre Pronchery        return 1;
234*e7be843bSPierre Pronchery    }
235*e7be843bSPierre Pronchery
236*e7be843bSPierre ProncheryWe assume the strings B<request1_start> and B<request2_start> hold the
237*e7be843bSPierre Proncheryappropriate HTTP requests. We can then call our helper function above to send
238*e7be843bSPierre Proncherythe requests on the two streams. For the sake of simplicity this example does
239*e7be843bSPierre Proncherythis sequentially, writing to B<stream1> first and, when this is successful,
240*e7be843bSPierre Proncherywriting to B<stream2> second. Remember that our client is blocking so these
241*e7be843bSPierre Proncherycalls will only return once they have been successfully completed. A real
242*e7be843bSPierre Proncheryapplication would not need to do these writes sequentially or in any particular
243*e7be843bSPierre Proncheryorder. For example we could start two threads (one for each stream) and write
244*e7be843bSPierre Proncherythe requests to each stream simultaneously.
245*e7be843bSPierre Pronchery
246*e7be843bSPierre Pronchery    /* Write an HTTP GET request on each of our streams to the peer */
247*e7be843bSPierre Pronchery    if (!write_a_request(stream1, request1_start, hostname)) {
248*e7be843bSPierre Pronchery        printf("Failed to write HTTP request on stream 1\n");
249*e7be843bSPierre Pronchery        goto end;
250*e7be843bSPierre Pronchery    }
251*e7be843bSPierre Pronchery
252*e7be843bSPierre Pronchery    if (!write_a_request(stream2, request2_start, hostname)) {
253*e7be843bSPierre Pronchery        printf("Failed to write HTTP request on stream 2\n");
254*e7be843bSPierre Pronchery        goto end;
255*e7be843bSPierre Pronchery    }
256*e7be843bSPierre Pronchery
257*e7be843bSPierre Pronchery=head2 Reading data from a stream
258*e7be843bSPierre Pronchery
259*e7be843bSPierre ProncheryIn this example B<stream1> is a bi-directional stream so, once we have sent the
260*e7be843bSPierre Proncheryrequest on it, we can attempt to read the response from the server back. Here
261*e7be843bSPierre Proncherywe just repeatedly call L<SSL_read_ex(3)> until that function fails (indicating
262*e7be843bSPierre Proncheryeither that there has been a problem, or that the peer has signalled the stream
263*e7be843bSPierre Proncheryas concluded).
264*e7be843bSPierre Pronchery
265*e7be843bSPierre Pronchery    printf("Stream 1 data:\n");
266*e7be843bSPierre Pronchery    /*
267*e7be843bSPierre Pronchery     * Get up to sizeof(buf) bytes of the response from stream 1 (which is a
268*e7be843bSPierre Pronchery     * bidirectional stream). We keep reading until the server closes the
269*e7be843bSPierre Pronchery     * connection.
270*e7be843bSPierre Pronchery     */
271*e7be843bSPierre Pronchery    while (SSL_read_ex(stream1, buf, sizeof(buf), &readbytes)) {
272*e7be843bSPierre Pronchery        /*
273*e7be843bSPierre Pronchery        * OpenSSL does not guarantee that the returned data is a string or
274*e7be843bSPierre Pronchery        * that it is NUL terminated so we use fwrite() to write the exact
275*e7be843bSPierre Pronchery        * number of bytes that we read. The data could be non-printable or
276*e7be843bSPierre Pronchery        * have NUL characters in the middle of it. For this simple example
277*e7be843bSPierre Pronchery        * we're going to print it to stdout anyway.
278*e7be843bSPierre Pronchery        */
279*e7be843bSPierre Pronchery        fwrite(buf, 1, readbytes, stdout);
280*e7be843bSPierre Pronchery    }
281*e7be843bSPierre Pronchery    /* In case the response didn't finish with a newline we add one now */
282*e7be843bSPierre Pronchery    printf("\n");
283*e7be843bSPierre Pronchery
284*e7be843bSPierre ProncheryIn a blocking application like this one calls to L<SSL_read_ex(3)> will either
285*e7be843bSPierre Proncherysucceed immediately returning data that is already available, or they will block
286*e7be843bSPierre Proncherywaiting for more data to become available and return it when it is, or they will
287*e7be843bSPierre Proncheryfail with a 0 response code.
288*e7be843bSPierre Pronchery
289*e7be843bSPierre ProncheryOnce we exit the while loop above we know that the last call to
290*e7be843bSPierre ProncheryL<SSL_read_ex(3)> gave a 0 response code so we call the L<SSL_get_error(3)>
291*e7be843bSPierre Proncheryfunction to find out more details. Since this is a blocking application this
292*e7be843bSPierre Proncherywill either return B<SSL_ERROR_SYSCALL> or B<SSL_ERROR_SSL> indicating a
293*e7be843bSPierre Proncheryfundamental problem, or it will return B<SSL_ERROR_ZERO_RETURN> indicating that
294*e7be843bSPierre Proncherythe stream is concluded and there will be no more data available to read from
295*e7be843bSPierre Proncheryit. Care must be taken to distinguish between an error at the stream level (i.e.
296*e7be843bSPierre Proncherya stream reset) and an error at the connection level (i.e. a connection closed).
297*e7be843bSPierre ProncheryThe L<SSL_get_stream_read_state(3)> function can be used to distinguish between
298*e7be843bSPierre Proncherythese different cases.
299*e7be843bSPierre Pronchery
300*e7be843bSPierre Pronchery    /*
301*e7be843bSPierre Pronchery     * Check whether we finished the while loop above normally or as the
302*e7be843bSPierre Pronchery     * result of an error. The 0 argument to SSL_get_error() is the return
303*e7be843bSPierre Pronchery     * code we received from the SSL_read_ex() call. It must be 0 in order
304*e7be843bSPierre Pronchery     * to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN. In
305*e7be843bSPierre Pronchery     * QUIC terms this means that the peer has sent FIN on the stream to
306*e7be843bSPierre Pronchery     * indicate that no further data will be sent.
307*e7be843bSPierre Pronchery     */
308*e7be843bSPierre Pronchery    switch (SSL_get_error(stream1, 0)) {
309*e7be843bSPierre Pronchery    case SSL_ERROR_ZERO_RETURN:
310*e7be843bSPierre Pronchery        /* Normal completion of the stream */
311*e7be843bSPierre Pronchery        break;
312*e7be843bSPierre Pronchery
313*e7be843bSPierre Pronchery    case SSL_ERROR_SSL:
314*e7be843bSPierre Pronchery        /*
315*e7be843bSPierre Pronchery         * Some stream fatal error occurred. This could be because of a stream
316*e7be843bSPierre Pronchery         * reset - or some failure occurred on the underlying connection.
317*e7be843bSPierre Pronchery         */
318*e7be843bSPierre Pronchery        switch (SSL_get_stream_read_state(stream1)) {
319*e7be843bSPierre Pronchery        case SSL_STREAM_STATE_RESET_REMOTE:
320*e7be843bSPierre Pronchery            printf("Stream reset occurred\n");
321*e7be843bSPierre Pronchery            /* The stream has been reset but the connection is still healthy. */
322*e7be843bSPierre Pronchery            break;
323*e7be843bSPierre Pronchery
324*e7be843bSPierre Pronchery        case SSL_STREAM_STATE_CONN_CLOSED:
325*e7be843bSPierre Pronchery            printf("Connection closed\n");
326*e7be843bSPierre Pronchery            /* Connection is already closed. Skip SSL_shutdown() */
327*e7be843bSPierre Pronchery            goto end;
328*e7be843bSPierre Pronchery
329*e7be843bSPierre Pronchery        default:
330*e7be843bSPierre Pronchery            printf("Unknown stream failure\n");
331*e7be843bSPierre Pronchery            break;
332*e7be843bSPierre Pronchery        }
333*e7be843bSPierre Pronchery        break;
334*e7be843bSPierre Pronchery
335*e7be843bSPierre Pronchery    default:
336*e7be843bSPierre Pronchery        /* Some other unexpected error occurred */
337*e7be843bSPierre Pronchery        printf ("Failed reading remaining data\n");
338*e7be843bSPierre Pronchery        break;
339*e7be843bSPierre Pronchery    }
340*e7be843bSPierre Pronchery
341*e7be843bSPierre Pronchery=head2 Accepting an incoming stream
342*e7be843bSPierre Pronchery
343*e7be843bSPierre ProncheryOur B<stream2> object that we created above was a uni-directional stream so it
344*e7be843bSPierre Proncherycannot be used to receive data from the server. In this hypothetical example
345*e7be843bSPierre Proncherywe assume that the server initiates a new stream to send us back the data that
346*e7be843bSPierre Proncherywe requested. To do that we call L<SSL_accept_stream(3)>. Since this is a
347*e7be843bSPierre Proncheryblocking application this will wait indefinitely until the new stream has
348*e7be843bSPierre Proncheryarrived and is available for us to accept. In the event of an error it will
349*e7be843bSPierre Proncheryreturn B<NULL>.
350*e7be843bSPierre Pronchery
351*e7be843bSPierre Pronchery    /*
352*e7be843bSPierre Pronchery     * In our hypothetical HTTP/1.0 over QUIC protocol that we are using we
353*e7be843bSPierre Pronchery     * assume that the server will respond with a server initiated stream
354*e7be843bSPierre Pronchery     * containing the data requested in our uni-directional stream. This doesn't
355*e7be843bSPierre Pronchery     * really make sense to do in a real protocol, but its just for
356*e7be843bSPierre Pronchery     * demonstration purposes.
357*e7be843bSPierre Pronchery     *
358*e7be843bSPierre Pronchery     * We're using blocking mode so this will block until a stream becomes
359*e7be843bSPierre Pronchery     * available. We could override this behaviour if we wanted to by setting
360*e7be843bSPierre Pronchery     * the SSL_ACCEPT_STREAM_NO_BLOCK flag in the second argument below.
361*e7be843bSPierre Pronchery     */
362*e7be843bSPierre Pronchery    stream3 = SSL_accept_stream(ssl, 0);
363*e7be843bSPierre Pronchery    if (stream3 == NULL) {
364*e7be843bSPierre Pronchery        printf("Failed to accept a new stream\n");
365*e7be843bSPierre Pronchery        goto end;
366*e7be843bSPierre Pronchery    }
367*e7be843bSPierre Pronchery
368*e7be843bSPierre ProncheryWe can now read data from the stream in the same way that we did for B<stream1>
369*e7be843bSPierre Proncheryabove. We won't repeat that here.
370*e7be843bSPierre Pronchery
371*e7be843bSPierre Pronchery=head2 Cleaning up the streams
372*e7be843bSPierre Pronchery
373*e7be843bSPierre ProncheryOnce we have finished using our streams we can simply free them by calling
374*e7be843bSPierre ProncheryL<SSL_free(3)>. Optionally we could call L<SSL_stream_conclude(3)> on them if
375*e7be843bSPierre Proncherywe want to indicate to the peer that we won't be sending them any more data, but
376*e7be843bSPierre Proncherywe don't do that in this example because we assume that the HTTP application
377*e7be843bSPierre Proncheryprotocol supplies sufficient information for the peer to know when we have
378*e7be843bSPierre Proncheryfinished sending request data.
379*e7be843bSPierre Pronchery
380*e7be843bSPierre ProncheryWe should not call L<SSL_shutdown(3)> or L<SSL_shutdown_ex(3)> on the stream
381*e7be843bSPierre Proncheryobjects since those calls should not be used for streams.
382*e7be843bSPierre Pronchery
383*e7be843bSPierre Pronchery    SSL_free(stream1);
384*e7be843bSPierre Pronchery    SSL_free(stream2);
385*e7be843bSPierre Pronchery    SSL_free(stream3);
386*e7be843bSPierre Pronchery
387*e7be843bSPierre Pronchery=head1 SEE ALSO
388*e7be843bSPierre Pronchery
389*e7be843bSPierre ProncheryL<ossl-guide-introduction(7)>, L<ossl-guide-libraries-introduction(7)>,
390*e7be843bSPierre ProncheryL<ossl-guide-libssl-introduction(7)> L<ossl-guide-quic-introduction(7)>,
391*e7be843bSPierre ProncheryL<ossl-guide-quic-client-block(7)>
392*e7be843bSPierre Pronchery
393*e7be843bSPierre Pronchery=head1 COPYRIGHT
394*e7be843bSPierre Pronchery
395*e7be843bSPierre ProncheryCopyright 2023 The OpenSSL Project Authors. All Rights Reserved.
396*e7be843bSPierre Pronchery
397*e7be843bSPierre ProncheryLicensed under the Apache License 2.0 (the "License").  You may not use
398*e7be843bSPierre Proncherythis file except in compliance with the License.  You can obtain a copy
399*e7be843bSPierre Proncheryin the file LICENSE in the source distribution or at
400*e7be843bSPierre ProncheryL<https://www.openssl.org/source/license.html>.
401*e7be843bSPierre Pronchery
402*e7be843bSPierre Pronchery=cut
403