Module: wine
Branch: master
Commit: 9f2f7600c5d79e243b6cd670c1506e273add99c6
URL: http://source.winehq.org/git/wine.git/?a=commit;h=9f2f7600c5d79e243b6cd670c…
Author: Erich Hoover <ehoover(a)mines.edu>
Date: Wed Sep 26 16:38:09 2012 -0600
ws2_32: Permit broadcast packets on interface-bound sockets for systems with IP_BOUND_IF.
---
dlls/ws2_32/socket.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 64 insertions(+), 0 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 7b86ca4..d645872 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2107,6 +2107,68 @@ static int WINAPI WS2_WSARecvMsg( SOCKET s, LPWSAMSG msg, LPDWORD lpNumberOfByte
}
/***********************************************************************
+ * interface_bind (INTERNAL)
+ *
+ * Take bind() calls on any name corresponding to a local network adapter and restrict the given socket to
+ * operating only on the specified interface. This restriction consists of two components:
+ * 1) An outgoing packet restriction suggesting the egress interface for all packets.
+ * 2) An incoming packet restriction dropping packets not meant for the interface.
+ * If the function succeeds in placing these restrictions (returns TRUE) then the name for the bind() may
+ * safely be changed to INADDR_ANY, permitting the transmission and receipt of broadcast packets on the
+ * socket. This behavior is only relevant to UDP sockets and is needed for applications that expect to be able
+ * to receive broadcast packets on a socket that is bound to a specific network interface.
+ */
+static BOOL interface_bind( SOCKET s, int fd, struct sockaddr *addr )
+{
+ struct sockaddr_in *in_sock = (struct sockaddr_in *) addr;
+ unsigned int sock_type = 0, optlen = sizeof(sock_type);
+ PIP_ADAPTER_INFO adapters = NULL, adapter;
+ BOOL ret = FALSE;
+ DWORD adap_size;
+ int enable = 1;
+
+ if (in_sock->sin_addr.s_addr == htonl(WS_INADDR_ANY))
+ return FALSE; /* Not binding to specific interface, uses default route */
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen) == -1 || sock_type != SOCK_DGRAM)
+ return FALSE; /* Special interface binding is only necessary for UDP datagrams. */
+ if (GetAdaptersInfo(NULL, &adap_size) != ERROR_BUFFER_OVERFLOW)
+ goto cleanup;
+ adapters = HeapAlloc(GetProcessHeap(), 0, adap_size);
+ if (adapters == NULL || GetAdaptersInfo(adapters, &adap_size) != NO_ERROR)
+ goto cleanup;
+ /* Search the IPv4 adapter list for the appropriate binding interface */
+ for (adapter = adapters; adapter != NULL; adapter = adapter->Next)
+ {
+ in_addr_t adapter_addr = (in_addr_t) inet_addr(adapter->IpAddressList.IpAddress.String);
+
+ if (in_sock->sin_addr.s_addr == adapter_addr)
+ {
+#if defined(IP_BOUND_IF)
+ /* IP_BOUND_IF sets both the incoming and outgoing restriction at once */
+ if (setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &adapter->Index, sizeof(adapter->Index)) != 0)
+ goto cleanup;
+ ret = TRUE;
+#else
+ FIXME("Broadcast packets on interface-bound sockets are not currently supported on this platform, "
+ "receiving broadcast packets will not work on socket %04lx.\n", s);
+#endif
+ break;
+ }
+ }
+ /* Will soon be switching to INADDR_ANY: permit address reuse */
+ if (ret && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == 0)
+ TRACE("Socket %04lx bound to interface index %d\n", s, adapter->Index);
+ else
+ ret = FALSE;
+
+cleanup:
+ if(!ret)
+ ERR("Failed to bind to interface, receiving broadcast packets will not work on socket %04lx.\n", s);
+ HeapFree(GetProcessHeap(), 0, adapters);
+ return ret;
+}
+
+/***********************************************************************
* bind (WS2_32.2)
*/
int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
@@ -2157,6 +2219,8 @@ int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
"INADDR_ANY instead.\n");
in4->sin_addr.s_addr = htonl(WS_INADDR_ANY);
}
+ else if (interface_bind(s, fd, &uaddr.addr))
+ in4->sin_addr.s_addr = htonl(WS_INADDR_ANY);
}
if (bind(fd, &uaddr.addr, uaddrlen) < 0)
{