ws2_32: Restore the local socket address that was bound with filter for getsockname().
This commit is contained in:
parent
dcfde9a9df
commit
61ed82fc86
@ -3218,6 +3218,61 @@ int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen)
|
|||||||
return res;
|
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)
|
* getsockname (WS2_32.6)
|
||||||
*/
|
*/
|
||||||
@ -3255,8 +3310,17 @@ int WINAPI WS_getsockname(SOCKET s, struct WS_sockaddr *name, int *namelen)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = 0;
|
interface_bind_check(fd, (struct sockaddr_in*) &uaddr);
|
||||||
TRACE("=> %s\n", debugstr_sockaddr(name));
|
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 );
|
release_sock_fd( s, fd );
|
||||||
}
|
}
|
||||||
|
@ -4238,7 +4238,6 @@ static void test_getsockname(void)
|
|||||||
ok(ret == 0, "getsockname failed with %d\n", GetLastError());
|
ok(ret == 0, "getsockname failed with %d\n", GetLastError());
|
||||||
strcpy(ipstr, inet_ntoa(sa_get.sin_addr));
|
strcpy(ipstr, inet_ntoa(sa_get.sin_addr));
|
||||||
trace("testing bind on interface %s\n", ipstr);
|
trace("testing bind on interface %s\n", ipstr);
|
||||||
todo_wine
|
|
||||||
ok(sa_get.sin_addr.s_addr == sa_set.sin_addr.s_addr,
|
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));
|
"address does not match: %s != %s", ipstr, inet_ntoa(sa_set.sin_addr));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user