1 1.1 christos Report on the Conclusions of the QUIC DDD Process 2 1.1 christos ================================================= 3 1.1 christos 4 1.1 christos The [QUIC Demo-Driven Design process](README.md) was undertaken to meet the OMC 5 1.1 christos requirement to develop a QUIC API that required only minimal changes to existing 6 1.1 christos applications to be able to adapt their code to use QUIC. The demo-driven design 7 1.1 christos process developed a set of representative demos modelling a variety of common 8 1.1 christos OpenSSL usage patterns based on analysis of a broad spectrum of open source 9 1.1 christos software projects using OpenSSL. 10 1.1 christos 11 1.1 christos As part of this process, a set of proposed diffs were produced. These proposed 12 1.1 christos diffs were the expected changes which would be needed to the baseline demos to 13 1.1 christos support QUIC based on theoretical analysis of the minimum requirements to be 14 1.1 christos able to support QUIC. This analysis concluded that the changes needed to 15 1.1 christos applications could be kept very small in many circumstances, with only minimal 16 1.1 christos diff sizes to the baseline demos. 17 1.1 christos 18 1.1 christos Following the development of QUIC MVP, these demos have been revisited and the 19 1.1 christos correspondence of our actual final API and usage patterns with the planned diffs 20 1.1 christos have been reviewed. 21 1.1 christos 22 1.1 christos This document discusses the planned changes and the actual changes for each demo 23 1.1 christos and draws conclusions on the level of disparity. 24 1.1 christos 25 1.1 christos Since tracking a set of diffs separately is unwieldy, both the planned and 26 1.1 christos unplanned changes have been folded into the original baseline demo files guarded 27 1.1 christos with `#ifdef USE_QUIC`. Viewing these files therefore is informative to 28 1.1 christos application writers as it provides a clear view of what is different when using 29 1.1 christos QUIC. (The originally planned changes, and the final changes, are added in 30 1.1 christos separate, clearly-labelled commits; to view the originally planned changes only, 31 1.1 christos view the commit history for a given demo file.) 32 1.1 christos 33 1.1 christos ddd-01-conn-blocking 34 1.1 christos -------------------- 35 1.1 christos 36 1.1 christos This demo exists to demonstrate the simplest possible usage of OpenSSL, whether 37 1.1 christos with TLS or QUIC. 38 1.1 christos 39 1.1 christos ### Originally planned changes 40 1.1 christos 41 1.1 christos The originally planned change to enable applications for QUIC amounted to just a 42 1.1 christos single line: 43 1.1 christos 44 1.1 christos ```diff 45 1.1 christos + ctx = SSL_CTX_new(QUIC_client_method()); 46 1.1 christos - ctx = SSL_CTX_new(TLS_client_method()); 47 1.1 christos ``` 48 1.1 christos 49 1.1 christos ### Actual changes 50 1.1 christos 51 1.1 christos The following additional changes needed to be made: 52 1.1 christos 53 1.1 christos - `QUIC_client_method` was renamed to `OSSL_QUIC_client_method` for namespacing 54 1.1 christos reasons. 55 1.1 christos 56 1.1 christos - A call to `SSL_set_alpn_protos` to configure ALPN was added. This is necessary 57 1.1 christos because QUIC mandates the use of ALPN, and this was not noted during the 58 1.1 christos DDD process. 59 1.1 christos 60 1.1 christos ddd-02-conn-nonblocking 61 1.1 christos ----------------------- 62 1.1 christos 63 1.1 christos This demo exists to demonstrate simple non-blocking usage. As with 64 1.1 christos ddd-01-conn-blocking, the name resolution process is managed by `BIO_s_connect`. 65 1.1 christos 66 1.1 christos It also arbitrarily adds a `BIO_f_buffer` pushed onto the BIO stack 67 1.1 christos as this is a common application usage pattern. 68 1.1 christos 69 1.1 christos ### Originally planned changes 70 1.1 christos 71 1.1 christos The originally planned changes to enable applications for QUIC amounted to: 72 1.1 christos 73 1.1 christos - Change of method (as for ddd-01-conn-blocking); 74 1.1 christos 75 1.1 christos - Use of a `BIO_f_dgram_buffer` BIO method instead of a `BIO_f_buffer`; 76 1.1 christos 77 1.1 christos - Use of a `BIO_get_poll_fd` function to get the FD to poll rather than 78 1.1 christos `BIO_get_fd`; 79 1.1 christos 80 1.1 christos - A change to how the `POLLIN`/`POLLOUT`/`POLLERR` flags to pass to poll(2) 81 1.1 christos need to be determined. 82 1.1 christos 83 1.1 christos - Additional functions in application code to determine event handling 84 1.1 christos timeouts related to QUIC (`get_conn_pump_timeout`) and to pump 85 1.1 christos the QUIC event loop (`pump`). 86 1.1 christos 87 1.1 christos - Timeout computation code which involves merging and comparing different 88 1.1 christos timeouts and calling `pump` as needed, based on deadlines reported 89 1.1 christos by libssl. 90 1.1 christos 91 1.1 christos Note that some of these changes are unnecessary when using the thread assisted 92 1.1 christos mode (see the variant ddd-02-conn-nonblocking-threads below). 93 1.1 christos 94 1.1 christos ### Actual changes 95 1.1 christos 96 1.1 christos The following additional changes needed to be made: 97 1.1 christos 98 1.1 christos - Change of method name (as for ddd-01-conn-blocking); 99 1.1 christos 100 1.1 christos - Use of ALPN (as for ddd-01-conn-blocking); 101 1.1 christos 102 1.1 christos - The strategy for how to expose pollable OS resource handles 103 1.1 christos to applications to determine I/O readiness has changed substantially since the 104 1.1 christos original DDD process. As such, applications now use `BIO_get_rpoll_descriptor` 105 1.1 christos and `BIO_get_wpoll_descriptor` to determine I/O readiness, rather than the 106 1.1 christos originally hypothesised `SSL_get_poll_fd`. 107 1.1 christos 108 1.1 christos - The strategy for how to determine when to poll for `POLLIN`, when to 109 1.1 christos poll for `POLLOUT`, etc. has changed since the original DDD process. 110 1.1 christos This information is now exposed via `SSL_net_read_desired` and 111 1.1 christos `SSL_net_write_desired`. 112 1.1 christos 113 1.1 christos - The API to expose the event handling deadline for the QUIC engine 114 1.1 christos has evolved since the original DDD process. The new API 115 1.1 christos `SSL_get_event_timeout` is used, rather than the originally hypothesised 116 1.1 christos `BIO_get_timeout`/`SSL_get_timeout`. 117 1.1 christos 118 1.1 christos - The API to perform QUIC event processing has been renamed to be 119 1.1 christos more descriptive. It is now called `SSL_handle_events` rather than 120 1.1 christos the originally hypothesised `BIO_pump`/`SSL_pump`. 121 1.1 christos 122 1.1 christos The following changes were foreseen to be necessary, but turned out to actually 123 1.1 christos not be necessary: 124 1.1 christos 125 1.1 christos - The need to change code which pushes a `BIO_f_buffer()` after an SSL BIO 126 1.1 christos was foreseen as use of buffering on the network side is unworkable with 127 1.1 christos QUIC. This turned out not to be necessary since we can just reject the 128 1.1 christos BIO_push() call. The buffer should still be freed eventually when the 129 1.1 christos SSL BIO is freed. The buffer is not used and is unnecessary, so it is 130 1.1 christos still desirable for applications to remove this code. 131 1.1 christos 132 1.1 christos ddd-02-conn-nonblocking-threads 133 1.1 christos ------------------------------- 134 1.1 christos 135 1.1 christos This is a variant of the ddd-02-conn-nonblocking demo. The base is the same, but 136 1.1 christos the changes made are different. The use of thread-assisted mode, in which an 137 1.1 christos internal assist thread is used to perform QUIC event handling, enables an 138 1.1 christos application to make fewer changes than are needed in the ddd-02-conn-nonblocking 139 1.1 christos demo. 140 1.1 christos 141 1.1 christos ### Originally planned changes 142 1.1 christos 143 1.1 christos The originally planned changes to enable applications for QUIC amounted to: 144 1.1 christos 145 1.1 christos - Change of method, this time using method `QUIC_client_thread_method` rather 146 1.1 christos than `QUIC_client_method`; 147 1.1 christos 148 1.1 christos - Use of a `BIO_get_poll_fd` function to get the FD to poll rather than 149 1.1 christos `BIO_get_fd`; 150 1.1 christos 151 1.1 christos - A change to how the `POLLIN`/`POLLOUT`/`POLLERR` flags to pass to poll(2) 152 1.1 christos need to be determined. 153 1.1 christos 154 1.1 christos Note that this is a substantially smaller list of changes than for 155 1.1 christos ddd-02-conn-nonblocking. 156 1.1 christos 157 1.1 christos ### Actual changes 158 1.1 christos 159 1.1 christos The following additional changes needed to be made: 160 1.1 christos 161 1.1 christos - Change of method name (`QUIC_client_thread_method` was renamed to 162 1.1 christos `OSSL_QUIC_client_thread_method` for namespacing reasons); 163 1.1 christos 164 1.1 christos - Use of ALPN (as for ddd-01-conn-blocking); 165 1.1 christos 166 1.1 christos - Use of `BIO_get_rpoll_descriptor` rather than `BIO_get_poll_fd` (as for 167 1.1 christos ddd-02-conn-nonblocking). 168 1.1 christos 169 1.1 christos - Use of `SSL_net_read_desired` and `SSL_net_write_desired` (as for 170 1.1 christos ddd-02-conn-nonblocking). 171 1.1 christos 172 1.1 christos ddd-03-fd-blocking 173 1.1 christos ------------------ 174 1.1 christos 175 1.1 christos This demo is similar to ddd-01-conn-blocking but uses a file descriptor passed 176 1.1 christos directly by the application rather than BIO_s_connect. 177 1.1 christos 178 1.1 christos ### Originally planned changes 179 1.1 christos 180 1.1 christos - Change of method (as for ddd-01-conn-blocking); 181 1.1 christos 182 1.1 christos - The arguments to the `socket(2)` call are changed from `(AF_INET, SOCK_STREAM, 183 1.1 christos IPPROTO_TCP)` to `(AF_INET, SOCK_DGRAM, IPPROTO_UDP)`. 184 1.1 christos 185 1.1 christos ### Actual changes 186 1.1 christos 187 1.1 christos The following additional changes needed to be made: 188 1.1 christos 189 1.1 christos - Change of method name (as for ddd-01-conn-blocking); 190 1.1 christos 191 1.1 christos - Use of ALPN (as for ddd-01-conn-blocking). 192 1.1 christos 193 1.1 christos ddd-04-fd-nonblocking 194 1.1 christos --------------------- 195 1.1 christos 196 1.1 christos This demo is similar to ddd-01-conn-nonblocking but uses a file descriptor 197 1.1 christos passed directly by the application rather than BIO_s_connect. 198 1.1 christos 199 1.1 christos ### Originally planned changes 200 1.1 christos 201 1.1 christos - Change of method (as for ddd-01-conn-blocking); 202 1.1 christos 203 1.1 christos - The arguments to the `socket(2)` call are changed from `(AF_INET, SOCK_STREAM, 204 1.1 christos IPPROTO_TCP)` to `(AF_INET, SOCK_DGRAM, IPPROTO_UDP)`; 205 1.1 christos 206 1.1 christos - A change to how the `POLLIN`/`POLLOUT`/`POLLERR` flags to pass to poll(2) 207 1.1 christos need to be determined. 208 1.1 christos 209 1.1 christos - Additional functions in application code to determine event handling 210 1.1 christos timeouts related to QUIC (`get_conn_pump_timeout`) and to pump 211 1.1 christos the QUIC event loop (`pump`). 212 1.1 christos 213 1.1 christos - Timeout computation code which involves merging and comparing different 214 1.1 christos timeouts and calling `pump` as needed, based on deadlines reported 215 1.1 christos by libssl. 216 1.1 christos 217 1.1 christos ### Actual changes 218 1.1 christos 219 1.1 christos The following additional changes needed to be made: 220 1.1 christos 221 1.1 christos - Change of method name (as for ddd-01-conn-blocking); 222 1.1 christos 223 1.1 christos - Use of ALPN (as for ddd-01-conn-blocking); 224 1.1 christos 225 1.1 christos - `SSL_get_timeout` replaced with `SSL_get_event_timeout` (as for 226 1.1 christos ddd-02-conn-nonblocking); 227 1.1 christos 228 1.1 christos - `SSL_pump` renamed to `SSL_handle_events` (as for ddd-02-conn-nonblocking); 229 1.1 christos 230 1.1 christos - The strategy for how to determine when to poll for `POLLIN`, when to 231 1.1 christos poll for `POLLOUT`, etc. has changed since the original DDD process. 232 1.1 christos This information is now exposed via `SSL_net_read_desired` and 233 1.1 christos `SSL_net_write_desired` (as for ddd-02-conn-nonblocking). 234 1.1 christos 235 1.1 christos ddd-05-mem-nonblocking 236 1.1 christos ---------------------- 237 1.1 christos 238 1.1 christos This demo is more elaborate. It uses memory buffers created and managed by an 239 1.1 christos application as an intermediary between libssl and the network, which is a common 240 1.1 christos usage pattern for applications. Managing this pattern for QUIC is more elaborate 241 1.1 christos since datagram semantics on the network channel need to be maintained. 242 1.1 christos 243 1.1 christos ### Originally planned changes 244 1.1 christos 245 1.1 christos - Change of method (as for ddd-01-conn-blocking); 246 1.1 christos 247 1.1 christos - Call to `BIO_new_bio_pair` is changed to `BIO_new_dgram_pair`, which 248 1.1 christos provides a bidirectional memory buffer BIO with datagram semantics. 249 1.1 christos 250 1.1 christos - A change to how the `POLLIN`/`POLLOUT`/`POLLERR` flags to pass to poll(2) 251 1.1 christos need to be determined. 252 1.1 christos 253 1.1 christos - Potential changes to buffer sizes used by applications to buffer 254 1.1 christos datagrams, if those buffers are smaller than 1472 bytes. 255 1.1 christos 256 1.1 christos - The arguments to the `socket(2)` call are changed from `(AF_INET, SOCK_STREAM, 257 1.1 christos IPPROTO_TCP)` to `(AF_INET, SOCK_DGRAM, IPPROTO_UDP)`; 258 1.1 christos 259 1.1 christos ### Actual changes 260 1.1 christos 261 1.1 christos The following additional changes needed to be made: 262 1.1 christos 263 1.1 christos - Change of method name (as for ddd-01-conn-blocking); 264 1.1 christos 265 1.1 christos - Use of ALPN (as for ddd-01-conn-blocking); 266 1.1 christos 267 1.1 christos - The API to construct a `BIO_s_dgram_pair` ended up being named 268 1.1 christos `BIO_new_bio_dgram_pair` rather than `BIO_new_dgram_pair`; 269 1.1 christos 270 1.1 christos - Use of `SSL_net_read_desired` and `SSL_net_write_desired` (as for 271 1.1 christos ddd-02-conn-nonblocking). 272 1.1 christos 273 1.1 christos ddd-06-mem-uv 274 1.1 christos ------------- 275 1.1 christos 276 1.1 christos This demo is the most elaborate of the set. It uses a real-world asynchronous 277 1.1 christos I/O reactor, namely libuv (the engine used by Node.js). In doing so it seeks to 278 1.1 christos demonstrate and prove the viability of our API design with a real-world 279 1.1 christos asynchronous I/O system. It operates wholly in non-blocking mode and uses memory 280 1.1 christos buffers on either side of the QUIC stack to feed data to and from the 281 1.1 christos application and the network. 282 1.1 christos 283 1.1 christos ### Originally planned changes 284 1.1 christos 285 1.1 christos - Change of method (as for ddd-01-conn-blocking); 286 1.1 christos 287 1.1 christos - Various changes to use of libuv needed to switch to using UDP; 288 1.1 christos 289 1.1 christos - Additional use of libuv to configure a timer event; 290 1.1 christos 291 1.1 christos - Call to `BIO_new_bio_pair` is changed to `BIO_new_dgram_pair` 292 1.1 christos (as for ddd-05-mem-nonblocking); 293 1.1 christos 294 1.1 christos - Some reordering of code required by the design of libuv. 295 1.1 christos 296 1.1 christos ### Actual changes 297 1.1 christos 298 1.1 christos The following additional changes needed to be made: 299 1.1 christos 300 1.1 christos - Change of method name (as for ddd-01-conn-blocking); 301 1.1 christos 302 1.1 christos - Use of ALPN (as for ddd-01-conn-blocking); 303 1.1 christos 304 1.1 christos - `BIO_new_dgram_pair` renamed to `BIO_new_bio_dgram_pair` (as for 305 1.1 christos ddd-05-mem-nonblocking); 306 1.1 christos 307 1.1 christos - `SSL_get_timeout` replaced with `SSL_get_event_timeout` (as for 308 1.1 christos ddd-02-conn-nonblocking); 309 1.1 christos 310 1.1 christos - `SSL_pump` renamed to `SSL_handle_events` (as for ddd-02-conn-nonblocking); 311 1.1 christos 312 1.1 christos - Fixes to use of libuv based on a corrected understanding 313 1.1 christos of its operation, and changes that necessarily ensue. 314 1.1 christos 315 1.1 christos Conclusions 316 1.1 christos ----------- 317 1.1 christos 318 1.1 christos The DDD process has successfully delivered on the objective of delivering a QUIC 319 1.1 christos API which can be used with only minimal API changes. The additional changes on 320 1.1 christos top of those originally planned which were required to successfully execute the 321 1.1 christos demos using QUIC were highly limited in scope and mostly constituted only minor 322 1.1 christos changes. The sum total of the changes required for each demo (both planned and 323 1.1 christos additional), as denoted in each DDD demo file under `#ifdef USE_QUIC` guards, 324 1.1 christos are both minimal and limited in scope. 325 1.1 christos 326 1.1 christos Minimal and limited are distinct criteria. If inexorable technical 327 1.1 christos requirements dictate, an enormous set of changes to an application could be 328 1.1 christos considered minimal. The changes required to representative applications, as 329 1.1 christos demonstrated by the DDD demos, are not merely minimal but also limited. 330 1.1 christos 331 1.1 christos For example, while the extent of these necessary changes varies by the 332 1.1 christos sophistication of each demo and the kind of application usage pattern it 333 1.1 christos represents, some demos in particular demonstrate exceptionally small changesets; 334 1.1 christos for example, ddd-01-conn-blocking and ddd-02-conn-nonblocking-threads, with 335 1.1 christos ddd-01-conn-blocking literally being enabled by a single line change assuming 336 1.1 christos ALPN is already configured. 337 1.1 christos 338 1.1 christos This report concludes the DDD process for the single-stream QUIC client API 339 1.1 christos design process, which sought to validate our API design and API ease of use for 340 1.1 christos existing applications seeking to adopt QUIC. 341