1*e7be843bSPierre Pronchery #include <sys/poll.h>
2*e7be843bSPierre Pronchery #include <openssl/ssl.h>
3*e7be843bSPierre Pronchery
4*e7be843bSPierre Pronchery /*
5*e7be843bSPierre Pronchery * Demo 5: Client — Client Uses Memory BIO — Nonblocking
6*e7be843bSPierre Pronchery * =====================================================
7*e7be843bSPierre Pronchery *
8*e7be843bSPierre Pronchery * This is an example of (part of) an application which uses libssl in an
9*e7be843bSPierre Pronchery * asynchronous, nonblocking fashion. The application passes memory BIOs to
10*e7be843bSPierre Pronchery * OpenSSL, meaning that it controls both when data is read/written from an SSL
11*e7be843bSPierre Pronchery * object on the decrypted side but also when encrypted data from the network is
12*e7be843bSPierre Pronchery * shunted to/from OpenSSL. In this way OpenSSL is used as a pure state machine
13*e7be843bSPierre Pronchery * which does not make its own network I/O calls. OpenSSL never sees or creates
14*e7be843bSPierre Pronchery * any file descriptor for a network socket. The functions below show all
15*e7be843bSPierre Pronchery * interactions with libssl the application makes, and would hypothetically be
16*e7be843bSPierre Pronchery * linked into a larger application.
17*e7be843bSPierre Pronchery */
18*e7be843bSPierre Pronchery typedef struct app_conn_st {
19*e7be843bSPierre Pronchery SSL *ssl;
20*e7be843bSPierre Pronchery BIO *ssl_bio, *net_bio;
21*e7be843bSPierre Pronchery int rx_need_tx, tx_need_rx;
22*e7be843bSPierre Pronchery } APP_CONN;
23*e7be843bSPierre Pronchery
24*e7be843bSPierre Pronchery /*
25*e7be843bSPierre Pronchery * The application is initializing and wants an SSL_CTX which it will use for
26*e7be843bSPierre Pronchery * some number of outgoing connections, which it creates in subsequent calls to
27*e7be843bSPierre Pronchery * new_conn. The application may also call this function multiple times to
28*e7be843bSPierre Pronchery * create multiple SSL_CTX.
29*e7be843bSPierre Pronchery */
create_ssl_ctx(void)30*e7be843bSPierre Pronchery SSL_CTX *create_ssl_ctx(void)
31*e7be843bSPierre Pronchery {
32*e7be843bSPierre Pronchery SSL_CTX *ctx;
33*e7be843bSPierre Pronchery
34*e7be843bSPierre Pronchery #ifdef USE_QUIC
35*e7be843bSPierre Pronchery ctx = SSL_CTX_new(OSSL_QUIC_client_method());
36*e7be843bSPierre Pronchery #else
37*e7be843bSPierre Pronchery ctx = SSL_CTX_new(TLS_client_method());
38*e7be843bSPierre Pronchery #endif
39*e7be843bSPierre Pronchery if (ctx == NULL)
40*e7be843bSPierre Pronchery return NULL;
41*e7be843bSPierre Pronchery
42*e7be843bSPierre Pronchery /* Enable trust chain verification. */
43*e7be843bSPierre Pronchery SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
44*e7be843bSPierre Pronchery
45*e7be843bSPierre Pronchery /* Load default root CA store. */
46*e7be843bSPierre Pronchery if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
47*e7be843bSPierre Pronchery SSL_CTX_free(ctx);
48*e7be843bSPierre Pronchery return NULL;
49*e7be843bSPierre Pronchery }
50*e7be843bSPierre Pronchery
51*e7be843bSPierre Pronchery return ctx;
52*e7be843bSPierre Pronchery }
53*e7be843bSPierre Pronchery
54*e7be843bSPierre Pronchery /*
55*e7be843bSPierre Pronchery * The application wants to create a new outgoing connection using a given
56*e7be843bSPierre Pronchery * SSL_CTX.
57*e7be843bSPierre Pronchery *
58*e7be843bSPierre Pronchery * hostname is a string like "openssl.org" used for certificate validation.
59*e7be843bSPierre Pronchery */
new_conn(SSL_CTX * ctx,const char * bare_hostname)60*e7be843bSPierre Pronchery APP_CONN *new_conn(SSL_CTX *ctx, const char *bare_hostname)
61*e7be843bSPierre Pronchery {
62*e7be843bSPierre Pronchery BIO *ssl_bio, *internal_bio, *net_bio;
63*e7be843bSPierre Pronchery APP_CONN *conn;
64*e7be843bSPierre Pronchery SSL *ssl;
65*e7be843bSPierre Pronchery #ifdef USE_QUIC
66*e7be843bSPierre Pronchery static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'};
67*e7be843bSPierre Pronchery #endif
68*e7be843bSPierre Pronchery
69*e7be843bSPierre Pronchery conn = calloc(1, sizeof(APP_CONN));
70*e7be843bSPierre Pronchery if (conn == NULL)
71*e7be843bSPierre Pronchery return NULL;
72*e7be843bSPierre Pronchery
73*e7be843bSPierre Pronchery ssl = conn->ssl = SSL_new(ctx);
74*e7be843bSPierre Pronchery if (ssl == NULL) {
75*e7be843bSPierre Pronchery free(conn);
76*e7be843bSPierre Pronchery return NULL;
77*e7be843bSPierre Pronchery }
78*e7be843bSPierre Pronchery
79*e7be843bSPierre Pronchery SSL_set_connect_state(ssl); /* cannot fail */
80*e7be843bSPierre Pronchery
81*e7be843bSPierre Pronchery #ifdef USE_QUIC
82*e7be843bSPierre Pronchery if (BIO_new_bio_dgram_pair(&internal_bio, 0, &net_bio, 0) <= 0) {
83*e7be843bSPierre Pronchery #else
84*e7be843bSPierre Pronchery if (BIO_new_bio_pair(&internal_bio, 0, &net_bio, 0) <= 0) {
85*e7be843bSPierre Pronchery #endif
86*e7be843bSPierre Pronchery SSL_free(ssl);
87*e7be843bSPierre Pronchery free(conn);
88*e7be843bSPierre Pronchery return NULL;
89*e7be843bSPierre Pronchery }
90*e7be843bSPierre Pronchery
91*e7be843bSPierre Pronchery SSL_set_bio(ssl, internal_bio, internal_bio);
92*e7be843bSPierre Pronchery
93*e7be843bSPierre Pronchery if (SSL_set1_host(ssl, bare_hostname) <= 0) {
94*e7be843bSPierre Pronchery SSL_free(ssl);
95*e7be843bSPierre Pronchery free(conn);
96*e7be843bSPierre Pronchery return NULL;
97*e7be843bSPierre Pronchery }
98*e7be843bSPierre Pronchery
99*e7be843bSPierre Pronchery if (SSL_set_tlsext_host_name(ssl, bare_hostname) <= 0) {
100*e7be843bSPierre Pronchery SSL_free(ssl);
101*e7be843bSPierre Pronchery free(conn);
102*e7be843bSPierre Pronchery return NULL;
103*e7be843bSPierre Pronchery }
104*e7be843bSPierre Pronchery
105*e7be843bSPierre Pronchery ssl_bio = BIO_new(BIO_f_ssl());
106*e7be843bSPierre Pronchery if (ssl_bio == NULL) {
107*e7be843bSPierre Pronchery SSL_free(ssl);
108*e7be843bSPierre Pronchery free(conn);
109*e7be843bSPierre Pronchery return NULL;
110*e7be843bSPierre Pronchery }
111*e7be843bSPierre Pronchery
112*e7be843bSPierre Pronchery if (BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE) <= 0) {
113*e7be843bSPierre Pronchery SSL_free(ssl);
114*e7be843bSPierre Pronchery BIO_free(ssl_bio);
115*e7be843bSPierre Pronchery return NULL;
116*e7be843bSPierre Pronchery }
117*e7be843bSPierre Pronchery
118*e7be843bSPierre Pronchery #ifdef USE_QUIC
119*e7be843bSPierre Pronchery /* Configure ALPN, which is required for QUIC. */
120*e7be843bSPierre Pronchery if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) {
121*e7be843bSPierre Pronchery /* Note: SSL_set_alpn_protos returns 1 for failure. */
122*e7be843bSPierre Pronchery SSL_free(ssl);
123*e7be843bSPierre Pronchery BIO_free(ssl_bio);
124*e7be843bSPierre Pronchery return NULL;
125*e7be843bSPierre Pronchery }
126*e7be843bSPierre Pronchery #endif
127*e7be843bSPierre Pronchery
128*e7be843bSPierre Pronchery conn->ssl_bio = ssl_bio;
129*e7be843bSPierre Pronchery conn->net_bio = net_bio;
130*e7be843bSPierre Pronchery return conn;
131*e7be843bSPierre Pronchery }
132*e7be843bSPierre Pronchery
133*e7be843bSPierre Pronchery /*
134*e7be843bSPierre Pronchery * Non-blocking transmission.
135*e7be843bSPierre Pronchery *
136*e7be843bSPierre Pronchery * Returns -1 on error. Returns -2 if the function would block (corresponds to
137*e7be843bSPierre Pronchery * EWOULDBLOCK).
138*e7be843bSPierre Pronchery */
139*e7be843bSPierre Pronchery int tx(APP_CONN *conn, const void *buf, int buf_len)
140*e7be843bSPierre Pronchery {
141*e7be843bSPierre Pronchery int rc, l;
142*e7be843bSPierre Pronchery
143*e7be843bSPierre Pronchery l = BIO_write(conn->ssl_bio, buf, buf_len);
144*e7be843bSPierre Pronchery if (l <= 0) {
145*e7be843bSPierre Pronchery rc = SSL_get_error(conn->ssl, l);
146*e7be843bSPierre Pronchery switch (rc) {
147*e7be843bSPierre Pronchery case SSL_ERROR_WANT_READ:
148*e7be843bSPierre Pronchery conn->tx_need_rx = 1;
149*e7be843bSPierre Pronchery case SSL_ERROR_WANT_CONNECT:
150*e7be843bSPierre Pronchery case SSL_ERROR_WANT_WRITE:
151*e7be843bSPierre Pronchery return -2;
152*e7be843bSPierre Pronchery default:
153*e7be843bSPierre Pronchery return -1;
154*e7be843bSPierre Pronchery }
155*e7be843bSPierre Pronchery } else {
156*e7be843bSPierre Pronchery conn->tx_need_rx = 0;
157*e7be843bSPierre Pronchery }
158*e7be843bSPierre Pronchery
159*e7be843bSPierre Pronchery return l;
160*e7be843bSPierre Pronchery }
161*e7be843bSPierre Pronchery
162*e7be843bSPierre Pronchery /*
163*e7be843bSPierre Pronchery * Non-blocking reception.
164*e7be843bSPierre Pronchery *
165*e7be843bSPierre Pronchery * Returns -1 on error. Returns -2 if the function would block (corresponds to
166*e7be843bSPierre Pronchery * EWOULDBLOCK).
167*e7be843bSPierre Pronchery */
168*e7be843bSPierre Pronchery int rx(APP_CONN *conn, void *buf, int buf_len)
169*e7be843bSPierre Pronchery {
170*e7be843bSPierre Pronchery int rc, l;
171*e7be843bSPierre Pronchery
172*e7be843bSPierre Pronchery l = BIO_read(conn->ssl_bio, buf, buf_len);
173*e7be843bSPierre Pronchery if (l <= 0) {
174*e7be843bSPierre Pronchery rc = SSL_get_error(conn->ssl, l);
175*e7be843bSPierre Pronchery switch (rc) {
176*e7be843bSPierre Pronchery case SSL_ERROR_WANT_WRITE:
177*e7be843bSPierre Pronchery conn->rx_need_tx = 1;
178*e7be843bSPierre Pronchery case SSL_ERROR_WANT_READ:
179*e7be843bSPierre Pronchery return -2;
180*e7be843bSPierre Pronchery default:
181*e7be843bSPierre Pronchery return -1;
182*e7be843bSPierre Pronchery }
183*e7be843bSPierre Pronchery } else {
184*e7be843bSPierre Pronchery conn->rx_need_tx = 0;
185*e7be843bSPierre Pronchery }
186*e7be843bSPierre Pronchery
187*e7be843bSPierre Pronchery return l;
188*e7be843bSPierre Pronchery }
189*e7be843bSPierre Pronchery
190*e7be843bSPierre Pronchery /*
191*e7be843bSPierre Pronchery * Called to get data which has been enqueued for transmission to the network
192*e7be843bSPierre Pronchery * by OpenSSL. For QUIC, this always outputs a single datagram.
193*e7be843bSPierre Pronchery *
194*e7be843bSPierre Pronchery * IMPORTANT (QUIC): If buf_len is inadequate to hold the datagram, it is truncated
195*e7be843bSPierre Pronchery * (similar to read(2)). A buffer size of at least 1472 must be used by default
196*e7be843bSPierre Pronchery * to guarantee this does not occur.
197*e7be843bSPierre Pronchery */
198*e7be843bSPierre Pronchery int read_net_tx(APP_CONN *conn, void *buf, int buf_len)
199*e7be843bSPierre Pronchery {
200*e7be843bSPierre Pronchery return BIO_read(conn->net_bio, buf, buf_len);
201*e7be843bSPierre Pronchery }
202*e7be843bSPierre Pronchery
203*e7be843bSPierre Pronchery /*
204*e7be843bSPierre Pronchery * Called to feed data which has been received from the network to OpenSSL.
205*e7be843bSPierre Pronchery *
206*e7be843bSPierre Pronchery * QUIC: buf must contain the entirety of a single datagram. It will be consumed
207*e7be843bSPierre Pronchery * entirely (return value == buf_len) or not at all.
208*e7be843bSPierre Pronchery */
209*e7be843bSPierre Pronchery int write_net_rx(APP_CONN *conn, const void *buf, int buf_len)
210*e7be843bSPierre Pronchery {
211*e7be843bSPierre Pronchery return BIO_write(conn->net_bio, buf, buf_len);
212*e7be843bSPierre Pronchery }
213*e7be843bSPierre Pronchery
214*e7be843bSPierre Pronchery /*
215*e7be843bSPierre Pronchery * Determine how much data can be written to the network RX BIO.
216*e7be843bSPierre Pronchery */
217*e7be843bSPierre Pronchery size_t net_rx_space(APP_CONN *conn)
218*e7be843bSPierre Pronchery {
219*e7be843bSPierre Pronchery return BIO_ctrl_get_write_guarantee(conn->net_bio);
220*e7be843bSPierre Pronchery }
221*e7be843bSPierre Pronchery
222*e7be843bSPierre Pronchery /*
223*e7be843bSPierre Pronchery * Determine how much data is currently queued for transmission in the network
224*e7be843bSPierre Pronchery * TX BIO.
225*e7be843bSPierre Pronchery */
226*e7be843bSPierre Pronchery size_t net_tx_avail(APP_CONN *conn)
227*e7be843bSPierre Pronchery {
228*e7be843bSPierre Pronchery return BIO_ctrl_pending(conn->net_bio);
229*e7be843bSPierre Pronchery }
230*e7be843bSPierre Pronchery
231*e7be843bSPierre Pronchery /*
232*e7be843bSPierre Pronchery * These functions returns zero or more of:
233*e7be843bSPierre Pronchery *
234*e7be843bSPierre Pronchery * POLLIN: The SSL state machine is interested in socket readability events.
235*e7be843bSPierre Pronchery *
236*e7be843bSPierre Pronchery * POLLOUT: The SSL state machine is interested in socket writeability events.
237*e7be843bSPierre Pronchery *
238*e7be843bSPierre Pronchery * POLLERR: The SSL state machine is interested in socket error events.
239*e7be843bSPierre Pronchery *
240*e7be843bSPierre Pronchery * get_conn_pending_tx returns events which may cause SSL_write to make
241*e7be843bSPierre Pronchery * progress and get_conn_pending_rx returns events which may cause SSL_read
242*e7be843bSPierre Pronchery * to make progress.
243*e7be843bSPierre Pronchery */
244*e7be843bSPierre Pronchery int get_conn_pending_tx(APP_CONN *conn)
245*e7be843bSPierre Pronchery {
246*e7be843bSPierre Pronchery #ifdef USE_QUIC
247*e7be843bSPierre Pronchery return (SSL_net_read_desired(conn->ssl) ? POLLIN : 0)
248*e7be843bSPierre Pronchery | (SSL_net_write_desired(conn->ssl) ? POLLOUT : 0)
249*e7be843bSPierre Pronchery | POLLERR;
250*e7be843bSPierre Pronchery #else
251*e7be843bSPierre Pronchery return (conn->tx_need_rx ? POLLIN : 0) | POLLOUT | POLLERR;
252*e7be843bSPierre Pronchery #endif
253*e7be843bSPierre Pronchery }
254*e7be843bSPierre Pronchery
255*e7be843bSPierre Pronchery int get_conn_pending_rx(APP_CONN *conn)
256*e7be843bSPierre Pronchery {
257*e7be843bSPierre Pronchery #ifdef USE_QUIC
258*e7be843bSPierre Pronchery return get_conn_pending_tx(conn);
259*e7be843bSPierre Pronchery #else
260*e7be843bSPierre Pronchery return (conn->rx_need_tx ? POLLOUT : 0) | POLLIN | POLLERR;
261*e7be843bSPierre Pronchery #endif
262*e7be843bSPierre Pronchery }
263*e7be843bSPierre Pronchery
264*e7be843bSPierre Pronchery /*
265*e7be843bSPierre Pronchery * The application wants to close the connection and free bookkeeping
266*e7be843bSPierre Pronchery * structures.
267*e7be843bSPierre Pronchery */
268*e7be843bSPierre Pronchery void teardown(APP_CONN *conn)
269*e7be843bSPierre Pronchery {
270*e7be843bSPierre Pronchery BIO_free_all(conn->ssl_bio);
271*e7be843bSPierre Pronchery BIO_free_all(conn->net_bio);
272*e7be843bSPierre Pronchery free(conn);
273*e7be843bSPierre Pronchery }
274*e7be843bSPierre Pronchery
275*e7be843bSPierre Pronchery /*
276*e7be843bSPierre Pronchery * The application is shutting down and wants to free a previously
277*e7be843bSPierre Pronchery * created SSL_CTX.
278*e7be843bSPierre Pronchery */
279*e7be843bSPierre Pronchery void teardown_ctx(SSL_CTX *ctx)
280*e7be843bSPierre Pronchery {
281*e7be843bSPierre Pronchery SSL_CTX_free(ctx);
282*e7be843bSPierre Pronchery }
283*e7be843bSPierre Pronchery
284*e7be843bSPierre Pronchery /*
285*e7be843bSPierre Pronchery * ============================================================================
286*e7be843bSPierre Pronchery * Example driver for the above code. This is just to demonstrate that the code
287*e7be843bSPierre Pronchery * works and is not intended to be representative of a real application.
288*e7be843bSPierre Pronchery */
289*e7be843bSPierre Pronchery #include <sys/types.h>
290*e7be843bSPierre Pronchery #include <sys/socket.h>
291*e7be843bSPierre Pronchery #include <sys/signal.h>
292*e7be843bSPierre Pronchery #include <netdb.h>
293*e7be843bSPierre Pronchery #include <unistd.h>
294*e7be843bSPierre Pronchery #include <fcntl.h>
295*e7be843bSPierre Pronchery #include <errno.h>
296*e7be843bSPierre Pronchery
297*e7be843bSPierre Pronchery static int pump(APP_CONN *conn, int fd, int events, int timeout)
298*e7be843bSPierre Pronchery {
299*e7be843bSPierre Pronchery int l, l2;
300*e7be843bSPierre Pronchery char buf[2048]; /* QUIC: would need to be changed if < 1472 */
301*e7be843bSPierre Pronchery size_t wspace;
302*e7be843bSPierre Pronchery struct pollfd pfd = {0};
303*e7be843bSPierre Pronchery
304*e7be843bSPierre Pronchery pfd.fd = fd;
305*e7be843bSPierre Pronchery pfd.events = (events & (POLLIN | POLLERR));
306*e7be843bSPierre Pronchery if (net_rx_space(conn) == 0)
307*e7be843bSPierre Pronchery pfd.events &= ~POLLIN;
308*e7be843bSPierre Pronchery if (net_tx_avail(conn) > 0)
309*e7be843bSPierre Pronchery pfd.events |= POLLOUT;
310*e7be843bSPierre Pronchery
311*e7be843bSPierre Pronchery if ((pfd.events & (POLLIN|POLLOUT)) == 0)
312*e7be843bSPierre Pronchery return 1;
313*e7be843bSPierre Pronchery
314*e7be843bSPierre Pronchery if (poll(&pfd, 1, timeout) == 0)
315*e7be843bSPierre Pronchery return -1;
316*e7be843bSPierre Pronchery
317*e7be843bSPierre Pronchery if (pfd.revents & POLLIN) {
318*e7be843bSPierre Pronchery while ((wspace = net_rx_space(conn)) > 0) {
319*e7be843bSPierre Pronchery l = read(fd, buf, wspace > sizeof(buf) ? sizeof(buf) : wspace);
320*e7be843bSPierre Pronchery if (l <= 0) {
321*e7be843bSPierre Pronchery switch (errno) {
322*e7be843bSPierre Pronchery case EAGAIN:
323*e7be843bSPierre Pronchery goto stop;
324*e7be843bSPierre Pronchery default:
325*e7be843bSPierre Pronchery if (l == 0) /* EOF */
326*e7be843bSPierre Pronchery goto stop;
327*e7be843bSPierre Pronchery
328*e7be843bSPierre Pronchery fprintf(stderr, "error on read: %d\n", errno);
329*e7be843bSPierre Pronchery return -1;
330*e7be843bSPierre Pronchery }
331*e7be843bSPierre Pronchery break;
332*e7be843bSPierre Pronchery }
333*e7be843bSPierre Pronchery l2 = write_net_rx(conn, buf, l);
334*e7be843bSPierre Pronchery if (l2 < l)
335*e7be843bSPierre Pronchery fprintf(stderr, "short write %d %d\n", l2, l);
336*e7be843bSPierre Pronchery } stop:;
337*e7be843bSPierre Pronchery }
338*e7be843bSPierre Pronchery
339*e7be843bSPierre Pronchery if (pfd.revents & POLLOUT) {
340*e7be843bSPierre Pronchery for (;;) {
341*e7be843bSPierre Pronchery l = read_net_tx(conn, buf, sizeof(buf));
342*e7be843bSPierre Pronchery if (l <= 0)
343*e7be843bSPierre Pronchery break;
344*e7be843bSPierre Pronchery l2 = write(fd, buf, l);
345*e7be843bSPierre Pronchery if (l2 < l)
346*e7be843bSPierre Pronchery fprintf(stderr, "short read %d %d\n", l2, l);
347*e7be843bSPierre Pronchery }
348*e7be843bSPierre Pronchery }
349*e7be843bSPierre Pronchery
350*e7be843bSPierre Pronchery return 1;
351*e7be843bSPierre Pronchery }
352*e7be843bSPierre Pronchery
353*e7be843bSPierre Pronchery int main(int argc, char **argv)
354*e7be843bSPierre Pronchery {
355*e7be843bSPierre Pronchery int rc, fd = -1, res = 1;
356*e7be843bSPierre Pronchery static char tx_msg[300];
357*e7be843bSPierre Pronchery const char *tx_p = tx_msg;
358*e7be843bSPierre Pronchery char rx_buf[2048];
359*e7be843bSPierre Pronchery int l, tx_len;
360*e7be843bSPierre Pronchery int timeout = 2000 /* ms */;
361*e7be843bSPierre Pronchery APP_CONN *conn = NULL;
362*e7be843bSPierre Pronchery struct addrinfo hints = {0}, *result = NULL;
363*e7be843bSPierre Pronchery SSL_CTX *ctx = NULL;
364*e7be843bSPierre Pronchery
365*e7be843bSPierre Pronchery if (argc < 3) {
366*e7be843bSPierre Pronchery fprintf(stderr, "usage: %s host port\n", argv[0]);
367*e7be843bSPierre Pronchery goto fail;
368*e7be843bSPierre Pronchery }
369*e7be843bSPierre Pronchery
370*e7be843bSPierre Pronchery tx_len = snprintf(tx_msg, sizeof(tx_msg),
371*e7be843bSPierre Pronchery "GET / HTTP/1.0\r\nHost: %s\r\n\r\n",
372*e7be843bSPierre Pronchery argv[1]);
373*e7be843bSPierre Pronchery
374*e7be843bSPierre Pronchery ctx = create_ssl_ctx();
375*e7be843bSPierre Pronchery if (ctx == NULL) {
376*e7be843bSPierre Pronchery fprintf(stderr, "cannot create SSL context\n");
377*e7be843bSPierre Pronchery goto fail;
378*e7be843bSPierre Pronchery }
379*e7be843bSPierre Pronchery
380*e7be843bSPierre Pronchery hints.ai_family = AF_INET;
381*e7be843bSPierre Pronchery hints.ai_socktype = SOCK_STREAM;
382*e7be843bSPierre Pronchery hints.ai_flags = AI_PASSIVE;
383*e7be843bSPierre Pronchery rc = getaddrinfo(argv[1], argv[2], &hints, &result);
384*e7be843bSPierre Pronchery if (rc < 0) {
385*e7be843bSPierre Pronchery fprintf(stderr, "cannot resolve\n");
386*e7be843bSPierre Pronchery goto fail;
387*e7be843bSPierre Pronchery }
388*e7be843bSPierre Pronchery
389*e7be843bSPierre Pronchery signal(SIGPIPE, SIG_IGN);
390*e7be843bSPierre Pronchery
391*e7be843bSPierre Pronchery #ifdef USE_QUIC
392*e7be843bSPierre Pronchery fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
393*e7be843bSPierre Pronchery #else
394*e7be843bSPierre Pronchery fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
395*e7be843bSPierre Pronchery #endif
396*e7be843bSPierre Pronchery if (fd < 0) {
397*e7be843bSPierre Pronchery fprintf(stderr, "cannot create socket\n");
398*e7be843bSPierre Pronchery goto fail;
399*e7be843bSPierre Pronchery }
400*e7be843bSPierre Pronchery
401*e7be843bSPierre Pronchery rc = connect(fd, result->ai_addr, result->ai_addrlen);
402*e7be843bSPierre Pronchery if (rc < 0) {
403*e7be843bSPierre Pronchery fprintf(stderr, "cannot connect\n");
404*e7be843bSPierre Pronchery goto fail;
405*e7be843bSPierre Pronchery }
406*e7be843bSPierre Pronchery
407*e7be843bSPierre Pronchery rc = fcntl(fd, F_SETFL, O_NONBLOCK);
408*e7be843bSPierre Pronchery if (rc < 0) {
409*e7be843bSPierre Pronchery fprintf(stderr, "cannot make socket nonblocking\n");
410*e7be843bSPierre Pronchery goto fail;
411*e7be843bSPierre Pronchery }
412*e7be843bSPierre Pronchery
413*e7be843bSPierre Pronchery conn = new_conn(ctx, argv[1]);
414*e7be843bSPierre Pronchery if (conn == NULL) {
415*e7be843bSPierre Pronchery fprintf(stderr, "cannot establish connection\n");
416*e7be843bSPierre Pronchery goto fail;
417*e7be843bSPierre Pronchery }
418*e7be843bSPierre Pronchery
419*e7be843bSPierre Pronchery /* TX */
420*e7be843bSPierre Pronchery while (tx_len != 0) {
421*e7be843bSPierre Pronchery l = tx(conn, tx_p, tx_len);
422*e7be843bSPierre Pronchery if (l > 0) {
423*e7be843bSPierre Pronchery tx_p += l;
424*e7be843bSPierre Pronchery tx_len -= l;
425*e7be843bSPierre Pronchery } else if (l == -1) {
426*e7be843bSPierre Pronchery fprintf(stderr, "tx error\n");
427*e7be843bSPierre Pronchery } else if (l == -2) {
428*e7be843bSPierre Pronchery if (pump(conn, fd, get_conn_pending_tx(conn), timeout) != 1) {
429*e7be843bSPierre Pronchery fprintf(stderr, "pump error\n");
430*e7be843bSPierre Pronchery goto fail;
431*e7be843bSPierre Pronchery }
432*e7be843bSPierre Pronchery }
433*e7be843bSPierre Pronchery }
434*e7be843bSPierre Pronchery
435*e7be843bSPierre Pronchery /* RX */
436*e7be843bSPierre Pronchery for (;;) {
437*e7be843bSPierre Pronchery l = rx(conn, rx_buf, sizeof(rx_buf));
438*e7be843bSPierre Pronchery if (l > 0) {
439*e7be843bSPierre Pronchery fwrite(rx_buf, 1, l, stdout);
440*e7be843bSPierre Pronchery } else if (l == -1) {
441*e7be843bSPierre Pronchery break;
442*e7be843bSPierre Pronchery } else if (l == -2) {
443*e7be843bSPierre Pronchery if (pump(conn, fd, get_conn_pending_rx(conn), timeout) != 1) {
444*e7be843bSPierre Pronchery fprintf(stderr, "pump error\n");
445*e7be843bSPierre Pronchery goto fail;
446*e7be843bSPierre Pronchery }
447*e7be843bSPierre Pronchery }
448*e7be843bSPierre Pronchery }
449*e7be843bSPierre Pronchery
450*e7be843bSPierre Pronchery res = 0;
451*e7be843bSPierre Pronchery fail:
452*e7be843bSPierre Pronchery if (conn != NULL)
453*e7be843bSPierre Pronchery teardown(conn);
454*e7be843bSPierre Pronchery if (ctx != NULL)
455*e7be843bSPierre Pronchery teardown_ctx(ctx);
456*e7be843bSPierre Pronchery if (result != NULL)
457*e7be843bSPierre Pronchery freeaddrinfo(result);
458*e7be843bSPierre Pronchery return res;
459*e7be843bSPierre Pronchery }
460