ossl-guide-quic-multi-stream.7ossl 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. .\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42)
  2. .\"
  3. .\" Standard preamble:
  4. .\" ========================================================================
  5. .de Sp \" Vertical space (when we can't use .PP)
  6. .if t .sp .5v
  7. .if n .sp
  8. ..
  9. .de Vb \" Begin verbatim text
  10. .ft CW
  11. .nf
  12. .ne \\$1
  13. ..
  14. .de Ve \" End verbatim text
  15. .ft R
  16. .fi
  17. ..
  18. .\" Set up some character translations and predefined strings. \*(-- will
  19. .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
  20. .\" double quote, and \*(R" will give a right double quote. \*(C+ will
  21. .\" give a nicer C++. Capital omega is used to do unbreakable dashes and
  22. .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
  23. .\" nothing in troff, for use with C<>.
  24. .tr \(*W-
  25. .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
  26. .ie n \{\
  27. . ds -- \(*W-
  28. . ds PI pi
  29. . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
  30. . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
  31. . ds L" ""
  32. . ds R" ""
  33. . ds C` ""
  34. . ds C' ""
  35. 'br\}
  36. .el\{\
  37. . ds -- \|\(em\|
  38. . ds PI \(*p
  39. . ds L" ``
  40. . ds R" ''
  41. . ds C`
  42. . ds C'
  43. 'br\}
  44. .\"
  45. .\" Escape single quotes in literal strings from groff's Unicode transform.
  46. .ie \n(.g .ds Aq \(aq
  47. .el .ds Aq '
  48. .\"
  49. .\" If the F register is >0, we'll generate index entries on stderr for
  50. .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
  51. .\" entries marked with X<> in POD. Of course, you'll have to process the
  52. .\" output yourself in some meaningful fashion.
  53. .\"
  54. .\" Avoid warning from groff about undefined register 'F'.
  55. .de IX
  56. ..
  57. .nr rF 0
  58. .if \n(.g .if rF .nr rF 1
  59. .if (\n(rF:(\n(.g==0)) \{\
  60. . if \nF \{\
  61. . de IX
  62. . tm Index:\\$1\t\\n%\t"\\$2"
  63. ..
  64. . if !\nF==2 \{\
  65. . nr % 0
  66. . nr F 2
  67. . \}
  68. . \}
  69. .\}
  70. .rr rF
  71. .\"
  72. .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
  73. .\" Fear. Run. Save yourself. No user-serviceable parts.
  74. . \" fudge factors for nroff and troff
  75. .if n \{\
  76. . ds #H 0
  77. . ds #V .8m
  78. . ds #F .3m
  79. . ds #[ \f1
  80. . ds #] \fP
  81. .\}
  82. .if t \{\
  83. . ds #H ((1u-(\\\\n(.fu%2u))*.13m)
  84. . ds #V .6m
  85. . ds #F 0
  86. . ds #[ \&
  87. . ds #] \&
  88. .\}
  89. . \" simple accents for nroff and troff
  90. .if n \{\
  91. . ds ' \&
  92. . ds ` \&
  93. . ds ^ \&
  94. . ds , \&
  95. . ds ~ ~
  96. . ds /
  97. .\}
  98. .if t \{\
  99. . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
  100. . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
  101. . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
  102. . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
  103. . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
  104. . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
  105. .\}
  106. . \" troff and (daisy-wheel) nroff accents
  107. .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
  108. .ds 8 \h'\*(#H'\(*b\h'-\*(#H'
  109. .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
  110. .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
  111. .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
  112. .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
  113. .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
  114. .ds ae a\h'-(\w'a'u*4/10)'e
  115. .ds Ae A\h'-(\w'A'u*4/10)'E
  116. . \" corrections for vroff
  117. .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
  118. .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
  119. . \" for low resolution devices (crt and lpr)
  120. .if \n(.H>23 .if \n(.V>19 \
  121. \{\
  122. . ds : e
  123. . ds 8 ss
  124. . ds o a
  125. . ds d- d\h'-1'\(ga
  126. . ds D- D\h'-1'\(hy
  127. . ds th \o'bp'
  128. . ds Th \o'LP'
  129. . ds ae ae
  130. . ds Ae AE
  131. .\}
  132. .rm #[ #] #H #V #F C
  133. .\" ========================================================================
  134. .\"
  135. .IX Title "OSSL-GUIDE-QUIC-MULTI-STREAM 7ossl"
  136. .TH OSSL-GUIDE-QUIC-MULTI-STREAM 7ossl "2024-09-03" "3.3.2" "OpenSSL"
  137. .\" For nroff, turn off justification. Always turn off hyphenation; it makes
  138. .\" way too many mistakes in technical documents.
  139. .if n .ad l
  140. .nh
  141. .SH "NAME"
  142. ossl\-guide\-quic\-multi\-stream
  143. \&\- OpenSSL Guide: Writing a simple multi\-stream QUIC client
  144. .SH "INTRODUCTION"
  145. .IX Header "INTRODUCTION"
  146. This page will introduce some important concepts required to write a simple
  147. \&\s-1QUIC\s0 multi-stream application. It assumes a basic understanding of \s-1QUIC\s0 and how
  148. it is used in OpenSSL. See \fBossl\-guide\-quic\-introduction\fR\|(7) and
  149. \&\fBossl\-guide\-quic\-client\-block\fR\|(7).
  150. .SH "QUIC STREAMS"
  151. .IX Header "QUIC STREAMS"
  152. In a \s-1QUIC\s0 multi-stream application we separate out the concepts of a \s-1QUIC\s0
  153. \&\*(L"connection\*(R" and a \s-1QUIC\s0 \*(L"stream\*(R". A connection object represents the overarching
  154. details of the connection between a client and a server including all its
  155. negotiated and configured parameters. We use the \fB\s-1SSL\s0\fR object for that in an
  156. OpenSSL application (known as the connection \fB\s-1SSL\s0\fR object). It is created by an
  157. application calling \fBSSL_new\fR\|(3).
  158. .PP
  159. Separately a connection can have zero or more streams associated with it
  160. (although a connection with zero streams is probably not very useful, so
  161. normally you would have at least one). A stream is used to send and receive
  162. data between the two peers. Each stream is also represented by an \fB\s-1SSL\s0\fR
  163. object. A stream is logically independent of all the other streams associated
  164. with the same connection. Data sent on a stream is guaranteed to be delivered
  165. in the order that it was sent within that stream. The same is not true across
  166. streams, e.g. if an application sends data on stream 1 first and then sends some
  167. more data on stream 2 second, then the remote peer may receive the data sent on
  168. stream 2 before it receives the data sent on stream 1.
  169. .PP
  170. Once the connection \fB\s-1SSL\s0\fR object has completed its handshake (i.e.
  171. \&\fBSSL_connect\fR\|(3) has returned 1), stream \fB\s-1SSL\s0\fR objects are created by the
  172. application calling \fBSSL_new_stream\fR\|(3) or \fBSSL_accept_stream\fR\|(3) (see
  173. \&\*(L"\s-1CREATING NEW STREAMS\*(R"\s0 below).
  174. .PP
  175. The same threading rules apply to \fB\s-1SSL\s0\fR objects as for most OpenSSL objects
  176. (see \fBossl\-guide\-libraries\-introduction\fR\|(7)). In particular most OpenSSL
  177. functions are thread safe, but the \fB\s-1SSL\s0\fR object is not. This means that you can
  178. use an \fB\s-1SSL\s0\fR object representing one stream at the same time as another thread
  179. is using a different \fB\s-1SSL\s0\fR object for a different stream on the same
  180. connection. But you cannot use the same \fB\s-1SSL\s0\fR object on two different threads
  181. at the same time (without additional application level locking).
  182. .SH "THE DEFAULT STREAM"
  183. .IX Header "THE DEFAULT STREAM"
  184. A connection \fB\s-1SSL\s0\fR object may also (optionally) be associated with a stream.
  185. This stream is known as the default stream. The default stream is automatically
  186. created and associated with the \fB\s-1SSL\s0\fR object when the application calls
  187. \&\fBSSL_read_ex\fR\|(3), \fBSSL_read\fR\|(3), \fBSSL_write_ex\fR\|(3) or \fBSSL_write\fR\|(3) and
  188. passes the connection \fB\s-1SSL\s0\fR object as a parameter.
  189. .PP
  190. If a client application calls \fBSSL_write_ex\fR\|(3) or \fBSSL_write\fR\|(3) first then
  191. (by default) the default stream will be a client-initiated bi-directional
  192. stream. If a client application calls \fBSSL_read_ex\fR\|(3) or \fBSSL_read\fR\|(3)
  193. first then the first stream initiated by the server will be used as the default
  194. stream (whether it is bi-directional or uni-directional).
  195. .PP
  196. This behaviour can be controlled via the default stream mode. See
  197. \&\fBSSL_set_default_stream_mode\fR\|(3) for further details.
  198. .PP
  199. It is recommended that new multi-stream applications should not use a default
  200. stream at all and instead should use a separate stream \fB\s-1SSL\s0\fR object for each
  201. stream that is used. This requires calling \fBSSL_set_default_stream_mode\fR\|(3)
  202. and setting the mode to \fB\s-1SSL_DEFAULT_STREAM_MODE_NONE\s0\fR.
  203. .SH "CREATING NEW STREAMS"
  204. .IX Header "CREATING NEW STREAMS"
  205. An endpoint can create a new stream by calling \fBSSL_new_stream\fR\|(3). This
  206. creates a locally initiated stream. In order to do so you must pass the \s-1QUIC\s0
  207. connection \fB\s-1SSL\s0\fR object as a parameter. You can also specify whether you want a
  208. bi-directional or a uni-directional stream.
  209. .PP
  210. The function returns a new \s-1QUIC\s0 stream \fB\s-1SSL\s0\fR object for sending and receiving
  211. data on that stream.
  212. .PP
  213. The peer may also initiate streams. An application can use the function
  214. \&\fBSSL_get_accept_stream_queue_len\fR\|(3) to determine the number of streams that
  215. the peer has initiated that are waiting for the application to handle. An
  216. application can call \fBSSL_accept_stream\fR\|(3) to create a new \fB\s-1SSL\s0\fR object for
  217. a remotely initiated stream. If the peer has not initiated any then this call
  218. will block until one is available if the connection object is in blocking mode
  219. (see \fBSSL_set_blocking_mode\fR\|(3)).
  220. .PP
  221. When using a default stream OpenSSL will prevent new streams from being
  222. accepted. To override this behaviour you must call
  223. \&\fBSSL_set_incoming_stream_policy\fR\|(3) to set the policy to
  224. \&\fB\s-1SSL_INCOMING_STREAM_POLICY_ACCEPT\s0\fR. See the man page for further details. This
  225. is not relevant if the default stream has been disabled as described in
  226. \&\*(L"\s-1THE DEFAULT STREAM\*(R"\s0 above.
  227. .PP
  228. Any stream may be bi-directional or uni-directional. If it is uni-directional
  229. then the initiator can write to it but not read from it, and vice-versa for the
  230. peer. You can determine what type of stream an \fB\s-1SSL\s0\fR object represents by
  231. calling \fBSSL_get_stream_type\fR\|(3). See the man page for further details.
  232. .SH "USING A STREAM TO SEND AND RECEIVE DATA"
  233. .IX Header "USING A STREAM TO SEND AND RECEIVE DATA"
  234. Once you have a stream \fB\s-1SSL\s0\fR object (which includes the connection \fB\s-1SSL\s0\fR
  235. object if a default stream is in use) then you can send and receive data over it
  236. using the \fBSSL_write_ex\fR\|(3), \fBSSL_write\fR\|(3), \fBSSL_read_ex\fR\|(3) or
  237. \&\fBSSL_read\fR\|(3) functions. See the man pages for further details.
  238. .PP
  239. In the event of one of these functions not returning a success code then
  240. you should call \fBSSL_get_error\fR\|(3) to find out further details about the error.
  241. In blocking mode this will either be a fatal error (e.g. \fB\s-1SSL_ERROR_SYSCALL\s0\fR
  242. or \fB\s-1SSL_ERROR_SSL\s0\fR), or it will be \fB\s-1SSL_ERROR_ZERO_RETURN\s0\fR which can occur
  243. when attempting to read data from a stream and the peer has indicated that the
  244. stream is concluded (i.e. \*(L"\s-1FIN\*(R"\s0 has been signalled on the stream). This means
  245. that the peer will send no more data on that stream. Note that the
  246. interpretation of \fB\s-1SSL_ERROR_ZERO_RETURN\s0\fR is slightly different for a \s-1QUIC\s0
  247. application compared to a \s-1TLS\s0 application. In \s-1TLS\s0 it occurs when the connection
  248. has been shutdown by the peer. In \s-1QUIC\s0 this only tells you that the current
  249. stream has been concluded by the peer. It tells you nothing about the underlying
  250. connection. If the peer has concluded the stream then no more data will be
  251. received on it, however an application can still send data to the peer until
  252. the send side of the stream has also been concluded. This can happen by the
  253. application calling \fBSSL_stream_conclude\fR\|(3). It is an error to attempt to
  254. send more data on a stream after \fBSSL_stream_conclude\fR\|(3) has been called.
  255. .PP
  256. It is also possible to abandon a stream abnormally by calling
  257. \&\fBSSL_stream_reset\fR\|(3).
  258. .PP
  259. Once a stream object is no longer needed it should be freed via a call to
  260. \&\fBSSL_free\fR\|(3). An application should not call \fBSSL_shutdown\fR\|(3) on it since
  261. this is only meaningful for connection level \fB\s-1SSL\s0\fR objects. Freeing the stream
  262. will automatically signal \s-1STOP_SENDING\s0 to the peer.
  263. .SH "STREAMS AND CONNECTIONS"
  264. .IX Header "STREAMS AND CONNECTIONS"
  265. Given a stream object it is possible to get the \fB\s-1SSL\s0\fR object corresponding to
  266. the connection via a call to \fBSSL_get0_connection\fR\|(3). Multi-threaded
  267. restrictions apply so care should be taken when using the returned connection
  268. object. Specifically, if you are handling each of your stream objects in a
  269. different thread and call \fBSSL_get0_connection\fR\|(3) from within that thread then
  270. you must be careful to not to call any function that uses the connection object
  271. at the same time as one of the other threads is also using that connection
  272. object (with the exception of \fBSSL_accept_stream\fR\|(3) and
  273. \&\fBSSL_get_accept_stream_queue_len\fR\|(3) which are thread-safe).
  274. .PP
  275. A stream object does not inherit all its settings and values from its parent
  276. \&\fB\s-1SSL\s0\fR connection object. Therefore certain function calls that are relevant to
  277. the connection as a whole will not work on a stream. For example the function
  278. \&\fBSSL_get_certificate\fR\|(3) can be used to obtain a handle on the peer certificate
  279. when called with a connection \fB\s-1SSL\s0\fR object. When called with a stream \fB\s-1SSL\s0\fR
  280. object it will return \s-1NULL.\s0
  281. .SH "SIMPLE MULTI-STREAM QUIC CLIENT EXAMPLE"
  282. .IX Header "SIMPLE MULTI-STREAM QUIC CLIENT EXAMPLE"
  283. This section will present various source code samples demonstrating how to write
  284. a simple multi-stream \s-1QUIC\s0 client application which connects to a server, send
  285. some \s-1HTTP/1.0\s0 requests to it, and read back the responses. Note that \s-1HTTP/1.0\s0
  286. over \s-1QUIC\s0 is non-standard and will not be supported by real world servers. This
  287. is for demonstration purposes only.
  288. .PP
  289. We will build on the example code for the simple blocking \s-1QUIC\s0 client that is
  290. covered on the \fBossl\-guide\-quic\-client\-block\fR\|(7) page and we assume that you
  291. are familiar with it. We will only describe the differences between the simple
  292. blocking \s-1QUIC\s0 client and the multi-stream \s-1QUIC\s0 client. Although the example code
  293. uses blocking \fB\s-1SSL\s0\fR objects, you can equally use nonblocking \fB\s-1SSL\s0\fR objects.
  294. See \fBossl\-guide\-quic\-client\-non\-block\fR\|(7) for more information about writing a
  295. nonblocking \s-1QUIC\s0 client.
  296. .PP
  297. The complete source code for this example multi-stream \s-1QUIC\s0 client is available
  298. in the \f(CW\*(C`demos/guide\*(C'\fR directory of the OpenSSL source distribution in the file
  299. \&\f(CW\*(C`quic\-multi\-stream.c\*(C'\fR. It is also available online at
  300. <https://github.com/openssl/openssl/blob/master/demos/guide/quic\-multi\-stream.c>.
  301. .SS "Disabling the default stream"
  302. .IX Subsection "Disabling the default stream"
  303. As discussed above in \*(L"\s-1THE DEFAULT STREAM\*(R"\s0 we will follow the recommendation
  304. to disable the default stream for our multi-stream client. To do this we call
  305. the \fBSSL_set_default_stream_mode\fR\|(3) function and pass in our connection \fB\s-1SSL\s0\fR
  306. object and the value \fB\s-1SSL_DEFAULT_STREAM_MODE_NONE\s0\fR.
  307. .PP
  308. .Vb 8
  309. \& /*
  310. \& * We will use multiple streams so we will disable the default stream mode.
  311. \& * This is not a requirement for using multiple streams but is recommended.
  312. \& */
  313. \& if (!SSL_set_default_stream_mode(ssl, SSL_DEFAULT_STREAM_MODE_NONE)) {
  314. \& printf("Failed to disable the default stream mode\en");
  315. \& goto end;
  316. \& }
  317. .Ve
  318. .SS "Creating the request streams"
  319. .IX Subsection "Creating the request streams"
  320. For the purposes of this example we will create two different streams to send
  321. two different \s-1HTTP\s0 requests to the server. For the purposes of demonstration the
  322. first of these will be a bi-directional stream and the second one will be a
  323. uni-directional one:
  324. .PP
  325. .Vb 10
  326. \& /*
  327. \& * We create two new client initiated streams. The first will be
  328. \& * bi\-directional, and the second will be uni\-directional.
  329. \& */
  330. \& stream1 = SSL_new_stream(ssl, 0);
  331. \& stream2 = SSL_new_stream(ssl, SSL_STREAM_FLAG_UNI);
  332. \& if (stream1 == NULL || stream2 == NULL) {
  333. \& printf("Failed to create streams\en");
  334. \& goto end;
  335. \& }
  336. .Ve
  337. .SS "Writing data to the streams"
  338. .IX Subsection "Writing data to the streams"
  339. Once the streams are successfully created we can start writing data to them. In
  340. this example we will be sending a different \s-1HTTP\s0 request on each stream. To
  341. avoid repeating too much code we write a simple helper function to send an \s-1HTTP\s0
  342. request to a stream:
  343. .PP
  344. .Vb 5
  345. \& int write_a_request(SSL *stream, const char *request_start,
  346. \& const char *hostname)
  347. \& {
  348. \& const char *request_end = "\er\en\er\en";
  349. \& size_t written;
  350. \&
  351. \& if (!SSL_write_ex(stream, request_start, strlen(request_start), &written))
  352. \& return 0;
  353. \& if (!SSL_write_ex(stream, hostname, strlen(hostname), &written))
  354. \& return 0;
  355. \& if (!SSL_write_ex(stream, request_end, strlen(request_end), &written))
  356. \& return 0;
  357. \&
  358. \& return 1;
  359. \& }
  360. .Ve
  361. .PP
  362. We assume the strings \fBrequest1_start\fR and \fBrequest2_start\fR hold the
  363. appropriate \s-1HTTP\s0 requests. We can then call our helper function above to send
  364. the requests on the two streams. For the sake of simplicity this example does
  365. this sequentially, writing to \fBstream1\fR first and, when this is successful,
  366. writing to \fBstream2\fR second. Remember that our client is blocking so these
  367. calls will only return once they have been successfully completed. A real
  368. application would not need to do these writes sequentially or in any particular
  369. order. For example we could start two threads (one for each stream) and write
  370. the requests to each stream simultaneously.
  371. .PP
  372. .Vb 5
  373. \& /* Write an HTTP GET request on each of our streams to the peer */
  374. \& if (!write_a_request(stream1, request1_start, hostname)) {
  375. \& printf("Failed to write HTTP request on stream 1\en");
  376. \& goto end;
  377. \& }
  378. \&
  379. \& if (!write_a_request(stream2, request2_start, hostname)) {
  380. \& printf("Failed to write HTTP request on stream 2\en");
  381. \& goto end;
  382. \& }
  383. .Ve
  384. .SS "Reading data from a stream"
  385. .IX Subsection "Reading data from a stream"
  386. In this example \fBstream1\fR is a bi-directional stream so, once we have sent the
  387. request on it, we can attempt to read the response from the server back. Here
  388. we just repeatedly call \fBSSL_read_ex\fR\|(3) until that function fails (indicating
  389. either that there has been a problem, or that the peer has signalled the stream
  390. as concluded).
  391. .PP
  392. .Vb 10
  393. \& printf("Stream 1 data:\en");
  394. \& /*
  395. \& * Get up to sizeof(buf) bytes of the response from stream 1 (which is a
  396. \& * bidirectional stream). We keep reading until the server closes the
  397. \& * connection.
  398. \& */
  399. \& while (SSL_read_ex(stream1, buf, sizeof(buf), &readbytes)) {
  400. \& /*
  401. \& * OpenSSL does not guarantee that the returned data is a string or
  402. \& * that it is NUL terminated so we use fwrite() to write the exact
  403. \& * number of bytes that we read. The data could be non\-printable or
  404. \& * have NUL characters in the middle of it. For this simple example
  405. \& * we\*(Aqre going to print it to stdout anyway.
  406. \& */
  407. \& fwrite(buf, 1, readbytes, stdout);
  408. \& }
  409. \& /* In case the response didn\*(Aqt finish with a newline we add one now */
  410. \& printf("\en");
  411. .Ve
  412. .PP
  413. In a blocking application like this one calls to \fBSSL_read_ex\fR\|(3) will either
  414. succeed immediately returning data that is already available, or they will block
  415. waiting for more data to become available and return it when it is, or they will
  416. fail with a 0 response code.
  417. .PP
  418. Once we exit the while loop above we know that the last call to
  419. \&\fBSSL_read_ex\fR\|(3) gave a 0 response code so we call the \fBSSL_get_error\fR\|(3)
  420. function to find out more details. Since this is a blocking application this
  421. will either return \fB\s-1SSL_ERROR_SYSCALL\s0\fR or \fB\s-1SSL_ERROR_SSL\s0\fR indicating a
  422. fundamental problem, or it will return \fB\s-1SSL_ERROR_ZERO_RETURN\s0\fR indicating that
  423. the stream is concluded and there will be no more data available to read from
  424. it. Care must be taken to distinguish between an error at the stream level (i.e.
  425. a stream reset) and an error at the connection level (i.e. a connection closed).
  426. The \fBSSL_get_stream_read_state\fR\|(3) function can be used to distinguish between
  427. these different cases.
  428. .PP
  429. .Vb 12
  430. \& /*
  431. \& * Check whether we finished the while loop above normally or as the
  432. \& * result of an error. The 0 argument to SSL_get_error() is the return
  433. \& * code we received from the SSL_read_ex() call. It must be 0 in order
  434. \& * to get here. Normal completion is indicated by SSL_ERROR_ZERO_RETURN. In
  435. \& * QUIC terms this means that the peer has sent FIN on the stream to
  436. \& * indicate that no further data will be sent.
  437. \& */
  438. \& switch (SSL_get_error(stream1, 0)) {
  439. \& case SSL_ERROR_ZERO_RETURN:
  440. \& /* Normal completion of the stream */
  441. \& break;
  442. \&
  443. \& case SSL_ERROR_SSL:
  444. \& /*
  445. \& * Some stream fatal error occurred. This could be because of a stream
  446. \& * reset \- or some failure occurred on the underlying connection.
  447. \& */
  448. \& switch (SSL_get_stream_read_state(stream1)) {
  449. \& case SSL_STREAM_STATE_RESET_REMOTE:
  450. \& printf("Stream reset occurred\en");
  451. \& /* The stream has been reset but the connection is still healthy. */
  452. \& break;
  453. \&
  454. \& case SSL_STREAM_STATE_CONN_CLOSED:
  455. \& printf("Connection closed\en");
  456. \& /* Connection is already closed. Skip SSL_shutdown() */
  457. \& goto end;
  458. \&
  459. \& default:
  460. \& printf("Unknown stream failure\en");
  461. \& break;
  462. \& }
  463. \& break;
  464. \&
  465. \& default:
  466. \& /* Some other unexpected error occurred */
  467. \& printf ("Failed reading remaining data\en");
  468. \& break;
  469. \& }
  470. .Ve
  471. .SS "Accepting an incoming stream"
  472. .IX Subsection "Accepting an incoming stream"
  473. Our \fBstream2\fR object that we created above was a uni-directional stream so it
  474. cannot be used to receive data from the server. In this hypothetical example
  475. we assume that the server initiates a new stream to send us back the data that
  476. we requested. To do that we call \fBSSL_accept_stream\fR\|(3). Since this is a
  477. blocking application this will wait indefinitely until the new stream has
  478. arrived and is available for us to accept. In the event of an error it will
  479. return \fB\s-1NULL\s0\fR.
  480. .PP
  481. .Vb 10
  482. \& /*
  483. \& * In our hypothetical HTTP/1.0 over QUIC protocol that we are using we
  484. \& * assume that the server will respond with a server initiated stream
  485. \& * containing the data requested in our uni\-directional stream. This doesn\*(Aqt
  486. \& * really make sense to do in a real protocol, but its just for
  487. \& * demonstration purposes.
  488. \& *
  489. \& * We\*(Aqre using blocking mode so this will block until a stream becomes
  490. \& * available. We could override this behaviour if we wanted to by setting
  491. \& * the SSL_ACCEPT_STREAM_NO_BLOCK flag in the second argument below.
  492. \& */
  493. \& stream3 = SSL_accept_stream(ssl, 0);
  494. \& if (stream3 == NULL) {
  495. \& printf("Failed to accept a new stream\en");
  496. \& goto end;
  497. \& }
  498. .Ve
  499. .PP
  500. We can now read data from the stream in the same way that we did for \fBstream1\fR
  501. above. We won't repeat that here.
  502. .SS "Cleaning up the streams"
  503. .IX Subsection "Cleaning up the streams"
  504. Once we have finished using our streams we can simply free them by calling
  505. \&\fBSSL_free\fR\|(3). Optionally we could call \fBSSL_stream_conclude\fR\|(3) on them if
  506. we want to indicate to the peer that we won't be sending them any more data, but
  507. we don't do that in this example because we assume that the \s-1HTTP\s0 application
  508. protocol supplies sufficient information for the peer to know when we have
  509. finished sending request data.
  510. .PP
  511. We should not call \fBSSL_shutdown\fR\|(3) or \fBSSL_shutdown_ex\fR\|(3) on the stream
  512. objects since those calls should not be used for streams.
  513. .PP
  514. .Vb 3
  515. \& SSL_free(stream1);
  516. \& SSL_free(stream2);
  517. \& SSL_free(stream3);
  518. .Ve
  519. .SH "SEE ALSO"
  520. .IX Header "SEE ALSO"
  521. \&\fBossl\-guide\-introduction\fR\|(7), \fBossl\-guide\-libraries\-introduction\fR\|(7),
  522. \&\fBossl\-guide\-libssl\-introduction\fR\|(7) \fBossl\-guide\-quic\-introduction\fR\|(7),
  523. \&\fBossl\-guide\-quic\-client\-block\fR\|(7)
  524. .SH "COPYRIGHT"
  525. .IX Header "COPYRIGHT"
  526. Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
  527. .PP
  528. Licensed under the Apache License 2.0 (the \*(L"License\*(R"). You may not use
  529. this file except in compliance with the License. You can obtain a copy
  530. in the file \s-1LICENSE\s0 in the source distribution or at
  531. <https://www.openssl.org/source/license.html>.