1*e7be843bSPierre Pronchery #include <sys/poll.h>
2*e7be843bSPierre Pronchery #include <openssl/ssl.h>
3*e7be843bSPierre Pronchery #include <uv.h>
4*e7be843bSPierre Pronchery #include <assert.h>
5*e7be843bSPierre Pronchery #ifdef USE_QUIC
6*e7be843bSPierre Pronchery # include <sys/time.h>
7*e7be843bSPierre Pronchery #endif
8*e7be843bSPierre Pronchery
9*e7be843bSPierre Pronchery typedef struct app_conn_st APP_CONN;
10*e7be843bSPierre Pronchery typedef struct upper_write_op_st UPPER_WRITE_OP;
11*e7be843bSPierre Pronchery typedef struct lower_write_op_st LOWER_WRITE_OP;
12*e7be843bSPierre Pronchery
13*e7be843bSPierre Pronchery typedef void (app_connect_cb)(APP_CONN *conn, int status, void *arg);
14*e7be843bSPierre Pronchery typedef void (app_write_cb)(APP_CONN *conn, int status, void *arg);
15*e7be843bSPierre Pronchery typedef void (app_read_cb)(APP_CONN *conn, void *buf, size_t buf_len, void *arg);
16*e7be843bSPierre Pronchery
17*e7be843bSPierre Pronchery #ifdef USE_QUIC
18*e7be843bSPierre Pronchery static void set_timer(APP_CONN *conn);
19*e7be843bSPierre Pronchery #else
20*e7be843bSPierre Pronchery static void tcp_connect_done(uv_connect_t *tcp_connect, int status);
21*e7be843bSPierre Pronchery #endif
22*e7be843bSPierre Pronchery static void net_connect_fail_close_done(uv_handle_t *handle);
23*e7be843bSPierre Pronchery static int handshake_ssl(APP_CONN *conn);
24*e7be843bSPierre Pronchery static void flush_write_buf(APP_CONN *conn);
25*e7be843bSPierre Pronchery static void set_rx(APP_CONN *conn);
26*e7be843bSPierre Pronchery static int try_write(APP_CONN *conn, UPPER_WRITE_OP *op);
27*e7be843bSPierre Pronchery static void handle_pending_writes(APP_CONN *conn);
28*e7be843bSPierre Pronchery static int write_deferred(APP_CONN *conn, const void *buf, size_t buf_len, app_write_cb *cb, void *arg);
29*e7be843bSPierre Pronchery static void teardown_continued(uv_handle_t *handle);
30*e7be843bSPierre Pronchery static int setup_ssl(APP_CONN *conn, const char *hostname);
31*e7be843bSPierre Pronchery
32*e7be843bSPierre Pronchery #ifdef USE_QUIC
timeval_to_ms(const struct timeval * t)33*e7be843bSPierre Pronchery static inline int timeval_to_ms(const struct timeval *t)
34*e7be843bSPierre Pronchery {
35*e7be843bSPierre Pronchery return t->tv_sec*1000 + t->tv_usec/1000;
36*e7be843bSPierre Pronchery }
37*e7be843bSPierre Pronchery #endif
38*e7be843bSPierre Pronchery
39*e7be843bSPierre Pronchery /*
40*e7be843bSPierre Pronchery * Structure to track an application-level write request. Only created
41*e7be843bSPierre Pronchery * if SSL_write does not accept the data immediately, typically because
42*e7be843bSPierre Pronchery * it is in WANT_READ.
43*e7be843bSPierre Pronchery */
44*e7be843bSPierre Pronchery struct upper_write_op_st {
45*e7be843bSPierre Pronchery struct upper_write_op_st *prev, *next;
46*e7be843bSPierre Pronchery const uint8_t *buf;
47*e7be843bSPierre Pronchery size_t buf_len, written;
48*e7be843bSPierre Pronchery APP_CONN *conn;
49*e7be843bSPierre Pronchery app_write_cb *cb;
50*e7be843bSPierre Pronchery void *cb_arg;
51*e7be843bSPierre Pronchery };
52*e7be843bSPierre Pronchery
53*e7be843bSPierre Pronchery /*
54*e7be843bSPierre Pronchery * Structure to track a network-level write request.
55*e7be843bSPierre Pronchery */
56*e7be843bSPierre Pronchery struct lower_write_op_st {
57*e7be843bSPierre Pronchery #ifdef USE_QUIC
58*e7be843bSPierre Pronchery uv_udp_send_t w;
59*e7be843bSPierre Pronchery #else
60*e7be843bSPierre Pronchery uv_write_t w;
61*e7be843bSPierre Pronchery #endif
62*e7be843bSPierre Pronchery uv_buf_t b;
63*e7be843bSPierre Pronchery uint8_t *buf;
64*e7be843bSPierre Pronchery APP_CONN *conn;
65*e7be843bSPierre Pronchery };
66*e7be843bSPierre Pronchery
67*e7be843bSPierre Pronchery /*
68*e7be843bSPierre Pronchery * Application connection object.
69*e7be843bSPierre Pronchery */
70*e7be843bSPierre Pronchery struct app_conn_st {
71*e7be843bSPierre Pronchery SSL_CTX *ctx;
72*e7be843bSPierre Pronchery SSL *ssl;
73*e7be843bSPierre Pronchery BIO *net_bio;
74*e7be843bSPierre Pronchery #ifdef USE_QUIC
75*e7be843bSPierre Pronchery uv_udp_t udp;
76*e7be843bSPierre Pronchery uv_timer_t timer;
77*e7be843bSPierre Pronchery #else
78*e7be843bSPierre Pronchery uv_stream_t *stream;
79*e7be843bSPierre Pronchery uv_tcp_t tcp;
80*e7be843bSPierre Pronchery uv_connect_t tcp_connect;
81*e7be843bSPierre Pronchery #endif
82*e7be843bSPierre Pronchery app_connect_cb *app_connect_cb; /* called once handshake is done */
83*e7be843bSPierre Pronchery void *app_connect_arg;
84*e7be843bSPierre Pronchery app_read_cb *app_read_cb; /* application's on-RX callback */
85*e7be843bSPierre Pronchery void *app_read_arg;
86*e7be843bSPierre Pronchery const char *hostname;
87*e7be843bSPierre Pronchery char init_handshake, done_handshake, closed;
88*e7be843bSPierre Pronchery char *teardown_done;
89*e7be843bSPierre Pronchery
90*e7be843bSPierre Pronchery UPPER_WRITE_OP *pending_upper_write_head, *pending_upper_write_tail;
91*e7be843bSPierre Pronchery };
92*e7be843bSPierre Pronchery
93*e7be843bSPierre Pronchery /*
94*e7be843bSPierre Pronchery * The application is initializing and wants an SSL_CTX which it will use for
95*e7be843bSPierre Pronchery * some number of outgoing connections, which it creates in subsequent calls to
96*e7be843bSPierre Pronchery * new_conn. The application may also call this function multiple times to
97*e7be843bSPierre Pronchery * create multiple SSL_CTX.
98*e7be843bSPierre Pronchery */
create_ssl_ctx(void)99*e7be843bSPierre Pronchery SSL_CTX *create_ssl_ctx(void)
100*e7be843bSPierre Pronchery {
101*e7be843bSPierre Pronchery SSL_CTX *ctx;
102*e7be843bSPierre Pronchery
103*e7be843bSPierre Pronchery #ifdef USE_QUIC
104*e7be843bSPierre Pronchery ctx = SSL_CTX_new(OSSL_QUIC_client_method());
105*e7be843bSPierre Pronchery #else
106*e7be843bSPierre Pronchery ctx = SSL_CTX_new(TLS_client_method());
107*e7be843bSPierre Pronchery #endif
108*e7be843bSPierre Pronchery if (ctx == NULL)
109*e7be843bSPierre Pronchery return NULL;
110*e7be843bSPierre Pronchery
111*e7be843bSPierre Pronchery /* Enable trust chain verification. */
112*e7be843bSPierre Pronchery SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
113*e7be843bSPierre Pronchery
114*e7be843bSPierre Pronchery /* Load default root CA store. */
115*e7be843bSPierre Pronchery if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
116*e7be843bSPierre Pronchery SSL_CTX_free(ctx);
117*e7be843bSPierre Pronchery return NULL;
118*e7be843bSPierre Pronchery }
119*e7be843bSPierre Pronchery
120*e7be843bSPierre Pronchery return ctx;
121*e7be843bSPierre Pronchery }
122*e7be843bSPierre Pronchery
123*e7be843bSPierre Pronchery /*
124*e7be843bSPierre Pronchery * The application wants to create a new outgoing connection using a given
125*e7be843bSPierre Pronchery * SSL_CTX. An outgoing TCP connection is started and the callback is called
126*e7be843bSPierre Pronchery * asynchronously when the TLS handshake is complete.
127*e7be843bSPierre Pronchery *
128*e7be843bSPierre Pronchery * hostname is a string like "openssl.org" used for certificate validation.
129*e7be843bSPierre Pronchery */
130*e7be843bSPierre Pronchery
new_conn(SSL_CTX * ctx,const char * hostname,struct sockaddr * sa,socklen_t sa_len,app_connect_cb * cb,void * arg)131*e7be843bSPierre Pronchery APP_CONN *new_conn(SSL_CTX *ctx, const char *hostname,
132*e7be843bSPierre Pronchery struct sockaddr *sa, socklen_t sa_len,
133*e7be843bSPierre Pronchery app_connect_cb *cb, void *arg)
134*e7be843bSPierre Pronchery {
135*e7be843bSPierre Pronchery int rc;
136*e7be843bSPierre Pronchery APP_CONN *conn = NULL;
137*e7be843bSPierre Pronchery
138*e7be843bSPierre Pronchery conn = calloc(1, sizeof(APP_CONN));
139*e7be843bSPierre Pronchery if (!conn)
140*e7be843bSPierre Pronchery return NULL;
141*e7be843bSPierre Pronchery
142*e7be843bSPierre Pronchery #ifdef USE_QUIC
143*e7be843bSPierre Pronchery uv_udp_init(uv_default_loop(), &conn->udp);
144*e7be843bSPierre Pronchery conn->udp.data = conn;
145*e7be843bSPierre Pronchery
146*e7be843bSPierre Pronchery uv_timer_init(uv_default_loop(), &conn->timer);
147*e7be843bSPierre Pronchery conn->timer.data = conn;
148*e7be843bSPierre Pronchery #else
149*e7be843bSPierre Pronchery uv_tcp_init(uv_default_loop(), &conn->tcp);
150*e7be843bSPierre Pronchery conn->tcp.data = conn;
151*e7be843bSPierre Pronchery
152*e7be843bSPierre Pronchery conn->stream = (uv_stream_t *)&conn->tcp;
153*e7be843bSPierre Pronchery #endif
154*e7be843bSPierre Pronchery
155*e7be843bSPierre Pronchery conn->app_connect_cb = cb;
156*e7be843bSPierre Pronchery conn->app_connect_arg = arg;
157*e7be843bSPierre Pronchery #ifdef USE_QUIC
158*e7be843bSPierre Pronchery rc = uv_udp_connect(&conn->udp, sa);
159*e7be843bSPierre Pronchery #else
160*e7be843bSPierre Pronchery conn->tcp_connect.data = conn;
161*e7be843bSPierre Pronchery rc = uv_tcp_connect(&conn->tcp_connect, &conn->tcp, sa, tcp_connect_done);
162*e7be843bSPierre Pronchery #endif
163*e7be843bSPierre Pronchery if (rc < 0) {
164*e7be843bSPierre Pronchery #ifdef USE_QUIC
165*e7be843bSPierre Pronchery uv_close((uv_handle_t *)&conn->udp, net_connect_fail_close_done);
166*e7be843bSPierre Pronchery #else
167*e7be843bSPierre Pronchery uv_close((uv_handle_t *)&conn->tcp, net_connect_fail_close_done);
168*e7be843bSPierre Pronchery #endif
169*e7be843bSPierre Pronchery return NULL;
170*e7be843bSPierre Pronchery }
171*e7be843bSPierre Pronchery
172*e7be843bSPierre Pronchery conn->ctx = ctx;
173*e7be843bSPierre Pronchery conn->hostname = hostname;
174*e7be843bSPierre Pronchery
175*e7be843bSPierre Pronchery #ifdef USE_QUIC
176*e7be843bSPierre Pronchery rc = setup_ssl(conn, hostname);
177*e7be843bSPierre Pronchery if (rc < 0) {
178*e7be843bSPierre Pronchery uv_close((uv_handle_t *)&conn->udp, net_connect_fail_close_done);
179*e7be843bSPierre Pronchery return NULL;
180*e7be843bSPierre Pronchery }
181*e7be843bSPierre Pronchery #endif
182*e7be843bSPierre Pronchery
183*e7be843bSPierre Pronchery return conn;
184*e7be843bSPierre Pronchery }
185*e7be843bSPierre Pronchery
186*e7be843bSPierre Pronchery /*
187*e7be843bSPierre Pronchery * The application wants to start reading from the SSL stream.
188*e7be843bSPierre Pronchery * The callback is called whenever data is available.
189*e7be843bSPierre Pronchery */
app_read_start(APP_CONN * conn,app_read_cb * cb,void * arg)190*e7be843bSPierre Pronchery int app_read_start(APP_CONN *conn, app_read_cb *cb, void *arg)
191*e7be843bSPierre Pronchery {
192*e7be843bSPierre Pronchery conn->app_read_cb = cb;
193*e7be843bSPierre Pronchery conn->app_read_arg = arg;
194*e7be843bSPierre Pronchery set_rx(conn);
195*e7be843bSPierre Pronchery return 0;
196*e7be843bSPierre Pronchery }
197*e7be843bSPierre Pronchery
198*e7be843bSPierre Pronchery /*
199*e7be843bSPierre Pronchery * The application wants to write. The callback is called once the
200*e7be843bSPierre Pronchery * write is complete. The callback should free the buffer.
201*e7be843bSPierre Pronchery */
app_write(APP_CONN * conn,const void * buf,size_t buf_len,app_write_cb * cb,void * arg)202*e7be843bSPierre Pronchery int app_write(APP_CONN *conn, const void *buf, size_t buf_len, app_write_cb *cb, void *arg)
203*e7be843bSPierre Pronchery {
204*e7be843bSPierre Pronchery write_deferred(conn, buf, buf_len, cb, arg);
205*e7be843bSPierre Pronchery handle_pending_writes(conn);
206*e7be843bSPierre Pronchery return buf_len;
207*e7be843bSPierre Pronchery }
208*e7be843bSPierre Pronchery
209*e7be843bSPierre Pronchery /*
210*e7be843bSPierre Pronchery * The application wants to close the connection and free bookkeeping
211*e7be843bSPierre Pronchery * structures.
212*e7be843bSPierre Pronchery */
teardown(APP_CONN * conn)213*e7be843bSPierre Pronchery void teardown(APP_CONN *conn)
214*e7be843bSPierre Pronchery {
215*e7be843bSPierre Pronchery char teardown_done = 0;
216*e7be843bSPierre Pronchery
217*e7be843bSPierre Pronchery if (conn == NULL)
218*e7be843bSPierre Pronchery return;
219*e7be843bSPierre Pronchery
220*e7be843bSPierre Pronchery BIO_free_all(conn->net_bio);
221*e7be843bSPierre Pronchery SSL_free(conn->ssl);
222*e7be843bSPierre Pronchery
223*e7be843bSPierre Pronchery #ifndef USE_QUIC
224*e7be843bSPierre Pronchery uv_cancel((uv_req_t *)&conn->tcp_connect);
225*e7be843bSPierre Pronchery #endif
226*e7be843bSPierre Pronchery
227*e7be843bSPierre Pronchery conn->teardown_done = &teardown_done;
228*e7be843bSPierre Pronchery #ifdef USE_QUIC
229*e7be843bSPierre Pronchery uv_close((uv_handle_t *)&conn->udp, teardown_continued);
230*e7be843bSPierre Pronchery uv_close((uv_handle_t *)&conn->timer, teardown_continued);
231*e7be843bSPierre Pronchery #else
232*e7be843bSPierre Pronchery uv_close((uv_handle_t *)conn->stream, teardown_continued);
233*e7be843bSPierre Pronchery #endif
234*e7be843bSPierre Pronchery
235*e7be843bSPierre Pronchery /* Just wait synchronously until teardown completes. */
236*e7be843bSPierre Pronchery #ifdef USE_QUIC
237*e7be843bSPierre Pronchery while (teardown_done < 2)
238*e7be843bSPierre Pronchery #else
239*e7be843bSPierre Pronchery while (!teardown_done)
240*e7be843bSPierre Pronchery #endif
241*e7be843bSPierre Pronchery uv_run(uv_default_loop(), UV_RUN_DEFAULT);
242*e7be843bSPierre Pronchery }
243*e7be843bSPierre Pronchery
244*e7be843bSPierre Pronchery /*
245*e7be843bSPierre Pronchery * The application is shutting down and wants to free a previously
246*e7be843bSPierre Pronchery * created SSL_CTX.
247*e7be843bSPierre Pronchery */
teardown_ctx(SSL_CTX * ctx)248*e7be843bSPierre Pronchery void teardown_ctx(SSL_CTX *ctx)
249*e7be843bSPierre Pronchery {
250*e7be843bSPierre Pronchery SSL_CTX_free(ctx);
251*e7be843bSPierre Pronchery }
252*e7be843bSPierre Pronchery
253*e7be843bSPierre Pronchery /*
254*e7be843bSPierre Pronchery * ============================================================================
255*e7be843bSPierre Pronchery * Internal implementation functions.
256*e7be843bSPierre Pronchery */
enqueue_upper_write_op(APP_CONN * conn,UPPER_WRITE_OP * op)257*e7be843bSPierre Pronchery static void enqueue_upper_write_op(APP_CONN *conn, UPPER_WRITE_OP *op)
258*e7be843bSPierre Pronchery {
259*e7be843bSPierre Pronchery op->prev = conn->pending_upper_write_tail;
260*e7be843bSPierre Pronchery if (op->prev)
261*e7be843bSPierre Pronchery op->prev->next = op;
262*e7be843bSPierre Pronchery
263*e7be843bSPierre Pronchery conn->pending_upper_write_tail = op;
264*e7be843bSPierre Pronchery if (conn->pending_upper_write_head == NULL)
265*e7be843bSPierre Pronchery conn->pending_upper_write_head = op;
266*e7be843bSPierre Pronchery }
267*e7be843bSPierre Pronchery
dequeue_upper_write_op(APP_CONN * conn)268*e7be843bSPierre Pronchery static void dequeue_upper_write_op(APP_CONN *conn)
269*e7be843bSPierre Pronchery {
270*e7be843bSPierre Pronchery if (conn->pending_upper_write_head == NULL)
271*e7be843bSPierre Pronchery return;
272*e7be843bSPierre Pronchery
273*e7be843bSPierre Pronchery if (conn->pending_upper_write_head->next == NULL) {
274*e7be843bSPierre Pronchery conn->pending_upper_write_head = NULL;
275*e7be843bSPierre Pronchery conn->pending_upper_write_tail = NULL;
276*e7be843bSPierre Pronchery } else {
277*e7be843bSPierre Pronchery conn->pending_upper_write_head = conn->pending_upper_write_head->next;
278*e7be843bSPierre Pronchery conn->pending_upper_write_head->prev = NULL;
279*e7be843bSPierre Pronchery }
280*e7be843bSPierre Pronchery }
281*e7be843bSPierre Pronchery
net_read_alloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)282*e7be843bSPierre Pronchery static void net_read_alloc(uv_handle_t *handle,
283*e7be843bSPierre Pronchery size_t suggested_size, uv_buf_t *buf)
284*e7be843bSPierre Pronchery {
285*e7be843bSPierre Pronchery #ifdef USE_QUIC
286*e7be843bSPierre Pronchery if (suggested_size < 1472)
287*e7be843bSPierre Pronchery suggested_size = 1472;
288*e7be843bSPierre Pronchery #endif
289*e7be843bSPierre Pronchery
290*e7be843bSPierre Pronchery buf->base = malloc(suggested_size);
291*e7be843bSPierre Pronchery buf->len = suggested_size;
292*e7be843bSPierre Pronchery }
293*e7be843bSPierre Pronchery
on_rx_push(APP_CONN * conn)294*e7be843bSPierre Pronchery static void on_rx_push(APP_CONN *conn)
295*e7be843bSPierre Pronchery {
296*e7be843bSPierre Pronchery int srd, rc;
297*e7be843bSPierre Pronchery int buf_len = 4096;
298*e7be843bSPierre Pronchery
299*e7be843bSPierre Pronchery do {
300*e7be843bSPierre Pronchery if (!conn->app_read_cb)
301*e7be843bSPierre Pronchery return;
302*e7be843bSPierre Pronchery
303*e7be843bSPierre Pronchery void *buf = malloc(buf_len);
304*e7be843bSPierre Pronchery if (!buf)
305*e7be843bSPierre Pronchery return;
306*e7be843bSPierre Pronchery
307*e7be843bSPierre Pronchery srd = SSL_read(conn->ssl, buf, buf_len);
308*e7be843bSPierre Pronchery flush_write_buf(conn);
309*e7be843bSPierre Pronchery if (srd <= 0) {
310*e7be843bSPierre Pronchery rc = SSL_get_error(conn->ssl, srd);
311*e7be843bSPierre Pronchery if (rc == SSL_ERROR_WANT_READ) {
312*e7be843bSPierre Pronchery free(buf);
313*e7be843bSPierre Pronchery return;
314*e7be843bSPierre Pronchery }
315*e7be843bSPierre Pronchery }
316*e7be843bSPierre Pronchery
317*e7be843bSPierre Pronchery conn->app_read_cb(conn, buf, srd, conn->app_read_arg);
318*e7be843bSPierre Pronchery } while (srd == buf_len);
319*e7be843bSPierre Pronchery }
320*e7be843bSPierre Pronchery
net_error(APP_CONN * conn)321*e7be843bSPierre Pronchery static void net_error(APP_CONN *conn)
322*e7be843bSPierre Pronchery {
323*e7be843bSPierre Pronchery conn->closed = 1;
324*e7be843bSPierre Pronchery set_rx(conn);
325*e7be843bSPierre Pronchery
326*e7be843bSPierre Pronchery if (conn->app_read_cb)
327*e7be843bSPierre Pronchery conn->app_read_cb(conn, NULL, 0, conn->app_read_arg);
328*e7be843bSPierre Pronchery }
329*e7be843bSPierre Pronchery
handle_pending_writes(APP_CONN * conn)330*e7be843bSPierre Pronchery static void handle_pending_writes(APP_CONN *conn)
331*e7be843bSPierre Pronchery {
332*e7be843bSPierre Pronchery int rc;
333*e7be843bSPierre Pronchery
334*e7be843bSPierre Pronchery if (conn->pending_upper_write_head == NULL)
335*e7be843bSPierre Pronchery return;
336*e7be843bSPierre Pronchery
337*e7be843bSPierre Pronchery do {
338*e7be843bSPierre Pronchery UPPER_WRITE_OP *op = conn->pending_upper_write_head;
339*e7be843bSPierre Pronchery rc = try_write(conn, op);
340*e7be843bSPierre Pronchery if (rc <= 0)
341*e7be843bSPierre Pronchery break;
342*e7be843bSPierre Pronchery
343*e7be843bSPierre Pronchery dequeue_upper_write_op(conn);
344*e7be843bSPierre Pronchery free(op);
345*e7be843bSPierre Pronchery } while (conn->pending_upper_write_head != NULL);
346*e7be843bSPierre Pronchery
347*e7be843bSPierre Pronchery set_rx(conn);
348*e7be843bSPierre Pronchery }
349*e7be843bSPierre Pronchery
350*e7be843bSPierre Pronchery #ifdef USE_QUIC
net_read_done(uv_udp_t * stream,ssize_t nr,const uv_buf_t * buf,const struct sockaddr * addr,unsigned int flags)351*e7be843bSPierre Pronchery static void net_read_done(uv_udp_t *stream, ssize_t nr, const uv_buf_t *buf,
352*e7be843bSPierre Pronchery const struct sockaddr *addr, unsigned int flags)
353*e7be843bSPierre Pronchery #else
354*e7be843bSPierre Pronchery static void net_read_done(uv_stream_t *stream, ssize_t nr, const uv_buf_t *buf)
355*e7be843bSPierre Pronchery #endif
356*e7be843bSPierre Pronchery {
357*e7be843bSPierre Pronchery int rc;
358*e7be843bSPierre Pronchery APP_CONN *conn = (APP_CONN *)stream->data;
359*e7be843bSPierre Pronchery
360*e7be843bSPierre Pronchery if (nr < 0) {
361*e7be843bSPierre Pronchery free(buf->base);
362*e7be843bSPierre Pronchery net_error(conn);
363*e7be843bSPierre Pronchery return;
364*e7be843bSPierre Pronchery }
365*e7be843bSPierre Pronchery
366*e7be843bSPierre Pronchery if (nr > 0) {
367*e7be843bSPierre Pronchery int wr = BIO_write(conn->net_bio, buf->base, nr);
368*e7be843bSPierre Pronchery assert(wr == nr);
369*e7be843bSPierre Pronchery }
370*e7be843bSPierre Pronchery
371*e7be843bSPierre Pronchery free(buf->base);
372*e7be843bSPierre Pronchery
373*e7be843bSPierre Pronchery if (!conn->done_handshake) {
374*e7be843bSPierre Pronchery rc = handshake_ssl(conn);
375*e7be843bSPierre Pronchery if (rc < 0) {
376*e7be843bSPierre Pronchery fprintf(stderr, "handshake error: %d\n", rc);
377*e7be843bSPierre Pronchery return;
378*e7be843bSPierre Pronchery }
379*e7be843bSPierre Pronchery
380*e7be843bSPierre Pronchery if (!conn->done_handshake)
381*e7be843bSPierre Pronchery return;
382*e7be843bSPierre Pronchery }
383*e7be843bSPierre Pronchery
384*e7be843bSPierre Pronchery handle_pending_writes(conn);
385*e7be843bSPierre Pronchery on_rx_push(conn);
386*e7be843bSPierre Pronchery }
387*e7be843bSPierre Pronchery
set_rx(APP_CONN * conn)388*e7be843bSPierre Pronchery static void set_rx(APP_CONN *conn)
389*e7be843bSPierre Pronchery {
390*e7be843bSPierre Pronchery #ifdef USE_QUIC
391*e7be843bSPierre Pronchery if (!conn->closed)
392*e7be843bSPierre Pronchery uv_udp_recv_start(&conn->udp, net_read_alloc, net_read_done);
393*e7be843bSPierre Pronchery else
394*e7be843bSPierre Pronchery uv_udp_recv_stop(&conn->udp);
395*e7be843bSPierre Pronchery #else
396*e7be843bSPierre Pronchery if (!conn->closed && (conn->app_read_cb || (!conn->done_handshake && conn->init_handshake) || conn->pending_upper_write_head != NULL))
397*e7be843bSPierre Pronchery uv_read_start(conn->stream, net_read_alloc, net_read_done);
398*e7be843bSPierre Pronchery else
399*e7be843bSPierre Pronchery uv_read_stop(conn->stream);
400*e7be843bSPierre Pronchery #endif
401*e7be843bSPierre Pronchery }
402*e7be843bSPierre Pronchery
403*e7be843bSPierre Pronchery #ifdef USE_QUIC
net_write_done(uv_udp_send_t * req,int status)404*e7be843bSPierre Pronchery static void net_write_done(uv_udp_send_t *req, int status)
405*e7be843bSPierre Pronchery #else
406*e7be843bSPierre Pronchery static void net_write_done(uv_write_t *req, int status)
407*e7be843bSPierre Pronchery #endif
408*e7be843bSPierre Pronchery {
409*e7be843bSPierre Pronchery LOWER_WRITE_OP *op = (LOWER_WRITE_OP *)req->data;
410*e7be843bSPierre Pronchery APP_CONN *conn = op->conn;
411*e7be843bSPierre Pronchery
412*e7be843bSPierre Pronchery if (status < 0) {
413*e7be843bSPierre Pronchery fprintf(stderr, "UV write failed %d\n", status);
414*e7be843bSPierre Pronchery return;
415*e7be843bSPierre Pronchery }
416*e7be843bSPierre Pronchery
417*e7be843bSPierre Pronchery free(op->buf);
418*e7be843bSPierre Pronchery free(op);
419*e7be843bSPierre Pronchery
420*e7be843bSPierre Pronchery flush_write_buf(conn);
421*e7be843bSPierre Pronchery }
422*e7be843bSPierre Pronchery
flush_write_buf(APP_CONN * conn)423*e7be843bSPierre Pronchery static void flush_write_buf(APP_CONN *conn)
424*e7be843bSPierre Pronchery {
425*e7be843bSPierre Pronchery int rc, rd;
426*e7be843bSPierre Pronchery LOWER_WRITE_OP *op;
427*e7be843bSPierre Pronchery uint8_t *buf;
428*e7be843bSPierre Pronchery
429*e7be843bSPierre Pronchery buf = malloc(4096);
430*e7be843bSPierre Pronchery if (!buf)
431*e7be843bSPierre Pronchery return;
432*e7be843bSPierre Pronchery
433*e7be843bSPierre Pronchery rd = BIO_read(conn->net_bio, buf, 4096);
434*e7be843bSPierre Pronchery if (rd <= 0) {
435*e7be843bSPierre Pronchery free(buf);
436*e7be843bSPierre Pronchery return;
437*e7be843bSPierre Pronchery }
438*e7be843bSPierre Pronchery
439*e7be843bSPierre Pronchery op = calloc(1, sizeof(LOWER_WRITE_OP));
440*e7be843bSPierre Pronchery if (!op)
441*e7be843bSPierre Pronchery return;
442*e7be843bSPierre Pronchery
443*e7be843bSPierre Pronchery op->buf = buf;
444*e7be843bSPierre Pronchery op->conn = conn;
445*e7be843bSPierre Pronchery op->w.data = op;
446*e7be843bSPierre Pronchery op->b.base = (char *)buf;
447*e7be843bSPierre Pronchery op->b.len = rd;
448*e7be843bSPierre Pronchery
449*e7be843bSPierre Pronchery #ifdef USE_QUIC
450*e7be843bSPierre Pronchery rc = uv_udp_send(&op->w, &conn->udp, &op->b, 1, NULL, net_write_done);
451*e7be843bSPierre Pronchery #else
452*e7be843bSPierre Pronchery rc = uv_write(&op->w, conn->stream, &op->b, 1, net_write_done);
453*e7be843bSPierre Pronchery #endif
454*e7be843bSPierre Pronchery if (rc < 0) {
455*e7be843bSPierre Pronchery free(buf);
456*e7be843bSPierre Pronchery free(op);
457*e7be843bSPierre Pronchery fprintf(stderr, "UV write failed\n");
458*e7be843bSPierre Pronchery return;
459*e7be843bSPierre Pronchery }
460*e7be843bSPierre Pronchery }
461*e7be843bSPierre Pronchery
handshake_done_ssl(APP_CONN * conn)462*e7be843bSPierre Pronchery static void handshake_done_ssl(APP_CONN *conn)
463*e7be843bSPierre Pronchery {
464*e7be843bSPierre Pronchery #ifdef USE_QUIC
465*e7be843bSPierre Pronchery set_timer(conn);
466*e7be843bSPierre Pronchery #endif
467*e7be843bSPierre Pronchery conn->app_connect_cb(conn, 0, conn->app_connect_arg);
468*e7be843bSPierre Pronchery }
469*e7be843bSPierre Pronchery
handshake_ssl(APP_CONN * conn)470*e7be843bSPierre Pronchery static int handshake_ssl(APP_CONN *conn)
471*e7be843bSPierre Pronchery {
472*e7be843bSPierre Pronchery int rc, rcx;
473*e7be843bSPierre Pronchery
474*e7be843bSPierre Pronchery conn->init_handshake = 1;
475*e7be843bSPierre Pronchery
476*e7be843bSPierre Pronchery rc = SSL_do_handshake(conn->ssl);
477*e7be843bSPierre Pronchery if (rc > 0) {
478*e7be843bSPierre Pronchery conn->done_handshake = 1;
479*e7be843bSPierre Pronchery handshake_done_ssl(conn);
480*e7be843bSPierre Pronchery set_rx(conn);
481*e7be843bSPierre Pronchery return 0;
482*e7be843bSPierre Pronchery }
483*e7be843bSPierre Pronchery
484*e7be843bSPierre Pronchery flush_write_buf(conn);
485*e7be843bSPierre Pronchery rcx = SSL_get_error(conn->ssl, rc);
486*e7be843bSPierre Pronchery if (rcx == SSL_ERROR_WANT_READ) {
487*e7be843bSPierre Pronchery set_rx(conn);
488*e7be843bSPierre Pronchery return 0;
489*e7be843bSPierre Pronchery }
490*e7be843bSPierre Pronchery
491*e7be843bSPierre Pronchery fprintf(stderr, "Handshake error: %d\n", rcx);
492*e7be843bSPierre Pronchery return -rcx;
493*e7be843bSPierre Pronchery }
494*e7be843bSPierre Pronchery
setup_ssl(APP_CONN * conn,const char * hostname)495*e7be843bSPierre Pronchery static int setup_ssl(APP_CONN *conn, const char *hostname)
496*e7be843bSPierre Pronchery {
497*e7be843bSPierre Pronchery BIO *internal_bio = NULL, *net_bio = NULL;
498*e7be843bSPierre Pronchery SSL *ssl = NULL;
499*e7be843bSPierre Pronchery #ifdef USE_QUIC
500*e7be843bSPierre Pronchery static const unsigned char alpn[] = {5, 'd', 'u', 'm', 'm', 'y'};
501*e7be843bSPierre Pronchery #endif
502*e7be843bSPierre Pronchery
503*e7be843bSPierre Pronchery ssl = SSL_new(conn->ctx);
504*e7be843bSPierre Pronchery if (!ssl)
505*e7be843bSPierre Pronchery return -1;
506*e7be843bSPierre Pronchery
507*e7be843bSPierre Pronchery SSL_set_connect_state(ssl);
508*e7be843bSPierre Pronchery
509*e7be843bSPierre Pronchery #ifdef USE_QUIC
510*e7be843bSPierre Pronchery if (BIO_new_bio_dgram_pair(&internal_bio, 0, &net_bio, 0) <= 0) {
511*e7be843bSPierre Pronchery SSL_free(ssl);
512*e7be843bSPierre Pronchery return -1;
513*e7be843bSPierre Pronchery }
514*e7be843bSPierre Pronchery #else
515*e7be843bSPierre Pronchery if (BIO_new_bio_pair(&internal_bio, 0, &net_bio, 0) <= 0) {
516*e7be843bSPierre Pronchery SSL_free(ssl);
517*e7be843bSPierre Pronchery return -1;
518*e7be843bSPierre Pronchery }
519*e7be843bSPierre Pronchery #endif
520*e7be843bSPierre Pronchery
521*e7be843bSPierre Pronchery SSL_set_bio(ssl, internal_bio, internal_bio);
522*e7be843bSPierre Pronchery
523*e7be843bSPierre Pronchery if (SSL_set1_host(ssl, hostname) <= 0) {
524*e7be843bSPierre Pronchery SSL_free(ssl);
525*e7be843bSPierre Pronchery return -1;
526*e7be843bSPierre Pronchery }
527*e7be843bSPierre Pronchery
528*e7be843bSPierre Pronchery if (SSL_set_tlsext_host_name(ssl, hostname) <= 0) {
529*e7be843bSPierre Pronchery SSL_free(ssl);
530*e7be843bSPierre Pronchery return -1;
531*e7be843bSPierre Pronchery }
532*e7be843bSPierre Pronchery
533*e7be843bSPierre Pronchery #ifdef USE_QUIC
534*e7be843bSPierre Pronchery /* Configure ALPN, which is required for QUIC. */
535*e7be843bSPierre Pronchery if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) {
536*e7be843bSPierre Pronchery /* Note: SSL_set_alpn_protos returns 1 for failure. */
537*e7be843bSPierre Pronchery SSL_free(ssl);
538*e7be843bSPierre Pronchery return -1;
539*e7be843bSPierre Pronchery }
540*e7be843bSPierre Pronchery #endif
541*e7be843bSPierre Pronchery
542*e7be843bSPierre Pronchery conn->net_bio = net_bio;
543*e7be843bSPierre Pronchery conn->ssl = ssl;
544*e7be843bSPierre Pronchery return handshake_ssl(conn);
545*e7be843bSPierre Pronchery }
546*e7be843bSPierre Pronchery
547*e7be843bSPierre Pronchery #ifndef USE_QUIC
tcp_connect_done(uv_connect_t * tcp_connect,int status)548*e7be843bSPierre Pronchery static void tcp_connect_done(uv_connect_t *tcp_connect, int status)
549*e7be843bSPierre Pronchery {
550*e7be843bSPierre Pronchery int rc;
551*e7be843bSPierre Pronchery APP_CONN *conn = (APP_CONN *)tcp_connect->data;
552*e7be843bSPierre Pronchery
553*e7be843bSPierre Pronchery if (status < 0) {
554*e7be843bSPierre Pronchery uv_stop(uv_default_loop());
555*e7be843bSPierre Pronchery return;
556*e7be843bSPierre Pronchery }
557*e7be843bSPierre Pronchery
558*e7be843bSPierre Pronchery rc = setup_ssl(conn, conn->hostname);
559*e7be843bSPierre Pronchery if (rc < 0) {
560*e7be843bSPierre Pronchery fprintf(stderr, "cannot init SSL\n");
561*e7be843bSPierre Pronchery uv_stop(uv_default_loop());
562*e7be843bSPierre Pronchery return;
563*e7be843bSPierre Pronchery }
564*e7be843bSPierre Pronchery }
565*e7be843bSPierre Pronchery #endif
566*e7be843bSPierre Pronchery
net_connect_fail_close_done(uv_handle_t * handle)567*e7be843bSPierre Pronchery static void net_connect_fail_close_done(uv_handle_t *handle)
568*e7be843bSPierre Pronchery {
569*e7be843bSPierre Pronchery APP_CONN *conn = (APP_CONN *)handle->data;
570*e7be843bSPierre Pronchery
571*e7be843bSPierre Pronchery free(conn);
572*e7be843bSPierre Pronchery }
573*e7be843bSPierre Pronchery
574*e7be843bSPierre Pronchery #ifdef USE_QUIC
575*e7be843bSPierre Pronchery
timer_done(uv_timer_t * timer)576*e7be843bSPierre Pronchery static void timer_done(uv_timer_t *timer)
577*e7be843bSPierre Pronchery {
578*e7be843bSPierre Pronchery APP_CONN *conn = (APP_CONN *)timer->data;
579*e7be843bSPierre Pronchery
580*e7be843bSPierre Pronchery SSL_handle_events(conn->ssl);
581*e7be843bSPierre Pronchery handle_pending_writes(conn);
582*e7be843bSPierre Pronchery flush_write_buf(conn);
583*e7be843bSPierre Pronchery set_rx(conn);
584*e7be843bSPierre Pronchery set_timer(conn); /* repeat timer */
585*e7be843bSPierre Pronchery }
586*e7be843bSPierre Pronchery
set_timer(APP_CONN * conn)587*e7be843bSPierre Pronchery static void set_timer(APP_CONN *conn)
588*e7be843bSPierre Pronchery {
589*e7be843bSPierre Pronchery struct timeval tv;
590*e7be843bSPierre Pronchery int ms, is_infinite;
591*e7be843bSPierre Pronchery
592*e7be843bSPierre Pronchery if (!SSL_get_event_timeout(conn->ssl, &tv, &is_infinite))
593*e7be843bSPierre Pronchery return;
594*e7be843bSPierre Pronchery
595*e7be843bSPierre Pronchery ms = is_infinite ? -1 : timeval_to_ms(&tv);
596*e7be843bSPierre Pronchery if (ms > 0)
597*e7be843bSPierre Pronchery uv_timer_start(&conn->timer, timer_done, ms, 0);
598*e7be843bSPierre Pronchery }
599*e7be843bSPierre Pronchery
600*e7be843bSPierre Pronchery #endif
601*e7be843bSPierre Pronchery
try_write(APP_CONN * conn,UPPER_WRITE_OP * op)602*e7be843bSPierre Pronchery static int try_write(APP_CONN *conn, UPPER_WRITE_OP *op)
603*e7be843bSPierre Pronchery {
604*e7be843bSPierre Pronchery int rc, rcx;
605*e7be843bSPierre Pronchery size_t written = op->written;
606*e7be843bSPierre Pronchery
607*e7be843bSPierre Pronchery while (written < op->buf_len) {
608*e7be843bSPierre Pronchery rc = SSL_write(conn->ssl, op->buf + written, op->buf_len - written);
609*e7be843bSPierre Pronchery if (rc <= 0) {
610*e7be843bSPierre Pronchery rcx = SSL_get_error(conn->ssl, rc);
611*e7be843bSPierre Pronchery if (rcx == SSL_ERROR_WANT_READ) {
612*e7be843bSPierre Pronchery op->written = written;
613*e7be843bSPierre Pronchery return 0;
614*e7be843bSPierre Pronchery } else {
615*e7be843bSPierre Pronchery if (op->cb != NULL)
616*e7be843bSPierre Pronchery op->cb(conn, -rcx, op->cb_arg);
617*e7be843bSPierre Pronchery return 1; /* op should be freed */
618*e7be843bSPierre Pronchery }
619*e7be843bSPierre Pronchery }
620*e7be843bSPierre Pronchery
621*e7be843bSPierre Pronchery written += rc;
622*e7be843bSPierre Pronchery }
623*e7be843bSPierre Pronchery
624*e7be843bSPierre Pronchery if (op->cb != NULL)
625*e7be843bSPierre Pronchery op->cb(conn, 0, op->cb_arg);
626*e7be843bSPierre Pronchery
627*e7be843bSPierre Pronchery flush_write_buf(conn);
628*e7be843bSPierre Pronchery return 1; /* op should be freed */
629*e7be843bSPierre Pronchery }
630*e7be843bSPierre Pronchery
write_deferred(APP_CONN * conn,const void * buf,size_t buf_len,app_write_cb * cb,void * arg)631*e7be843bSPierre Pronchery static int write_deferred(APP_CONN *conn, const void *buf, size_t buf_len, app_write_cb *cb, void *arg)
632*e7be843bSPierre Pronchery {
633*e7be843bSPierre Pronchery UPPER_WRITE_OP *op = calloc(1, sizeof(UPPER_WRITE_OP));
634*e7be843bSPierre Pronchery if (!op)
635*e7be843bSPierre Pronchery return -1;
636*e7be843bSPierre Pronchery
637*e7be843bSPierre Pronchery op->buf = buf;
638*e7be843bSPierre Pronchery op->buf_len = buf_len;
639*e7be843bSPierre Pronchery op->conn = conn;
640*e7be843bSPierre Pronchery op->cb = cb;
641*e7be843bSPierre Pronchery op->cb_arg = arg;
642*e7be843bSPierre Pronchery
643*e7be843bSPierre Pronchery enqueue_upper_write_op(conn, op);
644*e7be843bSPierre Pronchery set_rx(conn);
645*e7be843bSPierre Pronchery flush_write_buf(conn);
646*e7be843bSPierre Pronchery return buf_len;
647*e7be843bSPierre Pronchery }
648*e7be843bSPierre Pronchery
teardown_continued(uv_handle_t * handle)649*e7be843bSPierre Pronchery static void teardown_continued(uv_handle_t *handle)
650*e7be843bSPierre Pronchery {
651*e7be843bSPierre Pronchery APP_CONN *conn = (APP_CONN *)handle->data;
652*e7be843bSPierre Pronchery UPPER_WRITE_OP *op, *next_op;
653*e7be843bSPierre Pronchery char *teardown_done = conn->teardown_done;
654*e7be843bSPierre Pronchery
655*e7be843bSPierre Pronchery #ifdef USE_QUIC
656*e7be843bSPierre Pronchery if (++*teardown_done < 2)
657*e7be843bSPierre Pronchery return;
658*e7be843bSPierre Pronchery #endif
659*e7be843bSPierre Pronchery
660*e7be843bSPierre Pronchery for (op=conn->pending_upper_write_head; op; op=next_op) {
661*e7be843bSPierre Pronchery next_op = op->next;
662*e7be843bSPierre Pronchery free(op);
663*e7be843bSPierre Pronchery }
664*e7be843bSPierre Pronchery
665*e7be843bSPierre Pronchery free(conn);
666*e7be843bSPierre Pronchery #ifndef USE_QUIC
667*e7be843bSPierre Pronchery *teardown_done = 1;
668*e7be843bSPierre Pronchery #endif
669*e7be843bSPierre Pronchery }
670*e7be843bSPierre Pronchery
671*e7be843bSPierre Pronchery /*
672*e7be843bSPierre Pronchery * ============================================================================
673*e7be843bSPierre Pronchery * Example driver for the above code. This is just to demonstrate that the code
674*e7be843bSPierre Pronchery * works and is not intended to be representative of a real application.
675*e7be843bSPierre Pronchery */
post_read(APP_CONN * conn,void * buf,size_t buf_len,void * arg)676*e7be843bSPierre Pronchery static void post_read(APP_CONN *conn, void *buf, size_t buf_len, void *arg)
677*e7be843bSPierre Pronchery {
678*e7be843bSPierre Pronchery if (!buf_len) {
679*e7be843bSPierre Pronchery free(buf);
680*e7be843bSPierre Pronchery uv_stop(uv_default_loop());
681*e7be843bSPierre Pronchery return;
682*e7be843bSPierre Pronchery }
683*e7be843bSPierre Pronchery
684*e7be843bSPierre Pronchery fwrite(buf, 1, buf_len, stdout);
685*e7be843bSPierre Pronchery free(buf);
686*e7be843bSPierre Pronchery }
687*e7be843bSPierre Pronchery
post_write_get(APP_CONN * conn,int status,void * arg)688*e7be843bSPierre Pronchery static void post_write_get(APP_CONN *conn, int status, void *arg)
689*e7be843bSPierre Pronchery {
690*e7be843bSPierre Pronchery if (status < 0) {
691*e7be843bSPierre Pronchery fprintf(stderr, "write failed: %d\n", status);
692*e7be843bSPierre Pronchery return;
693*e7be843bSPierre Pronchery }
694*e7be843bSPierre Pronchery
695*e7be843bSPierre Pronchery app_read_start(conn, post_read, NULL);
696*e7be843bSPierre Pronchery }
697*e7be843bSPierre Pronchery
698*e7be843bSPierre Pronchery char tx_msg[300];
699*e7be843bSPierre Pronchery int mlen;
700*e7be843bSPierre Pronchery
post_connect(APP_CONN * conn,int status,void * arg)701*e7be843bSPierre Pronchery static void post_connect(APP_CONN *conn, int status, void *arg)
702*e7be843bSPierre Pronchery {
703*e7be843bSPierre Pronchery int wr;
704*e7be843bSPierre Pronchery
705*e7be843bSPierre Pronchery if (status < 0) {
706*e7be843bSPierre Pronchery fprintf(stderr, "failed to connect: %d\n", status);
707*e7be843bSPierre Pronchery uv_stop(uv_default_loop());
708*e7be843bSPierre Pronchery return;
709*e7be843bSPierre Pronchery }
710*e7be843bSPierre Pronchery
711*e7be843bSPierre Pronchery wr = app_write(conn, tx_msg, mlen, post_write_get, NULL);
712*e7be843bSPierre Pronchery if (wr < mlen) {
713*e7be843bSPierre Pronchery fprintf(stderr, "error writing request");
714*e7be843bSPierre Pronchery return;
715*e7be843bSPierre Pronchery }
716*e7be843bSPierre Pronchery }
717*e7be843bSPierre Pronchery
main(int argc,char ** argv)718*e7be843bSPierre Pronchery int main(int argc, char **argv)
719*e7be843bSPierre Pronchery {
720*e7be843bSPierre Pronchery int rc = 1;
721*e7be843bSPierre Pronchery SSL_CTX *ctx = NULL;
722*e7be843bSPierre Pronchery APP_CONN *conn = NULL;
723*e7be843bSPierre Pronchery struct addrinfo hints = {0}, *result = NULL;
724*e7be843bSPierre Pronchery
725*e7be843bSPierre Pronchery if (argc < 3) {
726*e7be843bSPierre Pronchery fprintf(stderr, "usage: %s host port\n", argv[0]);
727*e7be843bSPierre Pronchery goto fail;
728*e7be843bSPierre Pronchery }
729*e7be843bSPierre Pronchery
730*e7be843bSPierre Pronchery mlen = snprintf(tx_msg, sizeof(tx_msg),
731*e7be843bSPierre Pronchery "GET / HTTP/1.0\r\nHost: %s\r\n\r\n", argv[1]);
732*e7be843bSPierre Pronchery
733*e7be843bSPierre Pronchery ctx = create_ssl_ctx();
734*e7be843bSPierre Pronchery if (!ctx)
735*e7be843bSPierre Pronchery goto fail;
736*e7be843bSPierre Pronchery
737*e7be843bSPierre Pronchery hints.ai_family = AF_INET;
738*e7be843bSPierre Pronchery hints.ai_socktype = SOCK_STREAM;
739*e7be843bSPierre Pronchery hints.ai_flags = AI_PASSIVE;
740*e7be843bSPierre Pronchery rc = getaddrinfo(argv[1], argv[2], &hints, &result);
741*e7be843bSPierre Pronchery if (rc < 0) {
742*e7be843bSPierre Pronchery fprintf(stderr, "cannot resolve\n");
743*e7be843bSPierre Pronchery goto fail;
744*e7be843bSPierre Pronchery }
745*e7be843bSPierre Pronchery
746*e7be843bSPierre Pronchery conn = new_conn(ctx, argv[1], result->ai_addr, result->ai_addrlen, post_connect, NULL);
747*e7be843bSPierre Pronchery if (!conn)
748*e7be843bSPierre Pronchery goto fail;
749*e7be843bSPierre Pronchery
750*e7be843bSPierre Pronchery uv_run(uv_default_loop(), UV_RUN_DEFAULT);
751*e7be843bSPierre Pronchery
752*e7be843bSPierre Pronchery rc = 0;
753*e7be843bSPierre Pronchery fail:
754*e7be843bSPierre Pronchery teardown(conn);
755*e7be843bSPierre Pronchery freeaddrinfo(result);
756*e7be843bSPierre Pronchery uv_loop_close(uv_default_loop());
757*e7be843bSPierre Pronchery teardown_ctx(ctx);
758*e7be843bSPierre Pronchery }
759