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