xref: /third_party/openssl/crypto/bio/bss_conn.c (revision e1051a39)
1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stdio.h>
11e1051a39Sopenharmony_ci#include <errno.h>
12e1051a39Sopenharmony_ci
13e1051a39Sopenharmony_ci#include "bio_local.h"
14e1051a39Sopenharmony_ci#include "internal/ktls.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SOCK
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_citypedef struct bio_connect_st {
19e1051a39Sopenharmony_ci    int state;
20e1051a39Sopenharmony_ci    int connect_family;
21e1051a39Sopenharmony_ci    char *param_hostname;
22e1051a39Sopenharmony_ci    char *param_service;
23e1051a39Sopenharmony_ci    int connect_mode;
24e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_KTLS
25e1051a39Sopenharmony_ci    unsigned char record_type;
26e1051a39Sopenharmony_ci# endif
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_ci    BIO_ADDRINFO *addr_first;
29e1051a39Sopenharmony_ci    const BIO_ADDRINFO *addr_iter;
30e1051a39Sopenharmony_ci    /*
31e1051a39Sopenharmony_ci     * int socket; this will be kept in bio->num so that it is compatible
32e1051a39Sopenharmony_ci     * with the bss_sock bio
33e1051a39Sopenharmony_ci     */
34e1051a39Sopenharmony_ci    /*
35e1051a39Sopenharmony_ci     * called when the connection is initially made callback(BIO,state,ret);
36e1051a39Sopenharmony_ci     * The callback should return 'ret'.  state is for compatibility with the
37e1051a39Sopenharmony_ci     * ssl info_callback
38e1051a39Sopenharmony_ci     */
39e1051a39Sopenharmony_ci    BIO_info_cb *info_callback;
40e1051a39Sopenharmony_ci} BIO_CONNECT;
41e1051a39Sopenharmony_ci
42e1051a39Sopenharmony_cistatic int conn_write(BIO *h, const char *buf, int num);
43e1051a39Sopenharmony_cistatic int conn_read(BIO *h, char *buf, int size);
44e1051a39Sopenharmony_cistatic int conn_puts(BIO *h, const char *str);
45e1051a39Sopenharmony_cistatic long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2);
46e1051a39Sopenharmony_cistatic int conn_new(BIO *h);
47e1051a39Sopenharmony_cistatic int conn_free(BIO *data);
48e1051a39Sopenharmony_cistatic long conn_callback_ctrl(BIO *h, int cmd, BIO_info_cb *);
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_cistatic int conn_state(BIO *b, BIO_CONNECT *c);
51e1051a39Sopenharmony_cistatic void conn_close_socket(BIO *data);
52e1051a39Sopenharmony_ciBIO_CONNECT *BIO_CONNECT_new(void);
53e1051a39Sopenharmony_civoid BIO_CONNECT_free(BIO_CONNECT *a);
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_ci#define BIO_CONN_S_BEFORE                1
56e1051a39Sopenharmony_ci#define BIO_CONN_S_GET_ADDR              2
57e1051a39Sopenharmony_ci#define BIO_CONN_S_CREATE_SOCKET         3
58e1051a39Sopenharmony_ci#define BIO_CONN_S_CONNECT               4
59e1051a39Sopenharmony_ci#define BIO_CONN_S_OK                    5
60e1051a39Sopenharmony_ci#define BIO_CONN_S_BLOCKED_CONNECT       6
61e1051a39Sopenharmony_ci#define BIO_CONN_S_CONNECT_ERROR         7
62e1051a39Sopenharmony_ci
63e1051a39Sopenharmony_cistatic const BIO_METHOD methods_connectp = {
64e1051a39Sopenharmony_ci    BIO_TYPE_CONNECT,
65e1051a39Sopenharmony_ci    "socket connect",
66e1051a39Sopenharmony_ci    bwrite_conv,
67e1051a39Sopenharmony_ci    conn_write,
68e1051a39Sopenharmony_ci    bread_conv,
69e1051a39Sopenharmony_ci    conn_read,
70e1051a39Sopenharmony_ci    conn_puts,
71e1051a39Sopenharmony_ci    NULL,                       /* conn_gets, */
72e1051a39Sopenharmony_ci    conn_ctrl,
73e1051a39Sopenharmony_ci    conn_new,
74e1051a39Sopenharmony_ci    conn_free,
75e1051a39Sopenharmony_ci    conn_callback_ctrl,
76e1051a39Sopenharmony_ci};
77e1051a39Sopenharmony_ci
78e1051a39Sopenharmony_cistatic int conn_state(BIO *b, BIO_CONNECT *c)
79e1051a39Sopenharmony_ci{
80e1051a39Sopenharmony_ci    int ret = -1, i;
81e1051a39Sopenharmony_ci    BIO_info_cb *cb = NULL;
82e1051a39Sopenharmony_ci
83e1051a39Sopenharmony_ci    if (c->info_callback != NULL)
84e1051a39Sopenharmony_ci        cb = c->info_callback;
85e1051a39Sopenharmony_ci
86e1051a39Sopenharmony_ci    for (;;) {
87e1051a39Sopenharmony_ci        switch (c->state) {
88e1051a39Sopenharmony_ci        case BIO_CONN_S_BEFORE:
89e1051a39Sopenharmony_ci            if (c->param_hostname == NULL && c->param_service == NULL) {
90e1051a39Sopenharmony_ci                ERR_raise_data(ERR_LIB_BIO,
91e1051a39Sopenharmony_ci                               BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED,
92e1051a39Sopenharmony_ci                               "hostname=%s service=%s",
93e1051a39Sopenharmony_ci                               c->param_hostname, c->param_service);
94e1051a39Sopenharmony_ci                goto exit_loop;
95e1051a39Sopenharmony_ci            }
96e1051a39Sopenharmony_ci            c->state = BIO_CONN_S_GET_ADDR;
97e1051a39Sopenharmony_ci            break;
98e1051a39Sopenharmony_ci
99e1051a39Sopenharmony_ci        case BIO_CONN_S_GET_ADDR:
100e1051a39Sopenharmony_ci            {
101e1051a39Sopenharmony_ci                int family = AF_UNSPEC;
102e1051a39Sopenharmony_ci                switch (c->connect_family) {
103e1051a39Sopenharmony_ci                case BIO_FAMILY_IPV6:
104e1051a39Sopenharmony_ci                    if (1) { /* This is a trick we use to avoid bit rot.
105e1051a39Sopenharmony_ci                              * at least the "else" part will always be
106e1051a39Sopenharmony_ci                              * compiled.
107e1051a39Sopenharmony_ci                              */
108e1051a39Sopenharmony_ci#ifdef AF_INET6
109e1051a39Sopenharmony_ci                        family = AF_INET6;
110e1051a39Sopenharmony_ci                    } else {
111e1051a39Sopenharmony_ci#endif
112e1051a39Sopenharmony_ci                        ERR_raise(ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY);
113e1051a39Sopenharmony_ci                        goto exit_loop;
114e1051a39Sopenharmony_ci                    }
115e1051a39Sopenharmony_ci                    break;
116e1051a39Sopenharmony_ci                case BIO_FAMILY_IPV4:
117e1051a39Sopenharmony_ci                    family = AF_INET;
118e1051a39Sopenharmony_ci                    break;
119e1051a39Sopenharmony_ci                case BIO_FAMILY_IPANY:
120e1051a39Sopenharmony_ci                    family = AF_UNSPEC;
121e1051a39Sopenharmony_ci                    break;
122e1051a39Sopenharmony_ci                default:
123e1051a39Sopenharmony_ci                    ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY);
124e1051a39Sopenharmony_ci                    goto exit_loop;
125e1051a39Sopenharmony_ci                }
126e1051a39Sopenharmony_ci                if (BIO_lookup(c->param_hostname, c->param_service,
127e1051a39Sopenharmony_ci                               BIO_LOOKUP_CLIENT,
128e1051a39Sopenharmony_ci                               family, SOCK_STREAM, &c->addr_first) == 0)
129e1051a39Sopenharmony_ci                    goto exit_loop;
130e1051a39Sopenharmony_ci            }
131e1051a39Sopenharmony_ci            if (c->addr_first == NULL) {
132e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING);
133e1051a39Sopenharmony_ci                goto exit_loop;
134e1051a39Sopenharmony_ci            }
135e1051a39Sopenharmony_ci            c->addr_iter = c->addr_first;
136e1051a39Sopenharmony_ci            c->state = BIO_CONN_S_CREATE_SOCKET;
137e1051a39Sopenharmony_ci            break;
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_ci        case BIO_CONN_S_CREATE_SOCKET:
140e1051a39Sopenharmony_ci            ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
141e1051a39Sopenharmony_ci                             BIO_ADDRINFO_socktype(c->addr_iter),
142e1051a39Sopenharmony_ci                             BIO_ADDRINFO_protocol(c->addr_iter), 0);
143e1051a39Sopenharmony_ci            if (ret == (int)INVALID_SOCKET) {
144e1051a39Sopenharmony_ci                ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(),
145e1051a39Sopenharmony_ci                               "calling socket(%s, %s)",
146e1051a39Sopenharmony_ci                               c->param_hostname, c->param_service);
147e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET);
148e1051a39Sopenharmony_ci                goto exit_loop;
149e1051a39Sopenharmony_ci            }
150e1051a39Sopenharmony_ci            b->num = ret;
151e1051a39Sopenharmony_ci            c->state = BIO_CONN_S_CONNECT;
152e1051a39Sopenharmony_ci            break;
153e1051a39Sopenharmony_ci
154e1051a39Sopenharmony_ci        case BIO_CONN_S_CONNECT:
155e1051a39Sopenharmony_ci            BIO_clear_retry_flags(b);
156e1051a39Sopenharmony_ci            ERR_set_mark();
157e1051a39Sopenharmony_ci            ret = BIO_connect(b->num, BIO_ADDRINFO_address(c->addr_iter),
158e1051a39Sopenharmony_ci                              BIO_SOCK_KEEPALIVE | c->connect_mode);
159e1051a39Sopenharmony_ci            b->retry_reason = 0;
160e1051a39Sopenharmony_ci            if (ret == 0) {
161e1051a39Sopenharmony_ci                if (BIO_sock_should_retry(ret)) {
162e1051a39Sopenharmony_ci                    BIO_set_retry_special(b);
163e1051a39Sopenharmony_ci                    c->state = BIO_CONN_S_BLOCKED_CONNECT;
164e1051a39Sopenharmony_ci                    b->retry_reason = BIO_RR_CONNECT;
165e1051a39Sopenharmony_ci                    ERR_pop_to_mark();
166e1051a39Sopenharmony_ci                } else if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter))
167e1051a39Sopenharmony_ci                           != NULL) {
168e1051a39Sopenharmony_ci                    /*
169e1051a39Sopenharmony_ci                     * if there are more addresses to try, do that first
170e1051a39Sopenharmony_ci                     */
171e1051a39Sopenharmony_ci                    BIO_closesocket(b->num);
172e1051a39Sopenharmony_ci                    c->state = BIO_CONN_S_CREATE_SOCKET;
173e1051a39Sopenharmony_ci                    ERR_pop_to_mark();
174e1051a39Sopenharmony_ci                    break;
175e1051a39Sopenharmony_ci                } else {
176e1051a39Sopenharmony_ci                    ERR_clear_last_mark();
177e1051a39Sopenharmony_ci                    ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(),
178e1051a39Sopenharmony_ci                                   "calling connect(%s, %s)",
179e1051a39Sopenharmony_ci                                    c->param_hostname, c->param_service);
180e1051a39Sopenharmony_ci                    c->state = BIO_CONN_S_CONNECT_ERROR;
181e1051a39Sopenharmony_ci                    break;
182e1051a39Sopenharmony_ci                }
183e1051a39Sopenharmony_ci                goto exit_loop;
184e1051a39Sopenharmony_ci            } else {
185e1051a39Sopenharmony_ci                ERR_clear_last_mark();
186e1051a39Sopenharmony_ci                c->state = BIO_CONN_S_OK;
187e1051a39Sopenharmony_ci            }
188e1051a39Sopenharmony_ci            break;
189e1051a39Sopenharmony_ci
190e1051a39Sopenharmony_ci        case BIO_CONN_S_BLOCKED_CONNECT:
191e1051a39Sopenharmony_ci            /* wait for socket being writable, before querying BIO_sock_error */
192e1051a39Sopenharmony_ci            if (BIO_socket_wait(b->num, 0, time(NULL)) == 0)
193e1051a39Sopenharmony_ci                break;
194e1051a39Sopenharmony_ci            i = BIO_sock_error(b->num);
195e1051a39Sopenharmony_ci            if (i != 0) {
196e1051a39Sopenharmony_ci                BIO_clear_retry_flags(b);
197e1051a39Sopenharmony_ci                if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) != NULL) {
198e1051a39Sopenharmony_ci                    /*
199e1051a39Sopenharmony_ci                     * if there are more addresses to try, do that first
200e1051a39Sopenharmony_ci                     */
201e1051a39Sopenharmony_ci                    BIO_closesocket(b->num);
202e1051a39Sopenharmony_ci                    c->state = BIO_CONN_S_CREATE_SOCKET;
203e1051a39Sopenharmony_ci                    break;
204e1051a39Sopenharmony_ci                }
205e1051a39Sopenharmony_ci                ERR_raise_data(ERR_LIB_SYS, i,
206e1051a39Sopenharmony_ci                               "calling connect(%s, %s)",
207e1051a39Sopenharmony_ci                                c->param_hostname, c->param_service);
208e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_BIO, BIO_R_NBIO_CONNECT_ERROR);
209e1051a39Sopenharmony_ci                ret = 0;
210e1051a39Sopenharmony_ci                goto exit_loop;
211e1051a39Sopenharmony_ci            } else {
212e1051a39Sopenharmony_ci                c->state = BIO_CONN_S_OK;
213e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_KTLS
214e1051a39Sopenharmony_ci                /*
215e1051a39Sopenharmony_ci                 * The new socket is created successfully regardless of ktls_enable.
216e1051a39Sopenharmony_ci                 * ktls_enable doesn't change any functionality of the socket, except
217e1051a39Sopenharmony_ci                 * changing the setsockopt to enable the processing of ktls_start.
218e1051a39Sopenharmony_ci                 * Thus, it is not a problem to call it for non-TLS sockets.
219e1051a39Sopenharmony_ci                 */
220e1051a39Sopenharmony_ci                ktls_enable(b->num);
221e1051a39Sopenharmony_ci# endif
222e1051a39Sopenharmony_ci            }
223e1051a39Sopenharmony_ci            break;
224e1051a39Sopenharmony_ci
225e1051a39Sopenharmony_ci        case BIO_CONN_S_CONNECT_ERROR:
226e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_BIO, BIO_R_CONNECT_ERROR);
227e1051a39Sopenharmony_ci            ret = 0;
228e1051a39Sopenharmony_ci            goto exit_loop;
229e1051a39Sopenharmony_ci
230e1051a39Sopenharmony_ci        case BIO_CONN_S_OK:
231e1051a39Sopenharmony_ci            ret = 1;
232e1051a39Sopenharmony_ci            goto exit_loop;
233e1051a39Sopenharmony_ci        default:
234e1051a39Sopenharmony_ci            /* abort(); */
235e1051a39Sopenharmony_ci            goto exit_loop;
236e1051a39Sopenharmony_ci        }
237e1051a39Sopenharmony_ci
238e1051a39Sopenharmony_ci        if (cb != NULL) {
239e1051a39Sopenharmony_ci            if ((ret = cb((BIO *)b, c->state, ret)) == 0)
240e1051a39Sopenharmony_ci                goto end;
241e1051a39Sopenharmony_ci        }
242e1051a39Sopenharmony_ci    }
243e1051a39Sopenharmony_ci
244e1051a39Sopenharmony_ci    /* Loop does not exit */
245e1051a39Sopenharmony_ci exit_loop:
246e1051a39Sopenharmony_ci    if (cb != NULL)
247e1051a39Sopenharmony_ci        ret = cb((BIO *)b, c->state, ret);
248e1051a39Sopenharmony_ci end:
249e1051a39Sopenharmony_ci    return ret;
250e1051a39Sopenharmony_ci}
251e1051a39Sopenharmony_ci
252e1051a39Sopenharmony_ciBIO_CONNECT *BIO_CONNECT_new(void)
253e1051a39Sopenharmony_ci{
254e1051a39Sopenharmony_ci    BIO_CONNECT *ret;
255e1051a39Sopenharmony_ci
256e1051a39Sopenharmony_ci    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
257e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
258e1051a39Sopenharmony_ci        return NULL;
259e1051a39Sopenharmony_ci    }
260e1051a39Sopenharmony_ci    ret->state = BIO_CONN_S_BEFORE;
261e1051a39Sopenharmony_ci    ret->connect_family = BIO_FAMILY_IPANY;
262e1051a39Sopenharmony_ci    return ret;
263e1051a39Sopenharmony_ci}
264e1051a39Sopenharmony_ci
265e1051a39Sopenharmony_civoid BIO_CONNECT_free(BIO_CONNECT *a)
266e1051a39Sopenharmony_ci{
267e1051a39Sopenharmony_ci    if (a == NULL)
268e1051a39Sopenharmony_ci        return;
269e1051a39Sopenharmony_ci    OPENSSL_free(a->param_hostname);
270e1051a39Sopenharmony_ci    OPENSSL_free(a->param_service);
271e1051a39Sopenharmony_ci    BIO_ADDRINFO_free(a->addr_first);
272e1051a39Sopenharmony_ci    OPENSSL_free(a);
273e1051a39Sopenharmony_ci}
274e1051a39Sopenharmony_ci
275e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_s_connect(void)
276e1051a39Sopenharmony_ci{
277e1051a39Sopenharmony_ci    return &methods_connectp;
278e1051a39Sopenharmony_ci}
279e1051a39Sopenharmony_ci
280e1051a39Sopenharmony_cistatic int conn_new(BIO *bi)
281e1051a39Sopenharmony_ci{
282e1051a39Sopenharmony_ci    bi->init = 0;
283e1051a39Sopenharmony_ci    bi->num = (int)INVALID_SOCKET;
284e1051a39Sopenharmony_ci    bi->flags = 0;
285e1051a39Sopenharmony_ci    if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL)
286e1051a39Sopenharmony_ci        return 0;
287e1051a39Sopenharmony_ci    else
288e1051a39Sopenharmony_ci        return 1;
289e1051a39Sopenharmony_ci}
290e1051a39Sopenharmony_ci
291e1051a39Sopenharmony_cistatic void conn_close_socket(BIO *bio)
292e1051a39Sopenharmony_ci{
293e1051a39Sopenharmony_ci    BIO_CONNECT *c;
294e1051a39Sopenharmony_ci
295e1051a39Sopenharmony_ci    c = (BIO_CONNECT *)bio->ptr;
296e1051a39Sopenharmony_ci    if (bio->num != (int)INVALID_SOCKET) {
297e1051a39Sopenharmony_ci        /* Only do a shutdown if things were established */
298e1051a39Sopenharmony_ci        if (c->state == BIO_CONN_S_OK)
299e1051a39Sopenharmony_ci            shutdown(bio->num, 2);
300e1051a39Sopenharmony_ci        BIO_closesocket(bio->num);
301e1051a39Sopenharmony_ci        bio->num = (int)INVALID_SOCKET;
302e1051a39Sopenharmony_ci    }
303e1051a39Sopenharmony_ci}
304e1051a39Sopenharmony_ci
305e1051a39Sopenharmony_cistatic int conn_free(BIO *a)
306e1051a39Sopenharmony_ci{
307e1051a39Sopenharmony_ci    BIO_CONNECT *data;
308e1051a39Sopenharmony_ci
309e1051a39Sopenharmony_ci    if (a == NULL)
310e1051a39Sopenharmony_ci        return 0;
311e1051a39Sopenharmony_ci    data = (BIO_CONNECT *)a->ptr;
312e1051a39Sopenharmony_ci
313e1051a39Sopenharmony_ci    if (a->shutdown) {
314e1051a39Sopenharmony_ci        conn_close_socket(a);
315e1051a39Sopenharmony_ci        BIO_CONNECT_free(data);
316e1051a39Sopenharmony_ci        a->ptr = NULL;
317e1051a39Sopenharmony_ci        a->flags = 0;
318e1051a39Sopenharmony_ci        a->init = 0;
319e1051a39Sopenharmony_ci    }
320e1051a39Sopenharmony_ci    return 1;
321e1051a39Sopenharmony_ci}
322e1051a39Sopenharmony_ci
323e1051a39Sopenharmony_cistatic int conn_read(BIO *b, char *out, int outl)
324e1051a39Sopenharmony_ci{
325e1051a39Sopenharmony_ci    int ret = 0;
326e1051a39Sopenharmony_ci    BIO_CONNECT *data;
327e1051a39Sopenharmony_ci
328e1051a39Sopenharmony_ci    data = (BIO_CONNECT *)b->ptr;
329e1051a39Sopenharmony_ci    if (data->state != BIO_CONN_S_OK) {
330e1051a39Sopenharmony_ci        ret = conn_state(b, data);
331e1051a39Sopenharmony_ci        if (ret <= 0)
332e1051a39Sopenharmony_ci            return ret;
333e1051a39Sopenharmony_ci    }
334e1051a39Sopenharmony_ci
335e1051a39Sopenharmony_ci    if (out != NULL) {
336e1051a39Sopenharmony_ci        clear_socket_error();
337e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_KTLS
338e1051a39Sopenharmony_ci        if (BIO_get_ktls_recv(b))
339e1051a39Sopenharmony_ci            ret = ktls_read_record(b->num, out, outl);
340e1051a39Sopenharmony_ci        else
341e1051a39Sopenharmony_ci# endif
342e1051a39Sopenharmony_ci            ret = readsocket(b->num, out, outl);
343e1051a39Sopenharmony_ci        BIO_clear_retry_flags(b);
344e1051a39Sopenharmony_ci        if (ret <= 0) {
345e1051a39Sopenharmony_ci            if (BIO_sock_should_retry(ret))
346e1051a39Sopenharmony_ci                BIO_set_retry_read(b);
347e1051a39Sopenharmony_ci            else if (ret == 0)
348e1051a39Sopenharmony_ci                b->flags |= BIO_FLAGS_IN_EOF;
349e1051a39Sopenharmony_ci        }
350e1051a39Sopenharmony_ci    }
351e1051a39Sopenharmony_ci    return ret;
352e1051a39Sopenharmony_ci}
353e1051a39Sopenharmony_ci
354e1051a39Sopenharmony_cistatic int conn_write(BIO *b, const char *in, int inl)
355e1051a39Sopenharmony_ci{
356e1051a39Sopenharmony_ci    int ret;
357e1051a39Sopenharmony_ci    BIO_CONNECT *data;
358e1051a39Sopenharmony_ci
359e1051a39Sopenharmony_ci    data = (BIO_CONNECT *)b->ptr;
360e1051a39Sopenharmony_ci    if (data->state != BIO_CONN_S_OK) {
361e1051a39Sopenharmony_ci        ret = conn_state(b, data);
362e1051a39Sopenharmony_ci        if (ret <= 0)
363e1051a39Sopenharmony_ci            return ret;
364e1051a39Sopenharmony_ci    }
365e1051a39Sopenharmony_ci
366e1051a39Sopenharmony_ci    clear_socket_error();
367e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_KTLS
368e1051a39Sopenharmony_ci    if (BIO_should_ktls_ctrl_msg_flag(b)) {
369e1051a39Sopenharmony_ci        ret = ktls_send_ctrl_message(b->num, data->record_type, in, inl);
370e1051a39Sopenharmony_ci        if (ret >= 0) {
371e1051a39Sopenharmony_ci            ret = inl;
372e1051a39Sopenharmony_ci            BIO_clear_ktls_ctrl_msg_flag(b);
373e1051a39Sopenharmony_ci        }
374e1051a39Sopenharmony_ci    } else
375e1051a39Sopenharmony_ci# endif
376e1051a39Sopenharmony_ci        ret = writesocket(b->num, in, inl);
377e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
378e1051a39Sopenharmony_ci    if (ret <= 0) {
379e1051a39Sopenharmony_ci        if (BIO_sock_should_retry(ret))
380e1051a39Sopenharmony_ci            BIO_set_retry_write(b);
381e1051a39Sopenharmony_ci    }
382e1051a39Sopenharmony_ci    return ret;
383e1051a39Sopenharmony_ci}
384e1051a39Sopenharmony_ci
385e1051a39Sopenharmony_cistatic long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
386e1051a39Sopenharmony_ci{
387e1051a39Sopenharmony_ci    BIO *dbio;
388e1051a39Sopenharmony_ci    int *ip;
389e1051a39Sopenharmony_ci    const char **pptr = NULL;
390e1051a39Sopenharmony_ci    long ret = 1;
391e1051a39Sopenharmony_ci    BIO_CONNECT *data;
392e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_KTLS
393e1051a39Sopenharmony_ci    ktls_crypto_info_t *crypto_info;
394e1051a39Sopenharmony_ci# endif
395e1051a39Sopenharmony_ci
396e1051a39Sopenharmony_ci    data = (BIO_CONNECT *)b->ptr;
397e1051a39Sopenharmony_ci
398e1051a39Sopenharmony_ci    switch (cmd) {
399e1051a39Sopenharmony_ci    case BIO_CTRL_RESET:
400e1051a39Sopenharmony_ci        ret = 0;
401e1051a39Sopenharmony_ci        data->state = BIO_CONN_S_BEFORE;
402e1051a39Sopenharmony_ci        conn_close_socket(b);
403e1051a39Sopenharmony_ci        BIO_ADDRINFO_free(data->addr_first);
404e1051a39Sopenharmony_ci        data->addr_first = NULL;
405e1051a39Sopenharmony_ci        b->flags = 0;
406e1051a39Sopenharmony_ci        break;
407e1051a39Sopenharmony_ci    case BIO_C_DO_STATE_MACHINE:
408e1051a39Sopenharmony_ci        /* use this one to start the connection */
409e1051a39Sopenharmony_ci        if (data->state != BIO_CONN_S_OK)
410e1051a39Sopenharmony_ci            ret = (long)conn_state(b, data);
411e1051a39Sopenharmony_ci        else
412e1051a39Sopenharmony_ci            ret = 1;
413e1051a39Sopenharmony_ci        break;
414e1051a39Sopenharmony_ci    case BIO_C_GET_CONNECT:
415e1051a39Sopenharmony_ci        if (ptr != NULL) {
416e1051a39Sopenharmony_ci            pptr = (const char **)ptr;
417e1051a39Sopenharmony_ci            if (num == 0) {
418e1051a39Sopenharmony_ci                *pptr = data->param_hostname;
419e1051a39Sopenharmony_ci            } else if (num == 1) {
420e1051a39Sopenharmony_ci                *pptr = data->param_service;
421e1051a39Sopenharmony_ci            } else if (num == 2) {
422e1051a39Sopenharmony_ci                *pptr = (const char *)BIO_ADDRINFO_address(data->addr_iter);
423e1051a39Sopenharmony_ci            } else if (num == 3) {
424e1051a39Sopenharmony_ci                switch (BIO_ADDRINFO_family(data->addr_iter)) {
425e1051a39Sopenharmony_ci# ifdef AF_INET6
426e1051a39Sopenharmony_ci                case AF_INET6:
427e1051a39Sopenharmony_ci                    ret = BIO_FAMILY_IPV6;
428e1051a39Sopenharmony_ci                    break;
429e1051a39Sopenharmony_ci# endif
430e1051a39Sopenharmony_ci                case AF_INET:
431e1051a39Sopenharmony_ci                    ret = BIO_FAMILY_IPV4;
432e1051a39Sopenharmony_ci                    break;
433e1051a39Sopenharmony_ci                case 0:
434e1051a39Sopenharmony_ci                    ret = data->connect_family;
435e1051a39Sopenharmony_ci                    break;
436e1051a39Sopenharmony_ci                default:
437e1051a39Sopenharmony_ci                    ret = -1;
438e1051a39Sopenharmony_ci                    break;
439e1051a39Sopenharmony_ci                }
440e1051a39Sopenharmony_ci            } else {
441e1051a39Sopenharmony_ci                ret = 0;
442e1051a39Sopenharmony_ci            }
443e1051a39Sopenharmony_ci        } else {
444e1051a39Sopenharmony_ci            ret = 0;
445e1051a39Sopenharmony_ci        }
446e1051a39Sopenharmony_ci        break;
447e1051a39Sopenharmony_ci    case BIO_C_SET_CONNECT:
448e1051a39Sopenharmony_ci        if (ptr != NULL) {
449e1051a39Sopenharmony_ci            b->init = 1;
450e1051a39Sopenharmony_ci            if (num == 0) { /* BIO_set_conn_hostname */
451e1051a39Sopenharmony_ci                char *hold_service = data->param_service;
452e1051a39Sopenharmony_ci                /* We affect the hostname regardless.  However, the input
453e1051a39Sopenharmony_ci                 * string might contain a host:service spec, so we must
454e1051a39Sopenharmony_ci                 * parse it, which might or might not affect the service
455e1051a39Sopenharmony_ci                 */
456e1051a39Sopenharmony_ci
457e1051a39Sopenharmony_ci                OPENSSL_free(data->param_hostname);
458e1051a39Sopenharmony_ci                data->param_hostname = NULL;
459e1051a39Sopenharmony_ci                ret = BIO_parse_hostserv(ptr,
460e1051a39Sopenharmony_ci                                         &data->param_hostname,
461e1051a39Sopenharmony_ci                                         &data->param_service,
462e1051a39Sopenharmony_ci                                         BIO_PARSE_PRIO_HOST);
463e1051a39Sopenharmony_ci                if (hold_service != data->param_service)
464e1051a39Sopenharmony_ci                    OPENSSL_free(hold_service);
465e1051a39Sopenharmony_ci            } else if (num == 1) { /* BIO_set_conn_port */
466e1051a39Sopenharmony_ci                OPENSSL_free(data->param_service);
467e1051a39Sopenharmony_ci                if ((data->param_service = OPENSSL_strdup(ptr)) == NULL)
468e1051a39Sopenharmony_ci                    ret = 0;
469e1051a39Sopenharmony_ci            } else if (num == 2) { /* BIO_set_conn_address */
470e1051a39Sopenharmony_ci                const BIO_ADDR *addr = (const BIO_ADDR *)ptr;
471e1051a39Sopenharmony_ci                char *host = BIO_ADDR_hostname_string(addr, 1);
472e1051a39Sopenharmony_ci                char *service = BIO_ADDR_service_string(addr, 1);
473e1051a39Sopenharmony_ci
474e1051a39Sopenharmony_ci                ret = host != NULL && service != NULL;
475e1051a39Sopenharmony_ci                if (ret) {
476e1051a39Sopenharmony_ci                    OPENSSL_free(data->param_hostname);
477e1051a39Sopenharmony_ci                    data->param_hostname = host;
478e1051a39Sopenharmony_ci                    OPENSSL_free(data->param_service);
479e1051a39Sopenharmony_ci                    data->param_service = service;
480e1051a39Sopenharmony_ci                    BIO_ADDRINFO_free(data->addr_first);
481e1051a39Sopenharmony_ci                    data->addr_first = NULL;
482e1051a39Sopenharmony_ci                    data->addr_iter = NULL;
483e1051a39Sopenharmony_ci                } else {
484e1051a39Sopenharmony_ci                    OPENSSL_free(host);
485e1051a39Sopenharmony_ci                    OPENSSL_free(service);
486e1051a39Sopenharmony_ci                }
487e1051a39Sopenharmony_ci            } else if (num == 3) { /* BIO_set_conn_ip_family */
488e1051a39Sopenharmony_ci                data->connect_family = *(int *)ptr;
489e1051a39Sopenharmony_ci            } else {
490e1051a39Sopenharmony_ci                ret = 0;
491e1051a39Sopenharmony_ci            }
492e1051a39Sopenharmony_ci        }
493e1051a39Sopenharmony_ci        break;
494e1051a39Sopenharmony_ci    case BIO_C_SET_NBIO:
495e1051a39Sopenharmony_ci        if (num != 0)
496e1051a39Sopenharmony_ci            data->connect_mode |= BIO_SOCK_NONBLOCK;
497e1051a39Sopenharmony_ci        else
498e1051a39Sopenharmony_ci            data->connect_mode &= ~BIO_SOCK_NONBLOCK;
499e1051a39Sopenharmony_ci        break;
500e1051a39Sopenharmony_ci    case BIO_C_SET_CONNECT_MODE:
501e1051a39Sopenharmony_ci        data->connect_mode = (int)num;
502e1051a39Sopenharmony_ci        break;
503e1051a39Sopenharmony_ci    case BIO_C_GET_FD:
504e1051a39Sopenharmony_ci        if (b->init) {
505e1051a39Sopenharmony_ci            ip = (int *)ptr;
506e1051a39Sopenharmony_ci            if (ip != NULL)
507e1051a39Sopenharmony_ci                *ip = b->num;
508e1051a39Sopenharmony_ci            ret = b->num;
509e1051a39Sopenharmony_ci        } else
510e1051a39Sopenharmony_ci            ret = -1;
511e1051a39Sopenharmony_ci        break;
512e1051a39Sopenharmony_ci    case BIO_CTRL_GET_CLOSE:
513e1051a39Sopenharmony_ci        ret = b->shutdown;
514e1051a39Sopenharmony_ci        break;
515e1051a39Sopenharmony_ci    case BIO_CTRL_SET_CLOSE:
516e1051a39Sopenharmony_ci        b->shutdown = (int)num;
517e1051a39Sopenharmony_ci        break;
518e1051a39Sopenharmony_ci    case BIO_CTRL_PENDING:
519e1051a39Sopenharmony_ci    case BIO_CTRL_WPENDING:
520e1051a39Sopenharmony_ci        ret = 0;
521e1051a39Sopenharmony_ci        break;
522e1051a39Sopenharmony_ci    case BIO_CTRL_FLUSH:
523e1051a39Sopenharmony_ci        break;
524e1051a39Sopenharmony_ci    case BIO_CTRL_DUP:
525e1051a39Sopenharmony_ci        {
526e1051a39Sopenharmony_ci            dbio = (BIO *)ptr;
527e1051a39Sopenharmony_ci            if (data->param_hostname)
528e1051a39Sopenharmony_ci                BIO_set_conn_hostname(dbio, data->param_hostname);
529e1051a39Sopenharmony_ci            if (data->param_service)
530e1051a39Sopenharmony_ci                BIO_set_conn_port(dbio, data->param_service);
531e1051a39Sopenharmony_ci            BIO_set_conn_ip_family(dbio, data->connect_family);
532e1051a39Sopenharmony_ci            BIO_set_conn_mode(dbio, data->connect_mode);
533e1051a39Sopenharmony_ci            /*
534e1051a39Sopenharmony_ci             * FIXME: the cast of the function seems unlikely to be a good
535e1051a39Sopenharmony_ci             * idea
536e1051a39Sopenharmony_ci             */
537e1051a39Sopenharmony_ci            (void)BIO_set_info_callback(dbio, data->info_callback);
538e1051a39Sopenharmony_ci        }
539e1051a39Sopenharmony_ci        break;
540e1051a39Sopenharmony_ci    case BIO_CTRL_SET_CALLBACK:
541e1051a39Sopenharmony_ci        ret = 0; /* use callback ctrl */
542e1051a39Sopenharmony_ci        break;
543e1051a39Sopenharmony_ci    case BIO_CTRL_GET_CALLBACK:
544e1051a39Sopenharmony_ci        {
545e1051a39Sopenharmony_ci            BIO_info_cb **fptr;
546e1051a39Sopenharmony_ci
547e1051a39Sopenharmony_ci            fptr = (BIO_info_cb **)ptr;
548e1051a39Sopenharmony_ci            *fptr = data->info_callback;
549e1051a39Sopenharmony_ci        }
550e1051a39Sopenharmony_ci        break;
551e1051a39Sopenharmony_ci    case BIO_CTRL_EOF:
552e1051a39Sopenharmony_ci        ret = (b->flags & BIO_FLAGS_IN_EOF) != 0;
553e1051a39Sopenharmony_ci        break;
554e1051a39Sopenharmony_ci# ifndef OPENSSL_NO_KTLS
555e1051a39Sopenharmony_ci    case BIO_CTRL_SET_KTLS:
556e1051a39Sopenharmony_ci        crypto_info = (ktls_crypto_info_t *)ptr;
557e1051a39Sopenharmony_ci        ret = ktls_start(b->num, crypto_info, num);
558e1051a39Sopenharmony_ci        if (ret)
559e1051a39Sopenharmony_ci            BIO_set_ktls_flag(b, num);
560e1051a39Sopenharmony_ci        break;
561e1051a39Sopenharmony_ci    case BIO_CTRL_GET_KTLS_SEND:
562e1051a39Sopenharmony_ci        return BIO_should_ktls_flag(b, 1) != 0;
563e1051a39Sopenharmony_ci    case BIO_CTRL_GET_KTLS_RECV:
564e1051a39Sopenharmony_ci        return BIO_should_ktls_flag(b, 0) != 0;
565e1051a39Sopenharmony_ci    case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG:
566e1051a39Sopenharmony_ci        BIO_set_ktls_ctrl_msg_flag(b);
567e1051a39Sopenharmony_ci        data->record_type = num;
568e1051a39Sopenharmony_ci        ret = 0;
569e1051a39Sopenharmony_ci        break;
570e1051a39Sopenharmony_ci    case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
571e1051a39Sopenharmony_ci        BIO_clear_ktls_ctrl_msg_flag(b);
572e1051a39Sopenharmony_ci        ret = 0;
573e1051a39Sopenharmony_ci        break;
574e1051a39Sopenharmony_ci# endif
575e1051a39Sopenharmony_ci    default:
576e1051a39Sopenharmony_ci        ret = 0;
577e1051a39Sopenharmony_ci        break;
578e1051a39Sopenharmony_ci    }
579e1051a39Sopenharmony_ci    return ret;
580e1051a39Sopenharmony_ci}
581e1051a39Sopenharmony_ci
582e1051a39Sopenharmony_cistatic long conn_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
583e1051a39Sopenharmony_ci{
584e1051a39Sopenharmony_ci    long ret = 1;
585e1051a39Sopenharmony_ci    BIO_CONNECT *data;
586e1051a39Sopenharmony_ci
587e1051a39Sopenharmony_ci    data = (BIO_CONNECT *)b->ptr;
588e1051a39Sopenharmony_ci
589e1051a39Sopenharmony_ci    switch (cmd) {
590e1051a39Sopenharmony_ci    case BIO_CTRL_SET_CALLBACK:
591e1051a39Sopenharmony_ci        {
592e1051a39Sopenharmony_ci            data->info_callback = fp;
593e1051a39Sopenharmony_ci        }
594e1051a39Sopenharmony_ci        break;
595e1051a39Sopenharmony_ci    default:
596e1051a39Sopenharmony_ci        ret = 0;
597e1051a39Sopenharmony_ci        break;
598e1051a39Sopenharmony_ci    }
599e1051a39Sopenharmony_ci    return ret;
600e1051a39Sopenharmony_ci}
601e1051a39Sopenharmony_ci
602e1051a39Sopenharmony_cistatic int conn_puts(BIO *bp, const char *str)
603e1051a39Sopenharmony_ci{
604e1051a39Sopenharmony_ci    int n, ret;
605e1051a39Sopenharmony_ci
606e1051a39Sopenharmony_ci    n = strlen(str);
607e1051a39Sopenharmony_ci    ret = conn_write(bp, str, n);
608e1051a39Sopenharmony_ci    return ret;
609e1051a39Sopenharmony_ci}
610e1051a39Sopenharmony_ci
611e1051a39Sopenharmony_ciBIO *BIO_new_connect(const char *str)
612e1051a39Sopenharmony_ci{
613e1051a39Sopenharmony_ci    BIO *ret;
614e1051a39Sopenharmony_ci
615e1051a39Sopenharmony_ci    ret = BIO_new(BIO_s_connect());
616e1051a39Sopenharmony_ci    if (ret == NULL)
617e1051a39Sopenharmony_ci        return NULL;
618e1051a39Sopenharmony_ci    if (BIO_set_conn_hostname(ret, str))
619e1051a39Sopenharmony_ci        return ret;
620e1051a39Sopenharmony_ci    BIO_free(ret);
621e1051a39Sopenharmony_ci    return NULL;
622e1051a39Sopenharmony_ci}
623e1051a39Sopenharmony_ci
624e1051a39Sopenharmony_ci#endif
625