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