Erich Hoover : ws2_32: Permit broadcast packets on interface-bound sockets for systems with IP_BOUND_IF .

Alexandre Julliard julliard at winehq.org
Tue Oct 2 14:09:39 CDT 2012


Module: wine
Branch: master
Commit: 9f2f7600c5d79e243b6cd670c1506e273add99c6
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=9f2f7600c5d79e243b6cd670c1506e273add99c6

Author: Erich Hoover <ehoover at 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)
                 {




More information about the wine-cvs mailing list