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