xref: /third_party/openssl/crypto/bio/bss_acpt.c (revision e1051a39)
1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2023 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#define OPENSSL_SUPPRESS_DEPRECATED
11e1051a39Sopenharmony_ci
12e1051a39Sopenharmony_ci#include <stdio.h>
13e1051a39Sopenharmony_ci#include <errno.h>
14e1051a39Sopenharmony_ci#include "bio_local.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SOCK
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_citypedef struct bio_accept_st {
19e1051a39Sopenharmony_ci    int state;
20e1051a39Sopenharmony_ci    int accept_family;
21e1051a39Sopenharmony_ci    int bind_mode;     /* Socket mode for BIO_listen */
22e1051a39Sopenharmony_ci    int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
23e1051a39Sopenharmony_ci    char *param_addr;
24e1051a39Sopenharmony_ci    char *param_serv;
25e1051a39Sopenharmony_ci
26e1051a39Sopenharmony_ci    int accept_sock;
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_ci    BIO_ADDRINFO *addr_first;
29e1051a39Sopenharmony_ci    const BIO_ADDRINFO *addr_iter;
30e1051a39Sopenharmony_ci    BIO_ADDR cache_accepting_addr;   /* Useful if we asked for port 0 */
31e1051a39Sopenharmony_ci    char *cache_accepting_name, *cache_accepting_serv;
32e1051a39Sopenharmony_ci    BIO_ADDR cache_peer_addr;
33e1051a39Sopenharmony_ci    char *cache_peer_name, *cache_peer_serv;
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_ci    BIO *bio_chain;
36e1051a39Sopenharmony_ci} BIO_ACCEPT;
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_cistatic int acpt_write(BIO *h, const char *buf, int num);
39e1051a39Sopenharmony_cistatic int acpt_read(BIO *h, char *buf, int size);
40e1051a39Sopenharmony_cistatic int acpt_puts(BIO *h, const char *str);
41e1051a39Sopenharmony_cistatic long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
42e1051a39Sopenharmony_cistatic int acpt_new(BIO *h);
43e1051a39Sopenharmony_cistatic int acpt_free(BIO *data);
44e1051a39Sopenharmony_cistatic int acpt_state(BIO *b, BIO_ACCEPT *c);
45e1051a39Sopenharmony_cistatic void acpt_close_socket(BIO *data);
46e1051a39Sopenharmony_cistatic BIO_ACCEPT *BIO_ACCEPT_new(void);
47e1051a39Sopenharmony_cistatic void BIO_ACCEPT_free(BIO_ACCEPT *a);
48e1051a39Sopenharmony_ci
49e1051a39Sopenharmony_ci# define ACPT_S_BEFORE                   1
50e1051a39Sopenharmony_ci# define ACPT_S_GET_ADDR                 2
51e1051a39Sopenharmony_ci# define ACPT_S_CREATE_SOCKET            3
52e1051a39Sopenharmony_ci# define ACPT_S_LISTEN                   4
53e1051a39Sopenharmony_ci# define ACPT_S_ACCEPT                   5
54e1051a39Sopenharmony_ci# define ACPT_S_OK                       6
55e1051a39Sopenharmony_ci
56e1051a39Sopenharmony_cistatic const BIO_METHOD methods_acceptp = {
57e1051a39Sopenharmony_ci    BIO_TYPE_ACCEPT,
58e1051a39Sopenharmony_ci    "socket accept",
59e1051a39Sopenharmony_ci    bwrite_conv,
60e1051a39Sopenharmony_ci    acpt_write,
61e1051a39Sopenharmony_ci    bread_conv,
62e1051a39Sopenharmony_ci    acpt_read,
63e1051a39Sopenharmony_ci    acpt_puts,
64e1051a39Sopenharmony_ci    NULL,                       /* connect_gets,         */
65e1051a39Sopenharmony_ci    acpt_ctrl,
66e1051a39Sopenharmony_ci    acpt_new,
67e1051a39Sopenharmony_ci    acpt_free,
68e1051a39Sopenharmony_ci    NULL,                       /* connect_callback_ctrl */
69e1051a39Sopenharmony_ci};
70e1051a39Sopenharmony_ci
71e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_s_accept(void)
72e1051a39Sopenharmony_ci{
73e1051a39Sopenharmony_ci    return &methods_acceptp;
74e1051a39Sopenharmony_ci}
75e1051a39Sopenharmony_ci
76e1051a39Sopenharmony_cistatic int acpt_new(BIO *bi)
77e1051a39Sopenharmony_ci{
78e1051a39Sopenharmony_ci    BIO_ACCEPT *ba;
79e1051a39Sopenharmony_ci
80e1051a39Sopenharmony_ci    bi->init = 0;
81e1051a39Sopenharmony_ci    bi->num = (int)INVALID_SOCKET;
82e1051a39Sopenharmony_ci    bi->flags = 0;
83e1051a39Sopenharmony_ci    if ((ba = BIO_ACCEPT_new()) == NULL)
84e1051a39Sopenharmony_ci        return 0;
85e1051a39Sopenharmony_ci    bi->ptr = (char *)ba;
86e1051a39Sopenharmony_ci    ba->state = ACPT_S_BEFORE;
87e1051a39Sopenharmony_ci    bi->shutdown = 1;
88e1051a39Sopenharmony_ci    return 1;
89e1051a39Sopenharmony_ci}
90e1051a39Sopenharmony_ci
91e1051a39Sopenharmony_cistatic BIO_ACCEPT *BIO_ACCEPT_new(void)
92e1051a39Sopenharmony_ci{
93e1051a39Sopenharmony_ci    BIO_ACCEPT *ret;
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ci    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
96e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
97e1051a39Sopenharmony_ci        return NULL;
98e1051a39Sopenharmony_ci    }
99e1051a39Sopenharmony_ci    ret->accept_family = BIO_FAMILY_IPANY;
100e1051a39Sopenharmony_ci    ret->accept_sock = (int)INVALID_SOCKET;
101e1051a39Sopenharmony_ci    return ret;
102e1051a39Sopenharmony_ci}
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_cistatic void BIO_ACCEPT_free(BIO_ACCEPT *a)
105e1051a39Sopenharmony_ci{
106e1051a39Sopenharmony_ci    if (a == NULL)
107e1051a39Sopenharmony_ci        return;
108e1051a39Sopenharmony_ci    OPENSSL_free(a->param_addr);
109e1051a39Sopenharmony_ci    OPENSSL_free(a->param_serv);
110e1051a39Sopenharmony_ci    BIO_ADDRINFO_free(a->addr_first);
111e1051a39Sopenharmony_ci    OPENSSL_free(a->cache_accepting_name);
112e1051a39Sopenharmony_ci    OPENSSL_free(a->cache_accepting_serv);
113e1051a39Sopenharmony_ci    OPENSSL_free(a->cache_peer_name);
114e1051a39Sopenharmony_ci    OPENSSL_free(a->cache_peer_serv);
115e1051a39Sopenharmony_ci    BIO_free(a->bio_chain);
116e1051a39Sopenharmony_ci    OPENSSL_free(a);
117e1051a39Sopenharmony_ci}
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_cistatic void acpt_close_socket(BIO *bio)
120e1051a39Sopenharmony_ci{
121e1051a39Sopenharmony_ci    BIO_ACCEPT *c;
122e1051a39Sopenharmony_ci
123e1051a39Sopenharmony_ci    c = (BIO_ACCEPT *)bio->ptr;
124e1051a39Sopenharmony_ci    if (c->accept_sock != (int)INVALID_SOCKET) {
125e1051a39Sopenharmony_ci        shutdown(c->accept_sock, 2);
126e1051a39Sopenharmony_ci        closesocket(c->accept_sock);
127e1051a39Sopenharmony_ci        c->accept_sock = (int)INVALID_SOCKET;
128e1051a39Sopenharmony_ci        bio->num = (int)INVALID_SOCKET;
129e1051a39Sopenharmony_ci    }
130e1051a39Sopenharmony_ci}
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_cistatic int acpt_free(BIO *a)
133e1051a39Sopenharmony_ci{
134e1051a39Sopenharmony_ci    BIO_ACCEPT *data;
135e1051a39Sopenharmony_ci
136e1051a39Sopenharmony_ci    if (a == NULL)
137e1051a39Sopenharmony_ci        return 0;
138e1051a39Sopenharmony_ci    data = (BIO_ACCEPT *)a->ptr;
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    if (a->shutdown) {
141e1051a39Sopenharmony_ci        acpt_close_socket(a);
142e1051a39Sopenharmony_ci        BIO_ACCEPT_free(data);
143e1051a39Sopenharmony_ci        a->ptr = NULL;
144e1051a39Sopenharmony_ci        a->flags = 0;
145e1051a39Sopenharmony_ci        a->init = 0;
146e1051a39Sopenharmony_ci    }
147e1051a39Sopenharmony_ci    return 1;
148e1051a39Sopenharmony_ci}
149e1051a39Sopenharmony_ci
150e1051a39Sopenharmony_cistatic int acpt_state(BIO *b, BIO_ACCEPT *c)
151e1051a39Sopenharmony_ci{
152e1051a39Sopenharmony_ci    BIO *bio = NULL, *dbio;
153e1051a39Sopenharmony_ci    int s = -1, ret = -1;
154e1051a39Sopenharmony_ci
155e1051a39Sopenharmony_ci    for (;;) {
156e1051a39Sopenharmony_ci        switch (c->state) {
157e1051a39Sopenharmony_ci        case ACPT_S_BEFORE:
158e1051a39Sopenharmony_ci            if (c->param_addr == NULL && c->param_serv == NULL) {
159e1051a39Sopenharmony_ci                ERR_raise_data(ERR_LIB_BIO,
160e1051a39Sopenharmony_ci                               BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED,
161e1051a39Sopenharmony_ci                               "hostname=%s, service=%s",
162e1051a39Sopenharmony_ci                               c->param_addr, c->param_serv);
163e1051a39Sopenharmony_ci                goto exit_loop;
164e1051a39Sopenharmony_ci            }
165e1051a39Sopenharmony_ci
166e1051a39Sopenharmony_ci            /* Because we're starting a new bind, any cached name and serv
167e1051a39Sopenharmony_ci             * are now obsolete and need to be cleaned out.
168e1051a39Sopenharmony_ci             * QUESTION: should this be done in acpt_close_socket() instead?
169e1051a39Sopenharmony_ci             */
170e1051a39Sopenharmony_ci            OPENSSL_free(c->cache_accepting_name);
171e1051a39Sopenharmony_ci            c->cache_accepting_name = NULL;
172e1051a39Sopenharmony_ci            OPENSSL_free(c->cache_accepting_serv);
173e1051a39Sopenharmony_ci            c->cache_accepting_serv = NULL;
174e1051a39Sopenharmony_ci            OPENSSL_free(c->cache_peer_name);
175e1051a39Sopenharmony_ci            c->cache_peer_name = NULL;
176e1051a39Sopenharmony_ci            OPENSSL_free(c->cache_peer_serv);
177e1051a39Sopenharmony_ci            c->cache_peer_serv = NULL;
178e1051a39Sopenharmony_ci
179e1051a39Sopenharmony_ci            c->state = ACPT_S_GET_ADDR;
180e1051a39Sopenharmony_ci            break;
181e1051a39Sopenharmony_ci
182e1051a39Sopenharmony_ci        case ACPT_S_GET_ADDR:
183e1051a39Sopenharmony_ci            {
184e1051a39Sopenharmony_ci                int family = AF_UNSPEC;
185e1051a39Sopenharmony_ci                switch (c->accept_family) {
186e1051a39Sopenharmony_ci                case BIO_FAMILY_IPV6:
187e1051a39Sopenharmony_ci                    if (1) { /* This is a trick we use to avoid bit rot.
188e1051a39Sopenharmony_ci                              * at least the "else" part will always be
189e1051a39Sopenharmony_ci                              * compiled.
190e1051a39Sopenharmony_ci                              */
191e1051a39Sopenharmony_ci#ifdef AF_INET6
192e1051a39Sopenharmony_ci                        family = AF_INET6;
193e1051a39Sopenharmony_ci                    } else {
194e1051a39Sopenharmony_ci#endif
195e1051a39Sopenharmony_ci                        ERR_raise(ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY);
196e1051a39Sopenharmony_ci                        goto exit_loop;
197e1051a39Sopenharmony_ci                    }
198e1051a39Sopenharmony_ci                    break;
199e1051a39Sopenharmony_ci                case BIO_FAMILY_IPV4:
200e1051a39Sopenharmony_ci                    family = AF_INET;
201e1051a39Sopenharmony_ci                    break;
202e1051a39Sopenharmony_ci                case BIO_FAMILY_IPANY:
203e1051a39Sopenharmony_ci                    family = AF_UNSPEC;
204e1051a39Sopenharmony_ci                    break;
205e1051a39Sopenharmony_ci                default:
206e1051a39Sopenharmony_ci                    ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY);
207e1051a39Sopenharmony_ci                    goto exit_loop;
208e1051a39Sopenharmony_ci                }
209e1051a39Sopenharmony_ci                if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER,
210e1051a39Sopenharmony_ci                               family, SOCK_STREAM, &c->addr_first) == 0)
211e1051a39Sopenharmony_ci                    goto exit_loop;
212e1051a39Sopenharmony_ci            }
213e1051a39Sopenharmony_ci            if (c->addr_first == NULL) {
214e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING);
215e1051a39Sopenharmony_ci                goto exit_loop;
216e1051a39Sopenharmony_ci            }
217e1051a39Sopenharmony_ci            c->addr_iter = c->addr_first;
218e1051a39Sopenharmony_ci            c->state = ACPT_S_CREATE_SOCKET;
219e1051a39Sopenharmony_ci            break;
220e1051a39Sopenharmony_ci
221e1051a39Sopenharmony_ci        case ACPT_S_CREATE_SOCKET:
222e1051a39Sopenharmony_ci            ERR_set_mark();
223e1051a39Sopenharmony_ci            s = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
224e1051a39Sopenharmony_ci                           BIO_ADDRINFO_socktype(c->addr_iter),
225e1051a39Sopenharmony_ci                           BIO_ADDRINFO_protocol(c->addr_iter), 0);
226e1051a39Sopenharmony_ci            if (s == (int)INVALID_SOCKET) {
227e1051a39Sopenharmony_ci                if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) != NULL) {
228e1051a39Sopenharmony_ci                    /*
229e1051a39Sopenharmony_ci                     * if there are more addresses to try, do that first
230e1051a39Sopenharmony_ci                     */
231e1051a39Sopenharmony_ci                    ERR_pop_to_mark();
232e1051a39Sopenharmony_ci                    break;
233e1051a39Sopenharmony_ci                }
234e1051a39Sopenharmony_ci                ERR_clear_last_mark();
235e1051a39Sopenharmony_ci                ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(),
236e1051a39Sopenharmony_ci                               "calling socket(%s, %s)",
237e1051a39Sopenharmony_ci                                c->param_addr, c->param_serv);
238e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET);
239e1051a39Sopenharmony_ci                goto exit_loop;
240e1051a39Sopenharmony_ci            }
241e1051a39Sopenharmony_ci            c->accept_sock = s;
242e1051a39Sopenharmony_ci            b->num = s;
243e1051a39Sopenharmony_ci            c->state = ACPT_S_LISTEN;
244e1051a39Sopenharmony_ci            s = -1;
245e1051a39Sopenharmony_ci            break;
246e1051a39Sopenharmony_ci
247e1051a39Sopenharmony_ci        case ACPT_S_LISTEN:
248e1051a39Sopenharmony_ci            {
249e1051a39Sopenharmony_ci                if (!BIO_listen(c->accept_sock,
250e1051a39Sopenharmony_ci                                BIO_ADDRINFO_address(c->addr_iter),
251e1051a39Sopenharmony_ci                                c->bind_mode)) {
252e1051a39Sopenharmony_ci                    BIO_closesocket(c->accept_sock);
253e1051a39Sopenharmony_ci                    goto exit_loop;
254e1051a39Sopenharmony_ci                }
255e1051a39Sopenharmony_ci            }
256e1051a39Sopenharmony_ci
257e1051a39Sopenharmony_ci            {
258e1051a39Sopenharmony_ci                union BIO_sock_info_u info;
259e1051a39Sopenharmony_ci
260e1051a39Sopenharmony_ci                info.addr = &c->cache_accepting_addr;
261e1051a39Sopenharmony_ci                if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS,
262e1051a39Sopenharmony_ci                                   &info)) {
263e1051a39Sopenharmony_ci                    BIO_closesocket(c->accept_sock);
264e1051a39Sopenharmony_ci                    goto exit_loop;
265e1051a39Sopenharmony_ci                }
266e1051a39Sopenharmony_ci            }
267e1051a39Sopenharmony_ci
268e1051a39Sopenharmony_ci            c->cache_accepting_name =
269e1051a39Sopenharmony_ci                BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1);
270e1051a39Sopenharmony_ci            c->cache_accepting_serv =
271e1051a39Sopenharmony_ci                BIO_ADDR_service_string(&c->cache_accepting_addr, 1);
272e1051a39Sopenharmony_ci            c->state = ACPT_S_ACCEPT;
273e1051a39Sopenharmony_ci            s = -1;
274e1051a39Sopenharmony_ci            ret = 1;
275e1051a39Sopenharmony_ci            goto end;
276e1051a39Sopenharmony_ci
277e1051a39Sopenharmony_ci        case ACPT_S_ACCEPT:
278e1051a39Sopenharmony_ci            if (b->next_bio != NULL) {
279e1051a39Sopenharmony_ci                c->state = ACPT_S_OK;
280e1051a39Sopenharmony_ci                break;
281e1051a39Sopenharmony_ci            }
282e1051a39Sopenharmony_ci            BIO_clear_retry_flags(b);
283e1051a39Sopenharmony_ci            b->retry_reason = 0;
284e1051a39Sopenharmony_ci
285e1051a39Sopenharmony_ci            OPENSSL_free(c->cache_peer_name);
286e1051a39Sopenharmony_ci            c->cache_peer_name = NULL;
287e1051a39Sopenharmony_ci            OPENSSL_free(c->cache_peer_serv);
288e1051a39Sopenharmony_ci            c->cache_peer_serv = NULL;
289e1051a39Sopenharmony_ci
290e1051a39Sopenharmony_ci            s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr,
291e1051a39Sopenharmony_ci                              c->accepted_mode);
292e1051a39Sopenharmony_ci
293e1051a39Sopenharmony_ci            /* If the returned socket is invalid, this might still be
294e1051a39Sopenharmony_ci             * retryable
295e1051a39Sopenharmony_ci             */
296e1051a39Sopenharmony_ci            if (s < 0) {
297e1051a39Sopenharmony_ci                if (BIO_sock_should_retry(s)) {
298e1051a39Sopenharmony_ci                    BIO_set_retry_special(b);
299e1051a39Sopenharmony_ci                    b->retry_reason = BIO_RR_ACCEPT;
300e1051a39Sopenharmony_ci                    goto end;
301e1051a39Sopenharmony_ci                }
302e1051a39Sopenharmony_ci            }
303e1051a39Sopenharmony_ci
304e1051a39Sopenharmony_ci            /* If it wasn't retryable, we fail */
305e1051a39Sopenharmony_ci            if (s < 0) {
306e1051a39Sopenharmony_ci                ret = s;
307e1051a39Sopenharmony_ci                goto exit_loop;
308e1051a39Sopenharmony_ci            }
309e1051a39Sopenharmony_ci
310e1051a39Sopenharmony_ci            bio = BIO_new_socket(s, BIO_CLOSE);
311e1051a39Sopenharmony_ci            if (bio == NULL)
312e1051a39Sopenharmony_ci                goto exit_loop;
313e1051a39Sopenharmony_ci
314e1051a39Sopenharmony_ci            BIO_set_callback_ex(bio, BIO_get_callback_ex(b));
315e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DEPRECATED_3_0
316e1051a39Sopenharmony_ci            BIO_set_callback(bio, BIO_get_callback(b));
317e1051a39Sopenharmony_ci#endif
318e1051a39Sopenharmony_ci            BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
319e1051a39Sopenharmony_ci            /*
320e1051a39Sopenharmony_ci             * If the accept BIO has an bio_chain, we dup it and put the new
321e1051a39Sopenharmony_ci             * socket at the end.
322e1051a39Sopenharmony_ci             */
323e1051a39Sopenharmony_ci            if (c->bio_chain != NULL) {
324e1051a39Sopenharmony_ci                if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
325e1051a39Sopenharmony_ci                    goto exit_loop;
326e1051a39Sopenharmony_ci                if (!BIO_push(dbio, bio))
327e1051a39Sopenharmony_ci                    goto exit_loop;
328e1051a39Sopenharmony_ci                bio = dbio;
329e1051a39Sopenharmony_ci            }
330e1051a39Sopenharmony_ci            if (BIO_push(b, bio) == NULL)
331e1051a39Sopenharmony_ci                goto exit_loop;
332e1051a39Sopenharmony_ci
333e1051a39Sopenharmony_ci            c->cache_peer_name =
334e1051a39Sopenharmony_ci                BIO_ADDR_hostname_string(&c->cache_peer_addr, 1);
335e1051a39Sopenharmony_ci            c->cache_peer_serv =
336e1051a39Sopenharmony_ci                BIO_ADDR_service_string(&c->cache_peer_addr, 1);
337e1051a39Sopenharmony_ci            c->state = ACPT_S_OK;
338e1051a39Sopenharmony_ci            bio = NULL;
339e1051a39Sopenharmony_ci            ret = 1;
340e1051a39Sopenharmony_ci            goto end;
341e1051a39Sopenharmony_ci
342e1051a39Sopenharmony_ci        case ACPT_S_OK:
343e1051a39Sopenharmony_ci            if (b->next_bio == NULL) {
344e1051a39Sopenharmony_ci                c->state = ACPT_S_ACCEPT;
345e1051a39Sopenharmony_ci                break;
346e1051a39Sopenharmony_ci            }
347e1051a39Sopenharmony_ci            ret = 1;
348e1051a39Sopenharmony_ci            goto end;
349e1051a39Sopenharmony_ci
350e1051a39Sopenharmony_ci        default:
351e1051a39Sopenharmony_ci            ret = 0;
352e1051a39Sopenharmony_ci            goto end;
353e1051a39Sopenharmony_ci        }
354e1051a39Sopenharmony_ci    }
355e1051a39Sopenharmony_ci
356e1051a39Sopenharmony_ci  exit_loop:
357e1051a39Sopenharmony_ci    if (bio != NULL)
358e1051a39Sopenharmony_ci        BIO_free(bio);
359e1051a39Sopenharmony_ci    else if (s >= 0)
360e1051a39Sopenharmony_ci        BIO_closesocket(s);
361e1051a39Sopenharmony_ci  end:
362e1051a39Sopenharmony_ci    return ret;
363e1051a39Sopenharmony_ci}
364e1051a39Sopenharmony_ci
365e1051a39Sopenharmony_cistatic int acpt_read(BIO *b, char *out, int outl)
366e1051a39Sopenharmony_ci{
367e1051a39Sopenharmony_ci    int ret = 0;
368e1051a39Sopenharmony_ci    BIO_ACCEPT *data;
369e1051a39Sopenharmony_ci
370e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
371e1051a39Sopenharmony_ci    data = (BIO_ACCEPT *)b->ptr;
372e1051a39Sopenharmony_ci
373e1051a39Sopenharmony_ci    while (b->next_bio == NULL) {
374e1051a39Sopenharmony_ci        ret = acpt_state(b, data);
375e1051a39Sopenharmony_ci        if (ret <= 0)
376e1051a39Sopenharmony_ci            return ret;
377e1051a39Sopenharmony_ci    }
378e1051a39Sopenharmony_ci
379e1051a39Sopenharmony_ci    ret = BIO_read(b->next_bio, out, outl);
380e1051a39Sopenharmony_ci    BIO_copy_next_retry(b);
381e1051a39Sopenharmony_ci    return ret;
382e1051a39Sopenharmony_ci}
383e1051a39Sopenharmony_ci
384e1051a39Sopenharmony_cistatic int acpt_write(BIO *b, const char *in, int inl)
385e1051a39Sopenharmony_ci{
386e1051a39Sopenharmony_ci    int ret;
387e1051a39Sopenharmony_ci    BIO_ACCEPT *data;
388e1051a39Sopenharmony_ci
389e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
390e1051a39Sopenharmony_ci    data = (BIO_ACCEPT *)b->ptr;
391e1051a39Sopenharmony_ci
392e1051a39Sopenharmony_ci    while (b->next_bio == NULL) {
393e1051a39Sopenharmony_ci        ret = acpt_state(b, data);
394e1051a39Sopenharmony_ci        if (ret <= 0)
395e1051a39Sopenharmony_ci            return ret;
396e1051a39Sopenharmony_ci    }
397e1051a39Sopenharmony_ci
398e1051a39Sopenharmony_ci    ret = BIO_write(b->next_bio, in, inl);
399e1051a39Sopenharmony_ci    BIO_copy_next_retry(b);
400e1051a39Sopenharmony_ci    return ret;
401e1051a39Sopenharmony_ci}
402e1051a39Sopenharmony_ci
403e1051a39Sopenharmony_cistatic long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
404e1051a39Sopenharmony_ci{
405e1051a39Sopenharmony_ci    int *ip;
406e1051a39Sopenharmony_ci    long ret = 1;
407e1051a39Sopenharmony_ci    BIO_ACCEPT *data;
408e1051a39Sopenharmony_ci    char **pp;
409e1051a39Sopenharmony_ci
410e1051a39Sopenharmony_ci    data = (BIO_ACCEPT *)b->ptr;
411e1051a39Sopenharmony_ci
412e1051a39Sopenharmony_ci    switch (cmd) {
413e1051a39Sopenharmony_ci    case BIO_CTRL_RESET:
414e1051a39Sopenharmony_ci        ret = 0;
415e1051a39Sopenharmony_ci        data->state = ACPT_S_BEFORE;
416e1051a39Sopenharmony_ci        acpt_close_socket(b);
417e1051a39Sopenharmony_ci        BIO_ADDRINFO_free(data->addr_first);
418e1051a39Sopenharmony_ci        data->addr_first = NULL;
419e1051a39Sopenharmony_ci        b->flags = 0;
420e1051a39Sopenharmony_ci        break;
421e1051a39Sopenharmony_ci    case BIO_C_DO_STATE_MACHINE:
422e1051a39Sopenharmony_ci        /* use this one to start the connection */
423e1051a39Sopenharmony_ci        ret = (long)acpt_state(b, data);
424e1051a39Sopenharmony_ci        break;
425e1051a39Sopenharmony_ci    case BIO_C_SET_ACCEPT:
426e1051a39Sopenharmony_ci        if (ptr != NULL) {
427e1051a39Sopenharmony_ci            if (num == 0) {
428e1051a39Sopenharmony_ci                char *hold_serv = data->param_serv;
429e1051a39Sopenharmony_ci                /* We affect the hostname regardless.  However, the input
430e1051a39Sopenharmony_ci                 * string might contain a host:service spec, so we must
431e1051a39Sopenharmony_ci                 * parse it, which might or might not affect the service
432e1051a39Sopenharmony_ci                 */
433e1051a39Sopenharmony_ci                OPENSSL_free(data->param_addr);
434e1051a39Sopenharmony_ci                data->param_addr = NULL;
435e1051a39Sopenharmony_ci                ret = BIO_parse_hostserv(ptr,
436e1051a39Sopenharmony_ci                                         &data->param_addr,
437e1051a39Sopenharmony_ci                                         &data->param_serv,
438e1051a39Sopenharmony_ci                                         BIO_PARSE_PRIO_SERV);
439e1051a39Sopenharmony_ci                if (hold_serv != data->param_serv)
440e1051a39Sopenharmony_ci                    OPENSSL_free(hold_serv);
441e1051a39Sopenharmony_ci                b->init = 1;
442e1051a39Sopenharmony_ci            } else if (num == 1) {
443e1051a39Sopenharmony_ci                OPENSSL_free(data->param_serv);
444e1051a39Sopenharmony_ci                if ((data->param_serv = OPENSSL_strdup(ptr)) == NULL)
445e1051a39Sopenharmony_ci                    ret = 0;
446e1051a39Sopenharmony_ci                else
447e1051a39Sopenharmony_ci                    b->init = 1;
448e1051a39Sopenharmony_ci            } else if (num == 2) {
449e1051a39Sopenharmony_ci                data->bind_mode |= BIO_SOCK_NONBLOCK;
450e1051a39Sopenharmony_ci            } else if (num == 3) {
451e1051a39Sopenharmony_ci                BIO_free(data->bio_chain);
452e1051a39Sopenharmony_ci                data->bio_chain = (BIO *)ptr;
453e1051a39Sopenharmony_ci            } else if (num == 4) {
454e1051a39Sopenharmony_ci                data->accept_family = *(int *)ptr;
455e1051a39Sopenharmony_ci            }
456e1051a39Sopenharmony_ci        } else {
457e1051a39Sopenharmony_ci            if (num == 2) {
458e1051a39Sopenharmony_ci                data->bind_mode &= ~BIO_SOCK_NONBLOCK;
459e1051a39Sopenharmony_ci            }
460e1051a39Sopenharmony_ci        }
461e1051a39Sopenharmony_ci        break;
462e1051a39Sopenharmony_ci    case BIO_C_SET_NBIO:
463e1051a39Sopenharmony_ci        if (num != 0)
464e1051a39Sopenharmony_ci            data->accepted_mode |= BIO_SOCK_NONBLOCK;
465e1051a39Sopenharmony_ci        else
466e1051a39Sopenharmony_ci            data->accepted_mode &= ~BIO_SOCK_NONBLOCK;
467e1051a39Sopenharmony_ci        break;
468e1051a39Sopenharmony_ci    case BIO_C_SET_FD:
469e1051a39Sopenharmony_ci        b->num = *((int *)ptr);
470e1051a39Sopenharmony_ci        data->accept_sock = b->num;
471e1051a39Sopenharmony_ci        data->state = ACPT_S_ACCEPT;
472e1051a39Sopenharmony_ci        b->shutdown = (int)num;
473e1051a39Sopenharmony_ci        b->init = 1;
474e1051a39Sopenharmony_ci        break;
475e1051a39Sopenharmony_ci    case BIO_C_GET_FD:
476e1051a39Sopenharmony_ci        if (b->init) {
477e1051a39Sopenharmony_ci            ip = (int *)ptr;
478e1051a39Sopenharmony_ci            if (ip != NULL)
479e1051a39Sopenharmony_ci                *ip = data->accept_sock;
480e1051a39Sopenharmony_ci            ret = data->accept_sock;
481e1051a39Sopenharmony_ci        } else
482e1051a39Sopenharmony_ci            ret = -1;
483e1051a39Sopenharmony_ci        break;
484e1051a39Sopenharmony_ci    case BIO_C_GET_ACCEPT:
485e1051a39Sopenharmony_ci        if (b->init) {
486e1051a39Sopenharmony_ci            if (num == 0 && ptr != NULL) {
487e1051a39Sopenharmony_ci                pp = (char **)ptr;
488e1051a39Sopenharmony_ci                *pp = data->cache_accepting_name;
489e1051a39Sopenharmony_ci            } else if (num == 1 && ptr != NULL) {
490e1051a39Sopenharmony_ci                pp = (char **)ptr;
491e1051a39Sopenharmony_ci                *pp = data->cache_accepting_serv;
492e1051a39Sopenharmony_ci            } else if (num == 2 && ptr != NULL) {
493e1051a39Sopenharmony_ci                pp = (char **)ptr;
494e1051a39Sopenharmony_ci                *pp = data->cache_peer_name;
495e1051a39Sopenharmony_ci            } else if (num == 3 && ptr != NULL) {
496e1051a39Sopenharmony_ci                pp = (char **)ptr;
497e1051a39Sopenharmony_ci                *pp = data->cache_peer_serv;
498e1051a39Sopenharmony_ci            } else if (num == 4) {
499e1051a39Sopenharmony_ci                switch (BIO_ADDRINFO_family(data->addr_iter)) {
500e1051a39Sopenharmony_ci#ifdef AF_INET6
501e1051a39Sopenharmony_ci                case AF_INET6:
502e1051a39Sopenharmony_ci                    ret = BIO_FAMILY_IPV6;
503e1051a39Sopenharmony_ci                    break;
504e1051a39Sopenharmony_ci#endif
505e1051a39Sopenharmony_ci                case AF_INET:
506e1051a39Sopenharmony_ci                    ret = BIO_FAMILY_IPV4;
507e1051a39Sopenharmony_ci                    break;
508e1051a39Sopenharmony_ci                case 0:
509e1051a39Sopenharmony_ci                    ret = data->accept_family;
510e1051a39Sopenharmony_ci                    break;
511e1051a39Sopenharmony_ci                default:
512e1051a39Sopenharmony_ci                    ret = -1;
513e1051a39Sopenharmony_ci                    break;
514e1051a39Sopenharmony_ci                }
515e1051a39Sopenharmony_ci            } else
516e1051a39Sopenharmony_ci                ret = -1;
517e1051a39Sopenharmony_ci        } else
518e1051a39Sopenharmony_ci            ret = -1;
519e1051a39Sopenharmony_ci        break;
520e1051a39Sopenharmony_ci    case BIO_CTRL_GET_CLOSE:
521e1051a39Sopenharmony_ci        ret = b->shutdown;
522e1051a39Sopenharmony_ci        break;
523e1051a39Sopenharmony_ci    case BIO_CTRL_SET_CLOSE:
524e1051a39Sopenharmony_ci        b->shutdown = (int)num;
525e1051a39Sopenharmony_ci        break;
526e1051a39Sopenharmony_ci    case BIO_CTRL_PENDING:
527e1051a39Sopenharmony_ci    case BIO_CTRL_WPENDING:
528e1051a39Sopenharmony_ci        ret = 0;
529e1051a39Sopenharmony_ci        break;
530e1051a39Sopenharmony_ci    case BIO_CTRL_FLUSH:
531e1051a39Sopenharmony_ci        break;
532e1051a39Sopenharmony_ci    case BIO_C_SET_BIND_MODE:
533e1051a39Sopenharmony_ci        data->bind_mode = (int)num;
534e1051a39Sopenharmony_ci        break;
535e1051a39Sopenharmony_ci    case BIO_C_GET_BIND_MODE:
536e1051a39Sopenharmony_ci        ret = (long)data->bind_mode;
537e1051a39Sopenharmony_ci        break;
538e1051a39Sopenharmony_ci    case BIO_CTRL_DUP:
539e1051a39Sopenharmony_ci        break;
540e1051a39Sopenharmony_ci    case BIO_CTRL_EOF:
541e1051a39Sopenharmony_ci        if (b->next_bio == NULL)
542e1051a39Sopenharmony_ci            ret = 0;
543e1051a39Sopenharmony_ci        else
544e1051a39Sopenharmony_ci            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
545e1051a39Sopenharmony_ci        break;
546e1051a39Sopenharmony_ci    default:
547e1051a39Sopenharmony_ci        ret = 0;
548e1051a39Sopenharmony_ci        break;
549e1051a39Sopenharmony_ci    }
550e1051a39Sopenharmony_ci    return ret;
551e1051a39Sopenharmony_ci}
552e1051a39Sopenharmony_ci
553e1051a39Sopenharmony_cistatic int acpt_puts(BIO *bp, const char *str)
554e1051a39Sopenharmony_ci{
555e1051a39Sopenharmony_ci    int n, ret;
556e1051a39Sopenharmony_ci
557e1051a39Sopenharmony_ci    n = strlen(str);
558e1051a39Sopenharmony_ci    ret = acpt_write(bp, str, n);
559e1051a39Sopenharmony_ci    return ret;
560e1051a39Sopenharmony_ci}
561e1051a39Sopenharmony_ci
562e1051a39Sopenharmony_ciBIO *BIO_new_accept(const char *str)
563e1051a39Sopenharmony_ci{
564e1051a39Sopenharmony_ci    BIO *ret;
565e1051a39Sopenharmony_ci
566e1051a39Sopenharmony_ci    ret = BIO_new(BIO_s_accept());
567e1051a39Sopenharmony_ci    if (ret == NULL)
568e1051a39Sopenharmony_ci        return NULL;
569e1051a39Sopenharmony_ci    if (BIO_set_accept_name(ret, str) > 0)
570e1051a39Sopenharmony_ci        return ret;
571e1051a39Sopenharmony_ci    BIO_free(ret);
572e1051a39Sopenharmony_ci    return NULL;
573e1051a39Sopenharmony_ci}
574e1051a39Sopenharmony_ci
575e1051a39Sopenharmony_ci#endif
576