* 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.
This commit is contained in:
parent
0ca697dde1
commit
0ee535ccb1
|
@ -501,6 +501,7 @@ LoadDLLfuncEx (GetIfTable, 12, iphlpapi, 1)
|
||||||
LoadDLLfuncEx (GetIfEntry, 4, iphlpapi, 1)
|
LoadDLLfuncEx (GetIfEntry, 4, iphlpapi, 1)
|
||||||
LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1)
|
LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1)
|
||||||
LoadDLLfuncEx (GetNetworkParams, 8, iphlpapi, 1)
|
LoadDLLfuncEx (GetNetworkParams, 8, iphlpapi, 1)
|
||||||
|
LoadDLLfuncEx (GetTcpTable, 12, iphlpapi, 1)
|
||||||
|
|
||||||
LoadDLLfunc (CoTaskMemFree, 4, ole32)
|
LoadDLLfunc (CoTaskMemFree, 4, ole32)
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#define USE_SYS_TYPES_FD_SET
|
#define USE_SYS_TYPES_FD_SET
|
||||||
|
@ -580,6 +581,29 @@ fhandler_socket::link (const char *newpath)
|
||||||
return fhandler_base::link (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
|
int
|
||||||
fhandler_socket::bind (const struct sockaddr *name, int namelen)
|
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);
|
debug_printf ("%d = setsockopt (SO_EXCLUSIVEADDRUSE), %E", ret);
|
||||||
}
|
}
|
||||||
else
|
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))
|
if (::bind (get_socket (), name, namelen))
|
||||||
set_winsock_errno ();
|
set_winsock_errno ();
|
||||||
|
|
Loading…
Reference in New Issue