/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#ifndef OPENSSL_NO_SOCK
-# define USE_SOCKETS
# include "apps.h"
-# undef USE_SOCKETS
# include "s_apps.h"
+# include "internal/sockets.h"
# include <openssl/bio.h>
# include <openssl/err.h>
* @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or
* AF_UNSPEC
* @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
+ * @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any)
*
* This will create a socket and use it to connect to a host:port, or if
* family == AF_UNIX, to the path found in host.
* Returns 1 on success, 0 on failure.
*/
int init_client(int *sock, const char *host, const char *port,
- int family, int type)
+ int family, int type, int protocol)
{
BIO_ADDRINFO *res = NULL;
const BIO_ADDRINFO *ai = NULL;
int ret;
- if (!BIO_sock_init())
+ if (BIO_sock_init() != 1)
return 0;
- ret = BIO_lookup(host, port, BIO_LOOKUP_CLIENT, family, type, &res);
+ ret = BIO_lookup_ex(host, port, BIO_LOOKUP_CLIENT, family, type, protocol,
+ &res);
if (ret == 0) {
ERR_print_errors(bio_err);
return 0;
/* Admittedly, these checks are quite paranoid, we should not get
* anything in the BIO_ADDRINFO chain that we haven't
* asked for. */
- OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))
- && (type == 0 || type == BIO_ADDRINFO_socktype(res)));
+ OPENSSL_assert((family == AF_UNSPEC
+ || family == BIO_ADDRINFO_family(ai))
+ && (type == 0 || type == BIO_ADDRINFO_socktype(ai))
+ && (protocol == 0
+ || protocol == BIO_ADDRINFO_protocol(ai)));
*sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai),
- BIO_ADDRINFO_protocol(res), 0);
+ BIO_ADDRINFO_protocol(ai), 0);
if (*sock == INVALID_SOCKET) {
/* Maybe the kernel doesn't support the socket family, even if
* BIO_lookup() added it in the returned result...
*/
continue;
}
+
+#ifndef OPENSSL_NO_SCTP
+ if (protocol == IPPROTO_SCTP) {
+ /*
+ * For SCTP we have to set various options on the socket prior to
+ * connecting. This is done automatically by BIO_new_dgram_sctp().
+ * We don't actually need the created BIO though so we free it again
+ * immediately.
+ */
+ BIO *tmpbio = BIO_new_dgram_sctp(*sock, BIO_NOCLOSE);
+
+ if (tmpbio == NULL) {
+ ERR_print_errors(bio_err);
+ return 0;
+ }
+ BIO_free(tmpbio);
+ }
+#endif
+
if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai), 0)) {
BIO_closesocket(*sock);
*sock = INVALID_SOCKET;
* 0 on failure, something other on success.
*/
int do_server(int *accept_sock, const char *host, const char *port,
- int family, int type, do_server_cb cb,
+ int family, int type, int protocol, do_server_cb cb,
unsigned char *context, int naccept)
{
int asock = 0;
BIO_ADDRINFO *res = NULL;
int ret = 0;
- if (!BIO_sock_init())
+ if (BIO_sock_init() != 1)
return 0;
- if (!BIO_lookup(host, port, BIO_LOOKUP_SERVER, family, type, &res)) {
+ if (!BIO_lookup_ex(host, port, BIO_LOOKUP_SERVER, family, type, protocol,
+ &res)) {
ERR_print_errors(bio_err);
return 0;
}
/* Admittedly, these checks are quite paranoid, we should not get
* anything in the BIO_ADDRINFO chain that we haven't asked for */
OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))
- && (type == 0 || type == BIO_ADDRINFO_socktype(res)));
+ && (type == 0 || type == BIO_ADDRINFO_socktype(res))
+ && (protocol == 0 || protocol == BIO_ADDRINFO_protocol(res)));
asock = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res),
BIO_ADDRINFO_protocol(res), 0);
goto end;
}
+#ifndef OPENSSL_NO_SCTP
+ if (protocol == IPPROTO_SCTP) {
+ /*
+ * For SCTP we have to set various options on the socket prior to
+ * accepting. This is done automatically by BIO_new_dgram_sctp().
+ * We don't actually need the created BIO though so we free it again
+ * immediately.
+ */
+ BIO *tmpbio = BIO_new_dgram_sctp(asock, BIO_NOCLOSE);
+
+ if (tmpbio == NULL) {
+ BIO_closesocket(asock);
+ ERR_print_errors(bio_err);
+ goto end;
+ }
+ BIO_free(tmpbio);
+ }
+#endif
+
BIO_ADDRINFO_free(res);
res = NULL;
if (type == SOCK_STREAM) {
do {
sock = BIO_accept_ex(asock, NULL, 0);
- } while (sock < 0 && BIO_sock_should_retry(ret));
+ } while (sock < 0 && BIO_sock_should_retry(sock));
if (sock < 0) {
ERR_print_errors(bio_err);
BIO_closesocket(asock);
break;
}
- i = (*cb)(sock, type, context);
+ i = (*cb)(sock, type, protocol, context);
+ /*
+ * If we ended with an alert being sent, but still with data in the
+ * network buffer to be read, then calling BIO_closesocket() will
+ * result in a TCP-RST being sent. On some platforms (notably
+ * Windows) then this will result in the peer immediately abandoning
+ * the connection including any buffered alert data before it has
+ * had a chance to be read. Shutting down the sending side first,
+ * and then closing the socket sends TCP-FIN first followed by
+ * TCP-RST. This seems to allow the peer to read the alert data.
+ */
+#ifdef _WIN32
+# ifdef SD_SEND
+ shutdown(sock, SD_SEND);
+# endif
+#elif defined(SHUT_WR)
+ shutdown(sock, SHUT_WR);
+#endif
BIO_closesocket(sock);
} else {
- i = (*cb)(asock, type, context);
+ i = (*cb)(asock, type, protocol, context);
}
if (naccept != -1)