Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2006-02-01 14:10:53 +0300
committerCorinna Vinschen <corinna@vinschen.de>2006-02-01 14:10:53 +0300
commit0ee535ccb1e10e36bc6c311f56a8f9f279fc564f (patch)
tree016bbe2bb08e679755169a32ae9ee569e2e86c59 /winsup/cygwin
parent0ca697dde15f39c123f01d8ff1cc17720fb8451c (diff)
* autoload.cc (GetTcpTable): Define.
* fhandler_socket.cc (address_in_use): New function to check if sockaddr_in address is already in use. (fhandler_socket::bind): Check if address is alreay in use in case of SO_REUSEADDR, to circumvent WinSock non-standard behaviour.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/autoload.cc1
-rw-r--r--winsup/cygwin/fhandler_socket.cc43
2 files changed, 43 insertions, 1 deletions
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 333bff56d..548b4ab13 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -501,6 +501,7 @@ LoadDLLfuncEx (GetIfTable, 12, iphlpapi, 1)
LoadDLLfuncEx (GetIfEntry, 4, iphlpapi, 1)
LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1)
LoadDLLfuncEx (GetNetworkParams, 8, iphlpapi, 1)
+LoadDLLfuncEx (GetTcpTable, 12, iphlpapi, 1)
LoadDLLfunc (CoTaskMemFree, 4, ole32)
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index b885b97db..59c61c81d 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -17,6 +17,7 @@
#include <sys/un.h>
#include <sys/uio.h>
#include <asm/byteorder.h>
+#include <iphlpapi.h>
#include <stdlib.h>
#define USE_SYS_TYPES_FD_SET
@@ -580,6 +581,29 @@ fhandler_socket::link (const char *newpath)
return fhandler_base::link (newpath);
}
+static inline bool
+address_in_use (struct sockaddr_in *addr)
+{
+ PMIB_TCPTABLE tab;
+ PMIB_TCPROW entry;
+ DWORD size = 0, i;
+
+ if (GetTcpTable (NULL, &size, FALSE) == ERROR_INSUFFICIENT_BUFFER)
+ {
+ tab = (PMIB_TCPTABLE) alloca (size);
+ if (!GetTcpTable (tab, &size, FALSE))
+ {
+ for (i = tab->dwNumEntries, entry = tab->table; i > 0; --i, ++entry)
+ if (entry->dwLocalAddr == addr->sin_addr.s_addr
+ && entry->dwLocalPort == addr->sin_port
+ && entry->dwState >= MIB_TCP_STATE_LISTEN
+ && entry->dwState <= MIB_TCP_STATE_LAST_ACK)
+ return true;
+ }
+ }
+ return false;
+}
+
int
fhandler_socket::bind (const struct sockaddr *name, int namelen)
{
@@ -681,7 +705,24 @@ fhandler_socket::bind (const struct sockaddr *name, int namelen)
debug_printf ("%d = setsockopt (SO_EXCLUSIVEADDRUSE), %E", ret);
}
else
- debug_printf ("SO_REUSEADDR set");
+ {
+ debug_printf ("SO_REUSEADDR set");
+ /* There's a bug in SO_REUSEADDR handling in WinSock.
+ Per standards, we must not be able to reuse a complete
+ duplicate of a local TCP address (same IP, same port),
+ even if SO_REUSEADDR has been set. That's unfortunately
+ possible in WinSock. So we're testing here if the local
+ address is already in use and don't bind, if so. This
+ only works for OSes with IP Helper support. */
+ if (get_socket_type () == SOCK_STREAM
+ && wincap.has_ip_helper_lib ()
+ && address_in_use ((struct sockaddr_in *) name))
+ {
+ debug_printf ("Local address in use, don't bind");
+ set_errno (EADDRINUSE);
+ goto out;
+ }
+ }
}
if (::bind (get_socket (), name, namelen))
set_winsock_errno ();