diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2006-02-01 14:10:53 +0300 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2006-02-01 14:10:53 +0300 |
commit | 0ee535ccb1e10e36bc6c311f56a8f9f279fc564f (patch) | |
tree | 016bbe2bb08e679755169a32ae9ee569e2e86c59 /winsup | |
parent | 0ca697dde15f39c123f01d8ff1cc17720fb8451c (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')
-rw-r--r-- | winsup/cygwin/autoload.cc | 1 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_socket.cc | 43 |
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 (); |