summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-04-10 23:48:14 -0700
committerGarrett D'Amore <garrett@damore.org>2018-04-11 00:12:22 -0700
commit19e01dcaf1afda031143ae171d8eeadd0c49fee1 (patch)
tree8f4b29790a55e7303447f965743b6476b6c93dc7
parent83585e2cfa1053b705f8592e6bbceb04cfeef028 (diff)
downloadnanomsg-19e01dcaf1afda031143ae171d8eeadd0c49fee1.tar.gz
fixes #957 nanomsg always uses port 5907 for setting up event fds (Windows only)fix957
-rw-r--r--src/utils/efd_win.inc157
1 files changed, 42 insertions, 115 deletions
diff --git a/src/utils/efd_win.inc b/src/utils/efd_win.inc
index 20e3e3f..b6b4b55 100644
--- a/src/utils/efd_win.inc
+++ b/src/utils/efd_win.inc
@@ -1,7 +1,8 @@
/*
Copyright (c) 2012-2013 Martin Sustrik All rights reserved.
Copyright 2017 Garrett D'Amore <garrett@damore.org>
- Copyright 2017 Capitar IT Group BV <info@capitar.com>
+ Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+ Copyright 2018 Capitar IT Group BV <info@capitar.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -34,50 +35,15 @@
int nn_efd_init (struct nn_efd *self)
{
- SECURITY_ATTRIBUTES sa = {0};
- SECURITY_DESCRIPTOR sd;
- BOOL brc;
- HANDLE sync;
- DWORD dwrc;
SOCKET listener;
int rc;
struct sockaddr_in addr;
- int addrlen;
- BOOL reuseaddr;
+ socklen_t addrlen;
+ int one;
BOOL nodelay;
u_long nonblock;
int i;
- /* Make the following critical section accessible to everyone. */
- sa.nLength = sizeof (sa);
- sa.bInheritHandle = FALSE;
- brc = InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
- win_assert (brc);
- brc = SetSecurityDescriptorDacl(&sd, TRUE, (PACL) NULL, FALSE);
- win_assert (brc);
- sa.lpSecurityDescriptor = &sd;
-
- /* This function has to be enclosed in a system-wide critical section
- so that two instances of the library don't accidentally create an efd
- crossing the process boundary. */
- sync = CreateMutex (&sa, FALSE, "Global\\nanomsg-port-mutex");
- win_assert (sync != NULL);
-
- /* Enter the critical section. If we cannot get the object in 10 seconds
- then something is seriously wrong. Just bail. */
- dwrc = WaitForSingleObject (sync, 10000);
- switch (dwrc) {
- case WAIT_ABANDONED:
- case WAIT_OBJECT_0:
- break;
- case WAIT_TIMEOUT:
- rc = ETIMEDOUT;
- goto wsafail3;
- default:
- rc = nn_err_wsa_to_posix (WSAGetLastError ());
- goto wsafail3;
- }
-
/* Unfortunately, on Windows the only way to send signal to a file
descriptor (SOCKET) is to create a full-blown TCP connecting on top of
the loopback interface. */
@@ -86,102 +52,69 @@ int nn_efd_init (struct nn_efd *self)
/* Create listening socket. */
listener = socket (AF_INET, SOCK_STREAM, 0);
- if (nn_slow (listener == SOCKET_ERROR))
+ if (listener == SOCKET_ERROR)
goto wsafail;
- brc = SetHandleInformation ((HANDLE) listener, HANDLE_FLAG_INHERIT, 0);
- win_assert (brc);
-
- /* This prevents subsequent attempts to create a signaler to fail bacause
- of "TCP port in use" problem. */
- reuseaddr = 1;
- rc = setsockopt (listener, SOL_SOCKET, SO_REUSEADDR,
- (char*) &reuseaddr, sizeof (reuseaddr));
- if (nn_slow (rc == SOCKET_ERROR))
+
+ one = 1;
+ rc = setsockopt (listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
+ (char*) &one, sizeof (one));
+ if (rc == SOCKET_ERROR)
goto wsafail;
/* Bind the listening socket to the local port. */
memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- addr.sin_port = htons (NN_EFD_PORT);
+ addr.sin_port = 0;
+
rc = bind (listener, (const struct sockaddr*) &addr, sizeof (addr));
- if (nn_slow (rc == SOCKET_ERROR))
+ if (rc == SOCKET_ERROR)
+ goto wsafail;
+
+ /* Get the port we bound to (will be ephemeral.) */
+ addrlen = sizeof (addr);
+ rc = getsockname (listener, (struct sockaddr *) &addr, &addrlen);
+ if (rc == SOCKET_ERROR)
goto wsafail;
/* Start listening for the incomming connections. In normal case we are
going to accept just a single connection, so backlog buffer of size
1 is sufficient. */
rc = listen (listener, 1);
- if (nn_slow (rc == SOCKET_ERROR))
+ if (rc == SOCKET_ERROR)
goto wsafail;
/* The following code is in the loop, because windows sometimes delays
WSAEADDRINUSE error to the `connect` call. But retrying the connection
works like a charm. Still we want to limit number of retries */
- for(i = 0; i < NN_EFD_RETRIES; ++i) {
-
- /* Create the writer socket. */
- self->w = socket (AF_INET, SOCK_STREAM, 0);
- if (nn_slow (listener == SOCKET_ERROR))
- goto wsafail;
- brc = SetHandleInformation ((HANDLE) self->w, HANDLE_FLAG_INHERIT, 0);
- win_assert (brc);
-
- /* Set TCP_NODELAY on the writer socket to make efd as fast as possible.
- There's only one byte going to be written, so batching would not make
- sense anyway. */
- nodelay = 1;
- rc = setsockopt (self->w, IPPROTO_TCP, TCP_NODELAY, (char*) &nodelay,
- sizeof (nodelay));
- if (nn_slow (rc == SOCKET_ERROR))
- goto wsafail;
-
- /* Connect the writer socket to the listener socket. */
- rc = connect (self->w, (struct sockaddr*) &addr, sizeof (addr));
- if (nn_slow (rc == SOCKET_ERROR)) {
- rc = nn_err_wsa_to_posix (WSAGetLastError ());
- if (rc == EADDRINUSE) {
- rc = closesocket (self->w);
- if (nn_slow (rc == INVALID_SOCKET))
- goto wsafail;
- continue;
- }
- goto wsafail2;
- }
- break;
- }
- if (i == NN_EFD_RETRIES)
- goto wsafail2;
-
- for (;;) {
- /* Accept new incoming connection. */
- addrlen = sizeof (addr);
- self->r = accept (listener, (struct sockaddr*) &addr, &addrlen);
- if (nn_slow (self->r == INVALID_SOCKET || addrlen != sizeof (addr)))
- goto wsafail2;
+ /* Create the writer socket. */
+ self->w = socket (AF_INET, SOCK_STREAM, 0);
+ if (listener == SOCKET_ERROR)
+ goto wsafail;
- /* Check that the connection actually comes from the localhost. */
- if (nn_fast (addr.sin_addr.s_addr == htonl (INADDR_LOOPBACK)))
- break;
+ /* Set TCP_NODELAY on the writer socket to make efd as fast as possible.
+ There's only one byte going to be written, so batching would not make
+ sense anyway. */
+ nodelay = 1;
+ rc = setsockopt (self->w, IPPROTO_TCP, TCP_NODELAY, (char*) &nodelay,
+ sizeof (nodelay));
+ if (nn_slow (rc == SOCKET_ERROR))
+ goto wsafail;
- /* If not so, close the connection and try again. */
- rc = closesocket (self->r);
- if (nn_slow (rc == INVALID_SOCKET))
- goto wsafail;
- }
+ /* Connect the writer socket to the listener socket. */
+ rc = connect (self->w, (struct sockaddr*) &addr, sizeof (addr));
+ if (rc == SOCKET_ERROR)
+ goto wsafail;
- /* Listener socket can be closed now as no more connections for this efd
- are going to be established anyway. */
- rc = closesocket (listener);
- if (nn_slow (rc == INVALID_SOCKET))
+ /* Accept new incoming connection. */
+ addrlen = sizeof (addr);
+ self->r = accept (listener, (struct sockaddr*) &addr, &addrlen);
+ if (self->r == INVALID_SOCKET)
goto wsafail;
- /* Leave the critical section. */
- brc = ReleaseMutex (sync);
- win_assert (brc != 0);
- brc = CloseHandle (sync);
- win_assert (brc != 0);
+ /* Close the listener, we don't need it anymore. */
+ (void) closesocket (listener);
/* Make the receiving socket non-blocking. */
nonblock = 1;
@@ -192,12 +125,6 @@ int nn_efd_init (struct nn_efd *self)
wsafail:
rc = nn_err_wsa_to_posix (WSAGetLastError ());
-wsafail2:
- brc = ReleaseMutex (sync);
- win_assert (brc != 0);
-wsafail3:
- brc = CloseHandle (sync);
- win_assert (brc != 0);
return -rc;
}