socket() call can return an error - e.g. EMFILE, so we need to handle
this nicely and not crash.
Additionally wrap the socket() call inside a platform independent helper
function as the Socket data type on Windows is unsigned integer:
> This means, for example, that checking for errors when the socket and
> accept functions return should not be done by comparing the return
> value with –1, or seeing if the value is negative (both common and
> legal approaches in UNIX). Instead, an application should use the
> manifest constant INVALID_SOCKET as defined in the Winsock2.h header
> file.
(cherry picked from commit
8af7f81d6c1f974ac3305186ae34b9ce423525d0)
* Decrement socket-related statistics counters.
*/
+isc_result_t
+isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp);
+/*%<
+ * Platform independent socket() version
+ */
+
isc_result_t
isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family);
/*%<
#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/condition.h>
+#include <isc/errno.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
#include <isc/stats.h>
+#include <isc/strerr.h>
#include <isc/thread.h>
#include <isc/util.h>
}
}
+isc_result_t
+isc__nm_socket(int domain, int type, int protocol, uv_os_sock_t *sockp) {
+#ifdef WIN32
+ SOCKET sock;
+ sock = socket(domain, type, protocol);
+ if (sock == INVALID_SOCKET) {
+ char strbuf[ISC_STRERRORSIZE];
+ DWORD socket_errno = WSAGetLastError();
+ switch (socket_errno) {
+ case WSAEMFILE:
+ case WSAENOBUFS:
+ return (ISC_R_NORESOURCES);
+
+ case WSAEPROTONOSUPPORT:
+ case WSAEPFNOSUPPORT:
+ case WSAEAFNOSUPPORT:
+ return (ISC_R_FAMILYNOSUPPORT);
+ default:
+ strerror_r(socket_errno, strbuf, sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "socket() failed: %s", strbuf);
+ return (ISC_R_UNEXPECTED);
+ }
+ }
+#else
+ int sock = socket(domain, type, protocol);
+ if (sock < 0) {
+ return (isc_errno_toresult(errno));
+ }
+#endif
+ *sockp = (uv_os_sock_t)sock;
+ return (ISC_R_SUCCESS);
+}
+
#define setsockopt_on(socket, level, name) \
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
INSIST(csock->recv_cb == NULL && csock->recv_cbarg == NULL);
csock->recv_cb = cb;
csock->recv_cbarg = cbarg;
- csock->fd = socket(family, SOCK_DGRAM, 0);
- RUNTIME_CHECK(csock->fd >= 0);
+ result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &csock->fd);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = isc__nm_socket_reuse(csock->fd);
RUNTIME_CHECK(result == ISC_R_SUCCESS ||
isc__netievent_udpconnect_t *event = NULL;
isc__nm_uvreq_t *req = NULL;
sa_family_t sa_family;
+ uv_os_sock_t fd;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
sa_family = peer->addr.type.sa.sa_family;
+ /*
+ * The socket() call can fail spuriously on FreeBSD 12, so we need to
+ * handle the failure early and gracefully.
+ */
+ result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &fd);
+ if (result != ISC_R_SUCCESS) {
+ return (result);
+ }
+
sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(sock, mgr, isc_nm_udpsocket, local);
sock->read_timeout = timeout;
sock->extrahandlesize = extrahandlesize;
sock->peer = peer->addr;
+ sock->fd = fd;
atomic_init(&sock->client, true);
- sock->fd = socket(sa_family, SOCK_DGRAM, 0);
- RUNTIME_CHECK(sock->fd >= 0);
-
result = isc__nm_socket_reuse(sock->fd);
RUNTIME_CHECK(result == ISC_R_SUCCESS ||
result == ISC_R_NOTIMPLEMENTED);