2
0

ddd-02-conn-nonblocking-threads.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include <sys/poll.h>
  2. #include <openssl/ssl.h>
  3. /*
  4. * Demo 2: Client — Managed Connection — Nonblocking
  5. * ==============================================================
  6. *
  7. * This is an example of (part of) an application which uses libssl in an
  8. * asynchronous, nonblocking fashion. The functions show all interactions with
  9. * libssl the application makes, and would hypothetically be linked into a
  10. * larger application.
  11. *
  12. * In this example, libssl still makes syscalls directly using an fd, which is
  13. * configured in nonblocking mode. As such, the application can still be
  14. * abstracted from the details of what that fd is (is it a TCP socket? is it a
  15. * UDP socket?); this code passes the application an fd and the application
  16. * simply calls back into this code when poll()/etc. indicates it is ready.
  17. */
  18. typedef struct app_conn_st {
  19. SSL *ssl;
  20. BIO *ssl_bio;
  21. int rx_need_tx, tx_need_rx;
  22. } APP_CONN;
  23. /*
  24. * The application is initializing and wants an SSL_CTX which it will use for
  25. * some number of outgoing connections, which it creates in subsequent calls to
  26. * new_conn. The application may also call this function multiple times to
  27. * create multiple SSL_CTX.
  28. */
  29. SSL_CTX *create_ssl_ctx(void)
  30. {
  31. SSL_CTX *ctx;
  32. #ifdef USE_QUIC
  33. ctx = SSL_CTX_new(OSSL_QUIC_client_thread_method());
  34. #else
  35. ctx = SSL_CTX_new(TLS_client_method());
  36. #endif
  37. if (ctx == NULL)
  38. return NULL;
  39. /* Enable trust chain verification. */
  40. SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
  41. /* Load default root CA store. */
  42. if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
  43. SSL_CTX_free(ctx);
  44. return NULL;
  45. }
  46. return ctx;
  47. }
  48. /*
  49. * The application wants to create a new outgoing connection using a given
  50. * SSL_CTX.
  51. *
  52. * hostname is a string like "openssl.org:443" or "[::1]:443".
  53. */
  54. APP_CONN *new_conn(SSL_CTX *ctx, const char *hostname)
  55. {
  56. APP_CONN *conn;
  57. BIO *out, *buf;
  58. SSL *ssl = NULL;
  59. const char *bare_hostname;
  60. #ifdef USE_QUIC
  61. static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'};
  62. #endif
  63. conn = calloc(1, sizeof(APP_CONN));
  64. if (conn == NULL)
  65. return NULL;
  66. out = BIO_new_ssl_connect(ctx);
  67. if (out == NULL) {
  68. free(conn);
  69. return NULL;
  70. }
  71. if (BIO_get_ssl(out, &ssl) == 0) {
  72. BIO_free_all(out);
  73. free(conn);
  74. return NULL;
  75. }
  76. buf = BIO_new(BIO_f_buffer());
  77. if (buf == NULL) {
  78. BIO_free_all(out);
  79. free(conn);
  80. return NULL;
  81. }
  82. BIO_push(out, buf);
  83. if (BIO_set_conn_hostname(out, hostname) == 0) {
  84. BIO_free_all(out);
  85. free(conn);
  86. return NULL;
  87. }
  88. /* Returns the parsed hostname extracted from the hostname:port string. */
  89. bare_hostname = BIO_get_conn_hostname(out);
  90. if (bare_hostname == NULL) {
  91. BIO_free_all(out);
  92. free(conn);
  93. return NULL;
  94. }
  95. /* Tell the SSL object the hostname to check certificates against. */
  96. if (SSL_set1_host(ssl, bare_hostname) <= 0) {
  97. BIO_free_all(out);
  98. free(conn);
  99. return NULL;
  100. }
  101. #ifdef USE_QUIC
  102. /* Configure ALPN, which is required for QUIC. */
  103. if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) {
  104. /* Note: SSL_set_alpn_protos returns 1 for failure. */
  105. BIO_free_all(out);
  106. free(conn);
  107. return NULL;
  108. }
  109. #endif
  110. /* Make the BIO nonblocking. */
  111. BIO_set_nbio(out, 1);
  112. conn->ssl_bio = out;
  113. return conn;
  114. }
  115. /*
  116. * Non-blocking transmission.
  117. *
  118. * Returns -1 on error. Returns -2 if the function would block (corresponds to
  119. * EWOULDBLOCK).
  120. */
  121. int tx(APP_CONN *conn, const void *buf, int buf_len)
  122. {
  123. int l;
  124. conn->tx_need_rx = 0;
  125. l = BIO_write(conn->ssl_bio, buf, buf_len);
  126. if (l <= 0) {
  127. if (BIO_should_retry(conn->ssl_bio)) {
  128. conn->tx_need_rx = BIO_should_read(conn->ssl_bio);
  129. return -2;
  130. } else {
  131. return -1;
  132. }
  133. }
  134. return l;
  135. }
  136. /*
  137. * Non-blocking reception.
  138. *
  139. * Returns -1 on error. Returns -2 if the function would block (corresponds to
  140. * EWOULDBLOCK).
  141. */
  142. int rx(APP_CONN *conn, void *buf, int buf_len)
  143. {
  144. int l;
  145. conn->rx_need_tx = 0;
  146. l = BIO_read(conn->ssl_bio, buf, buf_len);
  147. if (l <= 0) {
  148. if (BIO_should_retry(conn->ssl_bio)) {
  149. conn->rx_need_tx = BIO_should_write(conn->ssl_bio);
  150. return -2;
  151. } else {
  152. return -1;
  153. }
  154. }
  155. return l;
  156. }
  157. /*
  158. * The application wants to know a fd it can poll on to determine when the
  159. * SSL state machine needs to be pumped.
  160. */
  161. int get_conn_fd(APP_CONN *conn)
  162. {
  163. #ifdef USE_QUIC
  164. BIO_POLL_DESCRIPTOR d;
  165. if (!BIO_get_rpoll_descriptor(conn->ssl_bio, &d))
  166. return -1;
  167. return d.value.fd;
  168. #else
  169. return BIO_get_fd(conn->ssl_bio, NULL);
  170. #endif
  171. }
  172. /*
  173. * These functions returns zero or more of:
  174. *
  175. * POLLIN: The SSL state machine is interested in socket readability events.
  176. *
  177. * POLLOUT: The SSL state machine is interested in socket writeability events.
  178. *
  179. * POLLERR: The SSL state machine is interested in socket error events.
  180. *
  181. * get_conn_pending_tx returns events which may cause SSL_write to make
  182. * progress and get_conn_pending_rx returns events which may cause SSL_read
  183. * to make progress.
  184. */
  185. int get_conn_pending_tx(APP_CONN *conn)
  186. {
  187. #ifdef USE_QUIC
  188. return (SSL_net_read_desired(conn->ssl) ? POLLIN : 0)
  189. | (SSL_net_write_desired(conn->ssl) ? POLLOUT : 0)
  190. | POLLERR;
  191. #else
  192. return (conn->tx_need_rx ? POLLIN : 0) | POLLOUT | POLLERR;
  193. #endif
  194. }
  195. int get_conn_pending_rx(APP_CONN *conn)
  196. {
  197. #ifdef USE_QUIC
  198. return get_conn_pending_tx(conn);
  199. #else
  200. return (conn->rx_need_tx ? POLLOUT : 0) | POLLIN | POLLERR;
  201. #endif
  202. }
  203. /*
  204. * The application wants to close the connection and free bookkeeping
  205. * structures.
  206. */
  207. void teardown(APP_CONN *conn)
  208. {
  209. BIO_free_all(conn->ssl_bio);
  210. free(conn);
  211. }
  212. /*
  213. * The application is shutting down and wants to free a previously
  214. * created SSL_CTX.
  215. */
  216. void teardown_ctx(SSL_CTX *ctx)
  217. {
  218. SSL_CTX_free(ctx);
  219. }
  220. /*
  221. * ============================================================================
  222. * Example driver for the above code. This is just to demonstrate that the code
  223. * works and is not intended to be representative of a real application.
  224. */
  225. int main(int argc, char **argv)
  226. {
  227. static char tx_msg[384], host_port[300];
  228. const char *tx_p = tx_msg;
  229. char rx_buf[2048];
  230. int res = 1, l, tx_len;
  231. int timeout = 2000 /* ms */;
  232. APP_CONN *conn = NULL;
  233. SSL_CTX *ctx = NULL;
  234. if (argc < 3) {
  235. fprintf(stderr, "usage: %s host port\n", argv[0]);
  236. goto fail;
  237. }
  238. snprintf(host_port, sizeof(host_port), "%s:%s", argv[1], argv[2]);
  239. tx_len = snprintf(tx_msg, sizeof(tx_msg),
  240. "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]);
  241. ctx = create_ssl_ctx();
  242. if (ctx == NULL) {
  243. fprintf(stderr, "cannot create SSL context\n");
  244. goto fail;
  245. }
  246. conn = new_conn(ctx, host_port);
  247. if (conn == NULL) {
  248. fprintf(stderr, "cannot establish connection\n");
  249. goto fail;
  250. }
  251. /* TX */
  252. while (tx_len != 0) {
  253. l = tx(conn, tx_p, tx_len);
  254. if (l > 0) {
  255. tx_p += l;
  256. tx_len -= l;
  257. } else if (l == -1) {
  258. fprintf(stderr, "tx error\n");
  259. } else if (l == -2) {
  260. struct pollfd pfd = {0};
  261. pfd.fd = get_conn_fd(conn);
  262. pfd.events = get_conn_pending_tx(conn);
  263. if (poll(&pfd, 1, timeout) == 0) {
  264. fprintf(stderr, "tx timeout\n");
  265. goto fail;
  266. }
  267. }
  268. }
  269. /* RX */
  270. for (;;) {
  271. l = rx(conn, rx_buf, sizeof(rx_buf));
  272. if (l > 0) {
  273. fwrite(rx_buf, 1, l, stdout);
  274. } else if (l == -1) {
  275. break;
  276. } else if (l == -2) {
  277. struct pollfd pfd = {0};
  278. pfd.fd = get_conn_fd(conn);
  279. pfd.events = get_conn_pending_rx(conn);
  280. if (poll(&pfd, 1, timeout) == 0) {
  281. fprintf(stderr, "rx timeout\n");
  282. goto fail;
  283. }
  284. }
  285. }
  286. res = 0;
  287. fail:
  288. if (conn != NULL)
  289. teardown(conn);
  290. if (ctx != NULL)
  291. teardown_ctx(ctx);
  292. return res;
  293. }