Bruno Jesus : ws2_32: Restore the local socket address that was bound with filter for getsockname ().

Alexandre Julliard julliard at wine.codeweavers.com
Thu Apr 9 11:07:40 CDT 2015


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

Author: Bruno Jesus <00cpxxx at gmail.com>
Date:   Thu Apr  9 00:09:29 2015 -0300

ws2_32: Restore the local socket address that was bound with filter for getsockname().

---

 dlls/ws2_32/socket.c     | 68 ++++++++++++++++++++++++++++++++++++++++++++++--
 dlls/ws2_32/tests/sock.c |  1 -
 2 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 6903909..bfcc755 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -3218,6 +3218,61 @@ int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen)
     return res;
 }
 
+/* When binding to an UDP address with filter support the getsockname call on the socket
+ * will always return 0.0.0.0 instead of the filtered interface address. This function
+ * checks if the socket is interface-bound on UDP and return the correct address.
+ * This is required because applications often do a bind() with port zero followed by a
+ * getsockname() to retrieve the port and address acquired.
+ */
+static void interface_bind_check(int fd, struct sockaddr_in *addr)
+{
+#if !defined(IP_BOUND_IF) && !defined(LINUX_BOUND_IF)
+    return;
+#else
+    int ifindex;
+    socklen_t len = sizeof(ifindex);
+
+    /* Check for IPv4, address 0.0.0.0 and UDP socket */
+    if (addr->sin_family != AF_INET || addr->sin_addr.s_addr != 0)
+        return;
+    if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &ifindex, &len) || ifindex != SOCK_DGRAM)
+        return;
+
+    ifindex = -1;
+    len = sizeof(ifindex);
+#if defined(IP_BOUND_IF)
+    getsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &ifindex, &len);
+#elif defined(LINUX_BOUND_IF)
+    getsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, &len);
+    if (ifindex > 0) ifindex = ntohl(ifindex);
+#endif
+    if (ifindex > 0)
+    {
+        PIP_ADAPTER_INFO adapters, adapter;
+        DWORD adap_size;
+
+        if (GetAdaptersInfo(NULL, &adap_size) != ERROR_BUFFER_OVERFLOW)
+            return;
+        adapters = HeapAlloc(GetProcessHeap(), 0, adap_size);
+        if (adapters && GetAdaptersInfo(adapters, &adap_size) == NO_ERROR)
+        {
+            /* Search the IPv4 adapter list for the appropriate bound interface */
+            for (adapter = adapters; adapter != NULL; adapter = adapter->Next)
+            {
+                in_addr_t adapter_addr;
+                if (adapter->Index != ifindex) continue;
+
+                adapter_addr = inet_addr(adapter->IpAddressList.IpAddress.String);
+                addr->sin_addr.s_addr = adapter_addr;
+                TRACE("reporting interface address from adapter %d\n", ifindex);
+                break;
+            }
+        }
+        HeapFree(GetProcessHeap(), 0, adapters);
+    }
+#endif
+}
+
 /***********************************************************************
  *		getsockname		(WS2_32.6)
  */
@@ -3255,8 +3310,17 @@ int WINAPI WS_getsockname(SOCKET s, struct WS_sockaddr *name, int *namelen)
         }
         else
         {
-            res = 0;
-            TRACE("=> %s\n", debugstr_sockaddr(name));
+            interface_bind_check(fd, (struct sockaddr_in*) &uaddr);
+            if (ws_sockaddr_u2ws(&uaddr.addr, name, namelen) != 0)
+            {
+                /* The buffer was too small */
+                SetLastError(WSAEFAULT);
+            }
+            else
+            {
+                res = 0;
+                TRACE("=> %s\n", debugstr_sockaddr(name));
+            }
         }
         release_sock_fd( s, fd );
     }
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 8690579..8b69cf6 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -4238,7 +4238,6 @@ static void test_getsockname(void)
             ok(ret == 0, "getsockname failed with %d\n", GetLastError());
             strcpy(ipstr, inet_ntoa(sa_get.sin_addr));
             trace("testing bind on interface %s\n", ipstr);
-todo_wine
             ok(sa_get.sin_addr.s_addr == sa_set.sin_addr.s_addr,
                "address does not match: %s != %s", ipstr, inet_ntoa(sa_set.sin_addr));
 




More information about the wine-cvs mailing list