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/* socket-related functions used by s_client and s_server */
11e1051a39Sopenharmony_ci#include <stdio.h>
12e1051a39Sopenharmony_ci#include <stdlib.h>
13e1051a39Sopenharmony_ci#include <string.h>
14e1051a39Sopenharmony_ci#include <errno.h>
15e1051a39Sopenharmony_ci#include <signal.h>
16e1051a39Sopenharmony_ci#include <openssl/opensslconf.h>
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_ci/*
19e1051a39Sopenharmony_ci * With IPv6, it looks like Digital has mixed up the proper order of
20e1051a39Sopenharmony_ci * recursive header file inclusion, resulting in the compiler complaining
21e1051a39Sopenharmony_ci * that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is
22e1051a39Sopenharmony_ci * needed to have fileno() declared correctly...  So let's define u_int
23e1051a39Sopenharmony_ci */
24e1051a39Sopenharmony_ci#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
25e1051a39Sopenharmony_ci# define __U_INT
26e1051a39Sopenharmony_citypedef unsigned int u_int;
27e1051a39Sopenharmony_ci#endif
28e1051a39Sopenharmony_ci
29e1051a39Sopenharmony_ci#ifdef _WIN32
30e1051a39Sopenharmony_ci# include <process.h>
31e1051a39Sopenharmony_ci
32e1051a39Sopenharmony_ci/* MSVC renamed some POSIX functions to have an underscore prefix. */
33e1051a39Sopenharmony_ci# ifdef _MSC_VER
34e1051a39Sopenharmony_ci#  define getpid _getpid
35e1051a39Sopenharmony_ci# endif
36e1051a39Sopenharmony_ci#endif
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SOCK
39e1051a39Sopenharmony_ci
40e1051a39Sopenharmony_ci# include "apps.h"
41e1051a39Sopenharmony_ci# include "s_apps.h"
42e1051a39Sopenharmony_ci# include "internal/sockets.h"
43e1051a39Sopenharmony_ci
44e1051a39Sopenharmony_ci# if defined(__TANDEM)
45e1051a39Sopenharmony_ci#  if defined(OPENSSL_TANDEM_FLOSS)
46e1051a39Sopenharmony_ci#   include <floss.h(floss_read)>
47e1051a39Sopenharmony_ci#  endif
48e1051a39Sopenharmony_ci# endif
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_ci# include <openssl/bio.h>
51e1051a39Sopenharmony_ci# include <openssl/err.h>
52e1051a39Sopenharmony_ci
53e1051a39Sopenharmony_ci/* Keep track of our peer's address for the cookie callback */
54e1051a39Sopenharmony_ciBIO_ADDR *ourpeer = NULL;
55e1051a39Sopenharmony_ci
56e1051a39Sopenharmony_ci/*
57e1051a39Sopenharmony_ci * init_client - helper routine to set up socket communication
58e1051a39Sopenharmony_ci * @sock: pointer to storage of resulting socket.
59e1051a39Sopenharmony_ci * @host: the host name or path (for AF_UNIX) to connect to.
60e1051a39Sopenharmony_ci * @port: the port to connect to (ignored for AF_UNIX).
61e1051a39Sopenharmony_ci * @bindhost: source host or path (for AF_UNIX).
62e1051a39Sopenharmony_ci * @bindport: source port (ignored for AF_UNIX).
63e1051a39Sopenharmony_ci * @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or
64e1051a39Sopenharmony_ci *  AF_UNSPEC
65e1051a39Sopenharmony_ci * @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
66e1051a39Sopenharmony_ci * @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any)
67e1051a39Sopenharmony_ci *
68e1051a39Sopenharmony_ci * This will create a socket and use it to connect to a host:port, or if
69e1051a39Sopenharmony_ci * family == AF_UNIX, to the path found in host.
70e1051a39Sopenharmony_ci *
71e1051a39Sopenharmony_ci * If the host has more than one address, it will try them one by one until
72e1051a39Sopenharmony_ci * a successful connection is established.  The resulting socket will be
73e1051a39Sopenharmony_ci * found in *sock on success, it will be given INVALID_SOCKET otherwise.
74e1051a39Sopenharmony_ci *
75e1051a39Sopenharmony_ci * Returns 1 on success, 0 on failure.
76e1051a39Sopenharmony_ci */
77e1051a39Sopenharmony_ciint init_client(int *sock, const char *host, const char *port,
78e1051a39Sopenharmony_ci                const char *bindhost, const char *bindport,
79e1051a39Sopenharmony_ci                int family, int type, int protocol)
80e1051a39Sopenharmony_ci{
81e1051a39Sopenharmony_ci    BIO_ADDRINFO *res = NULL;
82e1051a39Sopenharmony_ci    BIO_ADDRINFO *bindaddr = NULL;
83e1051a39Sopenharmony_ci    const BIO_ADDRINFO *ai = NULL;
84e1051a39Sopenharmony_ci    const BIO_ADDRINFO *bi = NULL;
85e1051a39Sopenharmony_ci    int found = 0;
86e1051a39Sopenharmony_ci    int ret;
87e1051a39Sopenharmony_ci
88e1051a39Sopenharmony_ci    if (BIO_sock_init() != 1)
89e1051a39Sopenharmony_ci        return 0;
90e1051a39Sopenharmony_ci
91e1051a39Sopenharmony_ci    ret = BIO_lookup_ex(host, port, BIO_LOOKUP_CLIENT, family, type, protocol,
92e1051a39Sopenharmony_ci                        &res);
93e1051a39Sopenharmony_ci    if (ret == 0) {
94e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
95e1051a39Sopenharmony_ci        return 0;
96e1051a39Sopenharmony_ci    }
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci    if (bindhost != NULL || bindport != NULL) {
99e1051a39Sopenharmony_ci        ret = BIO_lookup_ex(bindhost, bindport, BIO_LOOKUP_CLIENT,
100e1051a39Sopenharmony_ci                            family, type, protocol, &bindaddr);
101e1051a39Sopenharmony_ci        if (ret == 0) {
102e1051a39Sopenharmony_ci            ERR_print_errors (bio_err);
103e1051a39Sopenharmony_ci            goto out;
104e1051a39Sopenharmony_ci        }
105e1051a39Sopenharmony_ci    }
106e1051a39Sopenharmony_ci
107e1051a39Sopenharmony_ci    ret = 0;
108e1051a39Sopenharmony_ci    for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
109e1051a39Sopenharmony_ci        /* Admittedly, these checks are quite paranoid, we should not get
110e1051a39Sopenharmony_ci         * anything in the BIO_ADDRINFO chain that we haven't
111e1051a39Sopenharmony_ci         * asked for. */
112e1051a39Sopenharmony_ci        OPENSSL_assert((family == AF_UNSPEC
113e1051a39Sopenharmony_ci                        || family == BIO_ADDRINFO_family(ai))
114e1051a39Sopenharmony_ci                       && (type == 0 || type == BIO_ADDRINFO_socktype(ai))
115e1051a39Sopenharmony_ci                       && (protocol == 0
116e1051a39Sopenharmony_ci                           || protocol == BIO_ADDRINFO_protocol(ai)));
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ci        if (bindaddr != NULL) {
119e1051a39Sopenharmony_ci            for (bi = bindaddr; bi != NULL; bi = BIO_ADDRINFO_next(bi)) {
120e1051a39Sopenharmony_ci                if (BIO_ADDRINFO_family(bi) == BIO_ADDRINFO_family(ai))
121e1051a39Sopenharmony_ci                    break;
122e1051a39Sopenharmony_ci            }
123e1051a39Sopenharmony_ci            if (bi == NULL)
124e1051a39Sopenharmony_ci                continue;
125e1051a39Sopenharmony_ci            ++found;
126e1051a39Sopenharmony_ci        }
127e1051a39Sopenharmony_ci
128e1051a39Sopenharmony_ci        *sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai),
129e1051a39Sopenharmony_ci                           BIO_ADDRINFO_protocol(ai), 0);
130e1051a39Sopenharmony_ci        if (*sock == INVALID_SOCKET) {
131e1051a39Sopenharmony_ci            /* Maybe the kernel doesn't support the socket family, even if
132e1051a39Sopenharmony_ci             * BIO_lookup() added it in the returned result...
133e1051a39Sopenharmony_ci             */
134e1051a39Sopenharmony_ci            continue;
135e1051a39Sopenharmony_ci        }
136e1051a39Sopenharmony_ci
137e1051a39Sopenharmony_ci        if (bi != NULL) {
138e1051a39Sopenharmony_ci            if (!BIO_bind(*sock, BIO_ADDRINFO_address(bi),
139e1051a39Sopenharmony_ci                          BIO_SOCK_REUSEADDR)) {
140e1051a39Sopenharmony_ci                BIO_closesocket(*sock);
141e1051a39Sopenharmony_ci                *sock = INVALID_SOCKET;
142e1051a39Sopenharmony_ci                break;
143e1051a39Sopenharmony_ci            }
144e1051a39Sopenharmony_ci        }
145e1051a39Sopenharmony_ci
146e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SCTP
147e1051a39Sopenharmony_ci        if (protocol == IPPROTO_SCTP) {
148e1051a39Sopenharmony_ci            /*
149e1051a39Sopenharmony_ci             * For SCTP we have to set various options on the socket prior to
150e1051a39Sopenharmony_ci             * connecting. This is done automatically by BIO_new_dgram_sctp().
151e1051a39Sopenharmony_ci             * We don't actually need the created BIO though so we free it again
152e1051a39Sopenharmony_ci             * immediately.
153e1051a39Sopenharmony_ci             */
154e1051a39Sopenharmony_ci            BIO *tmpbio = BIO_new_dgram_sctp(*sock, BIO_NOCLOSE);
155e1051a39Sopenharmony_ci
156e1051a39Sopenharmony_ci            if (tmpbio == NULL) {
157e1051a39Sopenharmony_ci                ERR_print_errors(bio_err);
158e1051a39Sopenharmony_ci                return 0;
159e1051a39Sopenharmony_ci            }
160e1051a39Sopenharmony_ci            BIO_free(tmpbio);
161e1051a39Sopenharmony_ci        }
162e1051a39Sopenharmony_ci#endif
163e1051a39Sopenharmony_ci
164e1051a39Sopenharmony_ci        if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai),
165e1051a39Sopenharmony_ci                         BIO_ADDRINFO_protocol(ai) == IPPROTO_TCP ? BIO_SOCK_NODELAY : 0)) {
166e1051a39Sopenharmony_ci            BIO_closesocket(*sock);
167e1051a39Sopenharmony_ci            *sock = INVALID_SOCKET;
168e1051a39Sopenharmony_ci            continue;
169e1051a39Sopenharmony_ci        }
170e1051a39Sopenharmony_ci
171e1051a39Sopenharmony_ci        /* Success, don't try any more addresses */
172e1051a39Sopenharmony_ci        break;
173e1051a39Sopenharmony_ci    }
174e1051a39Sopenharmony_ci
175e1051a39Sopenharmony_ci    if (*sock == INVALID_SOCKET) {
176e1051a39Sopenharmony_ci        if (bindaddr != NULL && !found) {
177e1051a39Sopenharmony_ci            BIO_printf(bio_err, "Can't bind %saddress for %s%s%s\n",
178e1051a39Sopenharmony_ci#ifdef AF_INET6
179e1051a39Sopenharmony_ci                       BIO_ADDRINFO_family(res) == AF_INET6 ? "IPv6 " :
180e1051a39Sopenharmony_ci#endif
181e1051a39Sopenharmony_ci                       BIO_ADDRINFO_family(res) == AF_INET ? "IPv4 " :
182e1051a39Sopenharmony_ci                       BIO_ADDRINFO_family(res) == AF_UNIX ? "unix " : "",
183e1051a39Sopenharmony_ci                       bindhost != NULL ? bindhost : "",
184e1051a39Sopenharmony_ci                       bindport != NULL ? ":" : "",
185e1051a39Sopenharmony_ci                       bindport != NULL ? bindport : "");
186e1051a39Sopenharmony_ci            ERR_clear_error();
187e1051a39Sopenharmony_ci            ret = 0;
188e1051a39Sopenharmony_ci        }
189e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
190e1051a39Sopenharmony_ci    } else {
191e1051a39Sopenharmony_ci        /* Remove any stale errors from previous connection attempts */
192e1051a39Sopenharmony_ci        ERR_clear_error();
193e1051a39Sopenharmony_ci        ret = 1;
194e1051a39Sopenharmony_ci    }
195e1051a39Sopenharmony_ciout:
196e1051a39Sopenharmony_ci    if (bindaddr != NULL) {
197e1051a39Sopenharmony_ci        BIO_ADDRINFO_free (bindaddr);
198e1051a39Sopenharmony_ci    }
199e1051a39Sopenharmony_ci    BIO_ADDRINFO_free(res);
200e1051a39Sopenharmony_ci    return ret;
201e1051a39Sopenharmony_ci}
202e1051a39Sopenharmony_ci
203e1051a39Sopenharmony_ciint report_server_accept(BIO *out, int asock, int with_address, int with_pid)
204e1051a39Sopenharmony_ci{
205e1051a39Sopenharmony_ci    int success = 1;
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    if (BIO_printf(out, "ACCEPT") <= 0)
208e1051a39Sopenharmony_ci        return 0;
209e1051a39Sopenharmony_ci    if (with_address) {
210e1051a39Sopenharmony_ci        union BIO_sock_info_u info;
211e1051a39Sopenharmony_ci        char *hostname = NULL;
212e1051a39Sopenharmony_ci        char *service = NULL;
213e1051a39Sopenharmony_ci
214e1051a39Sopenharmony_ci        if ((info.addr = BIO_ADDR_new()) != NULL
215e1051a39Sopenharmony_ci            && BIO_sock_info(asock, BIO_SOCK_INFO_ADDRESS, &info)
216e1051a39Sopenharmony_ci            && (hostname = BIO_ADDR_hostname_string(info.addr, 1)) != NULL
217e1051a39Sopenharmony_ci            && (service = BIO_ADDR_service_string(info.addr, 1)) != NULL) {
218e1051a39Sopenharmony_ci            success = BIO_printf(out,
219e1051a39Sopenharmony_ci                                 strchr(hostname, ':') == NULL
220e1051a39Sopenharmony_ci                                 ? /* IPv4 */ " %s:%s"
221e1051a39Sopenharmony_ci                                 : /* IPv6 */ " [%s]:%s",
222e1051a39Sopenharmony_ci                                 hostname, service) > 0;
223e1051a39Sopenharmony_ci        } else {
224e1051a39Sopenharmony_ci            (void)BIO_printf(out, "unknown:error\n");
225e1051a39Sopenharmony_ci            success = 0;
226e1051a39Sopenharmony_ci        }
227e1051a39Sopenharmony_ci        OPENSSL_free(hostname);
228e1051a39Sopenharmony_ci        OPENSSL_free(service);
229e1051a39Sopenharmony_ci        BIO_ADDR_free(info.addr);
230e1051a39Sopenharmony_ci    }
231e1051a39Sopenharmony_ci    if (with_pid)
232e1051a39Sopenharmony_ci        success = success && BIO_printf(out, " PID=%d", getpid()) > 0;
233e1051a39Sopenharmony_ci    success = success && BIO_printf(out, "\n") > 0;
234e1051a39Sopenharmony_ci    (void)BIO_flush(out);
235e1051a39Sopenharmony_ci
236e1051a39Sopenharmony_ci    return success;
237e1051a39Sopenharmony_ci}
238e1051a39Sopenharmony_ci
239e1051a39Sopenharmony_ci/*
240e1051a39Sopenharmony_ci * do_server - helper routine to perform a server operation
241e1051a39Sopenharmony_ci * @accept_sock: pointer to storage of resulting socket.
242e1051a39Sopenharmony_ci * @host: the host name or path (for AF_UNIX) to connect to.
243e1051a39Sopenharmony_ci * @port: the port to connect to (ignored for AF_UNIX).
244e1051a39Sopenharmony_ci * @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or
245e1051a39Sopenharmony_ci *  AF_UNSPEC
246e1051a39Sopenharmony_ci * @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
247e1051a39Sopenharmony_ci * @cb: pointer to a function that receives the accepted socket and
248e1051a39Sopenharmony_ci *  should perform the communication with the connecting client.
249e1051a39Sopenharmony_ci * @context: pointer to memory that's passed verbatim to the cb function.
250e1051a39Sopenharmony_ci * @naccept: number of times an incoming connect should be accepted.  If -1,
251e1051a39Sopenharmony_ci *  unlimited number.
252e1051a39Sopenharmony_ci *
253e1051a39Sopenharmony_ci * This will create a socket and use it to listen to a host:port, or if
254e1051a39Sopenharmony_ci * family == AF_UNIX, to the path found in host, then start accepting
255e1051a39Sopenharmony_ci * incoming connections and run cb on the resulting socket.
256e1051a39Sopenharmony_ci *
257e1051a39Sopenharmony_ci * 0 on failure, something other on success.
258e1051a39Sopenharmony_ci */
259e1051a39Sopenharmony_ciint do_server(int *accept_sock, const char *host, const char *port,
260e1051a39Sopenharmony_ci              int family, int type, int protocol, do_server_cb cb,
261e1051a39Sopenharmony_ci              unsigned char *context, int naccept, BIO *bio_s_out)
262e1051a39Sopenharmony_ci{
263e1051a39Sopenharmony_ci    int asock = 0;
264e1051a39Sopenharmony_ci    int sock;
265e1051a39Sopenharmony_ci    int i;
266e1051a39Sopenharmony_ci    BIO_ADDRINFO *res = NULL;
267e1051a39Sopenharmony_ci    const BIO_ADDRINFO *next;
268e1051a39Sopenharmony_ci    int sock_family, sock_type, sock_protocol, sock_port;
269e1051a39Sopenharmony_ci    const BIO_ADDR *sock_address;
270e1051a39Sopenharmony_ci    int sock_family_fallback = AF_UNSPEC;
271e1051a39Sopenharmony_ci    const BIO_ADDR *sock_address_fallback = NULL;
272e1051a39Sopenharmony_ci    int sock_options = BIO_SOCK_REUSEADDR;
273e1051a39Sopenharmony_ci    int ret = 0;
274e1051a39Sopenharmony_ci
275e1051a39Sopenharmony_ci    if (BIO_sock_init() != 1)
276e1051a39Sopenharmony_ci        return 0;
277e1051a39Sopenharmony_ci
278e1051a39Sopenharmony_ci    if (!BIO_lookup_ex(host, port, BIO_LOOKUP_SERVER, family, type, protocol,
279e1051a39Sopenharmony_ci                       &res)) {
280e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
281e1051a39Sopenharmony_ci        return 0;
282e1051a39Sopenharmony_ci    }
283e1051a39Sopenharmony_ci
284e1051a39Sopenharmony_ci    /* Admittedly, these checks are quite paranoid, we should not get
285e1051a39Sopenharmony_ci     * anything in the BIO_ADDRINFO chain that we haven't asked for */
286e1051a39Sopenharmony_ci    OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))
287e1051a39Sopenharmony_ci                   && (type == 0 || type == BIO_ADDRINFO_socktype(res))
288e1051a39Sopenharmony_ci                   && (protocol == 0 || protocol == BIO_ADDRINFO_protocol(res)));
289e1051a39Sopenharmony_ci
290e1051a39Sopenharmony_ci    sock_family = BIO_ADDRINFO_family(res);
291e1051a39Sopenharmony_ci    sock_type = BIO_ADDRINFO_socktype(res);
292e1051a39Sopenharmony_ci    sock_protocol = BIO_ADDRINFO_protocol(res);
293e1051a39Sopenharmony_ci    sock_address = BIO_ADDRINFO_address(res);
294e1051a39Sopenharmony_ci    next = BIO_ADDRINFO_next(res);
295e1051a39Sopenharmony_ci#ifdef AF_INET6
296e1051a39Sopenharmony_ci    if (sock_family == AF_INET6)
297e1051a39Sopenharmony_ci        sock_options |= BIO_SOCK_V6_ONLY;
298e1051a39Sopenharmony_ci    if (next != NULL
299e1051a39Sopenharmony_ci            && BIO_ADDRINFO_socktype(next) == sock_type
300e1051a39Sopenharmony_ci            && BIO_ADDRINFO_protocol(next) == sock_protocol) {
301e1051a39Sopenharmony_ci        if (sock_family == AF_INET
302e1051a39Sopenharmony_ci                && BIO_ADDRINFO_family(next) == AF_INET6) {
303e1051a39Sopenharmony_ci            /* In case AF_INET6 is returned but not supported by the
304e1051a39Sopenharmony_ci             * kernel, retry with the first detected address family */
305e1051a39Sopenharmony_ci            sock_family_fallback = sock_family;
306e1051a39Sopenharmony_ci            sock_address_fallback = sock_address;
307e1051a39Sopenharmony_ci            sock_family = AF_INET6;
308e1051a39Sopenharmony_ci            sock_address = BIO_ADDRINFO_address(next);
309e1051a39Sopenharmony_ci        } else if (sock_family == AF_INET6
310e1051a39Sopenharmony_ci                   && BIO_ADDRINFO_family(next) == AF_INET) {
311e1051a39Sopenharmony_ci            sock_options &= ~BIO_SOCK_V6_ONLY;
312e1051a39Sopenharmony_ci        }
313e1051a39Sopenharmony_ci    }
314e1051a39Sopenharmony_ci#endif
315e1051a39Sopenharmony_ci
316e1051a39Sopenharmony_ci    asock = BIO_socket(sock_family, sock_type, sock_protocol, 0);
317e1051a39Sopenharmony_ci    if (asock == INVALID_SOCKET && sock_family_fallback != AF_UNSPEC) {
318e1051a39Sopenharmony_ci        asock = BIO_socket(sock_family_fallback, sock_type, sock_protocol, 0);
319e1051a39Sopenharmony_ci        sock_address = sock_address_fallback;
320e1051a39Sopenharmony_ci    }
321e1051a39Sopenharmony_ci    if (asock == INVALID_SOCKET
322e1051a39Sopenharmony_ci        || !BIO_listen(asock, sock_address, sock_options)) {
323e1051a39Sopenharmony_ci        BIO_ADDRINFO_free(res);
324e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
325e1051a39Sopenharmony_ci        if (asock != INVALID_SOCKET)
326e1051a39Sopenharmony_ci            BIO_closesocket(asock);
327e1051a39Sopenharmony_ci        goto end;
328e1051a39Sopenharmony_ci    }
329e1051a39Sopenharmony_ci
330e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SCTP
331e1051a39Sopenharmony_ci    if (protocol == IPPROTO_SCTP) {
332e1051a39Sopenharmony_ci        /*
333e1051a39Sopenharmony_ci         * For SCTP we have to set various options on the socket prior to
334e1051a39Sopenharmony_ci         * accepting. This is done automatically by BIO_new_dgram_sctp().
335e1051a39Sopenharmony_ci         * We don't actually need the created BIO though so we free it again
336e1051a39Sopenharmony_ci         * immediately.
337e1051a39Sopenharmony_ci         */
338e1051a39Sopenharmony_ci        BIO *tmpbio = BIO_new_dgram_sctp(asock, BIO_NOCLOSE);
339e1051a39Sopenharmony_ci
340e1051a39Sopenharmony_ci        if (tmpbio == NULL) {
341e1051a39Sopenharmony_ci            BIO_closesocket(asock);
342e1051a39Sopenharmony_ci            ERR_print_errors(bio_err);
343e1051a39Sopenharmony_ci            goto end;
344e1051a39Sopenharmony_ci        }
345e1051a39Sopenharmony_ci        BIO_free(tmpbio);
346e1051a39Sopenharmony_ci    }
347e1051a39Sopenharmony_ci#endif
348e1051a39Sopenharmony_ci
349e1051a39Sopenharmony_ci    sock_port = BIO_ADDR_rawport(sock_address);
350e1051a39Sopenharmony_ci
351e1051a39Sopenharmony_ci    BIO_ADDRINFO_free(res);
352e1051a39Sopenharmony_ci    res = NULL;
353e1051a39Sopenharmony_ci
354e1051a39Sopenharmony_ci    if (!report_server_accept(bio_s_out, asock, sock_port == 0, 0)) {
355e1051a39Sopenharmony_ci        BIO_closesocket(asock);
356e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
357e1051a39Sopenharmony_ci        goto end;
358e1051a39Sopenharmony_ci    }
359e1051a39Sopenharmony_ci
360e1051a39Sopenharmony_ci    if (accept_sock != NULL)
361e1051a39Sopenharmony_ci        *accept_sock = asock;
362e1051a39Sopenharmony_ci    for (;;) {
363e1051a39Sopenharmony_ci        char sink[64];
364e1051a39Sopenharmony_ci        struct timeval timeout;
365e1051a39Sopenharmony_ci        fd_set readfds;
366e1051a39Sopenharmony_ci
367e1051a39Sopenharmony_ci        if (type == SOCK_STREAM) {
368e1051a39Sopenharmony_ci            BIO_ADDR_free(ourpeer);
369e1051a39Sopenharmony_ci            ourpeer = BIO_ADDR_new();
370e1051a39Sopenharmony_ci            if (ourpeer == NULL) {
371e1051a39Sopenharmony_ci                BIO_closesocket(asock);
372e1051a39Sopenharmony_ci                ERR_print_errors(bio_err);
373e1051a39Sopenharmony_ci                goto end;
374e1051a39Sopenharmony_ci            }
375e1051a39Sopenharmony_ci            do {
376e1051a39Sopenharmony_ci                sock = BIO_accept_ex(asock, ourpeer, 0);
377e1051a39Sopenharmony_ci            } while (sock < 0 && BIO_sock_should_retry(sock));
378e1051a39Sopenharmony_ci            if (sock < 0) {
379e1051a39Sopenharmony_ci                ERR_print_errors(bio_err);
380e1051a39Sopenharmony_ci                BIO_closesocket(asock);
381e1051a39Sopenharmony_ci                break;
382e1051a39Sopenharmony_ci            }
383e1051a39Sopenharmony_ci            BIO_set_tcp_ndelay(sock, 1);
384e1051a39Sopenharmony_ci            i = (*cb)(sock, type, protocol, context);
385e1051a39Sopenharmony_ci
386e1051a39Sopenharmony_ci            /*
387e1051a39Sopenharmony_ci             * If we ended with an alert being sent, but still with data in the
388e1051a39Sopenharmony_ci             * network buffer to be read, then calling BIO_closesocket() will
389e1051a39Sopenharmony_ci             * result in a TCP-RST being sent. On some platforms (notably
390e1051a39Sopenharmony_ci             * Windows) then this will result in the peer immediately abandoning
391e1051a39Sopenharmony_ci             * the connection including any buffered alert data before it has
392e1051a39Sopenharmony_ci             * had a chance to be read. Shutting down the sending side first,
393e1051a39Sopenharmony_ci             * and then closing the socket sends TCP-FIN first followed by
394e1051a39Sopenharmony_ci             * TCP-RST. This seems to allow the peer to read the alert data.
395e1051a39Sopenharmony_ci             */
396e1051a39Sopenharmony_ci            shutdown(sock, 1); /* SHUT_WR */
397e1051a39Sopenharmony_ci            /*
398e1051a39Sopenharmony_ci             * We just said we have nothing else to say, but it doesn't mean
399e1051a39Sopenharmony_ci             * that the other side has nothing. It's even recommended to
400e1051a39Sopenharmony_ci             * consume incoming data. [In testing context this ensures that
401e1051a39Sopenharmony_ci             * alerts are passed on...]
402e1051a39Sopenharmony_ci             */
403e1051a39Sopenharmony_ci            timeout.tv_sec = 0;
404e1051a39Sopenharmony_ci            timeout.tv_usec = 500000;  /* some extreme round-trip */
405e1051a39Sopenharmony_ci            do {
406e1051a39Sopenharmony_ci                FD_ZERO(&readfds);
407e1051a39Sopenharmony_ci                openssl_fdset(sock, &readfds);
408e1051a39Sopenharmony_ci            } while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0
409e1051a39Sopenharmony_ci                     && readsocket(sock, sink, sizeof(sink)) > 0);
410e1051a39Sopenharmony_ci
411e1051a39Sopenharmony_ci            BIO_closesocket(sock);
412e1051a39Sopenharmony_ci        } else {
413e1051a39Sopenharmony_ci            i = (*cb)(asock, type, protocol, context);
414e1051a39Sopenharmony_ci        }
415e1051a39Sopenharmony_ci
416e1051a39Sopenharmony_ci        if (naccept != -1)
417e1051a39Sopenharmony_ci            naccept--;
418e1051a39Sopenharmony_ci        if (i < 0 || naccept == 0) {
419e1051a39Sopenharmony_ci            BIO_closesocket(asock);
420e1051a39Sopenharmony_ci            ret = i;
421e1051a39Sopenharmony_ci            break;
422e1051a39Sopenharmony_ci        }
423e1051a39Sopenharmony_ci    }
424e1051a39Sopenharmony_ci end:
425e1051a39Sopenharmony_ci# ifdef AF_UNIX
426e1051a39Sopenharmony_ci    if (family == AF_UNIX)
427e1051a39Sopenharmony_ci        unlink(host);
428e1051a39Sopenharmony_ci# endif
429e1051a39Sopenharmony_ci    BIO_ADDR_free(ourpeer);
430e1051a39Sopenharmony_ci    ourpeer = NULL;
431e1051a39Sopenharmony_ci    return ret;
432e1051a39Sopenharmony_ci}
433e1051a39Sopenharmony_ci
434e1051a39Sopenharmony_civoid do_ssl_shutdown(SSL *ssl)
435e1051a39Sopenharmony_ci{
436e1051a39Sopenharmony_ci    int ret;
437e1051a39Sopenharmony_ci
438e1051a39Sopenharmony_ci    do {
439e1051a39Sopenharmony_ci        /* We only do unidirectional shutdown */
440e1051a39Sopenharmony_ci        ret = SSL_shutdown(ssl);
441e1051a39Sopenharmony_ci        if (ret < 0) {
442e1051a39Sopenharmony_ci            switch (SSL_get_error(ssl, ret)) {
443e1051a39Sopenharmony_ci            case SSL_ERROR_WANT_READ:
444e1051a39Sopenharmony_ci            case SSL_ERROR_WANT_WRITE:
445e1051a39Sopenharmony_ci            case SSL_ERROR_WANT_ASYNC:
446e1051a39Sopenharmony_ci            case SSL_ERROR_WANT_ASYNC_JOB:
447e1051a39Sopenharmony_ci                /* We just do busy waiting. Nothing clever */
448e1051a39Sopenharmony_ci                continue;
449e1051a39Sopenharmony_ci            }
450e1051a39Sopenharmony_ci            ret = 0;
451e1051a39Sopenharmony_ci        }
452e1051a39Sopenharmony_ci    } while (ret < 0);
453e1051a39Sopenharmony_ci}
454e1051a39Sopenharmony_ci
455e1051a39Sopenharmony_ci#endif  /* OPENSSL_NO_SOCK */
456