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