mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-13 07:56:17 +01:00
Merge branch 'master' into 'master'
windows: fix multicast socket binding to specific network interfaces Closes #1635 See merge request GNOME/glib!887
This commit is contained in:
commit
8f385b8cf5
132
gio/gsocket.c
132
gio/gsocket.c
@ -2162,6 +2162,122 @@ g_socket_bind (GSocket *socket,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
static gulong
|
||||
g_socket_w32_get_adapter_ipv4_addr (const gchar *name_or_ip)
|
||||
{
|
||||
ULONG bufsize = 15000; /* MS-recommended initial bufsize */
|
||||
DWORD ret = ERROR_BUFFER_OVERFLOW;
|
||||
unsigned int malloc_iterations = 0;
|
||||
PIP_ADAPTER_ADDRESSES addr_buf = NULL, eth_adapter;
|
||||
wchar_t *wchar_name_or_ip = NULL;
|
||||
gulong ip_result;
|
||||
NET_IFINDEX if_index;
|
||||
|
||||
/*
|
||||
* For Windows OS only - return adapter IPv4 address in network byte order.
|
||||
*
|
||||
* Input string can be either friendly name of adapter, IP address of adapter,
|
||||
* indextoname, or fullname of adapter.
|
||||
* Example:
|
||||
* 192.168.1.109 ===> IP address given directly,
|
||||
* convert directly with inet_addr() function
|
||||
* Wi-Fi ===> Adapter friendly name "Wi-Fi",
|
||||
* scan with GetAdapterAddresses and adapter->FriendlyName
|
||||
* ethernet_32774 ===> Adapter name as returned by if_indextoname
|
||||
* {33E8F5CD-BAEA-4214-BE13-B79AB8080CAB} ===> Adaptername,
|
||||
* as returned in GetAdapterAddresses and adapter->AdapterName
|
||||
*/
|
||||
|
||||
/* Step 1: Check if string is an IP address: */
|
||||
ip_result = inet_addr (name_or_ip);
|
||||
if (ip_result != INADDR_NONE)
|
||||
return ip_result; /* Success, IP address string was given directly */
|
||||
|
||||
/*
|
||||
* Step 2: Check if name represents a valid Interface index (e.g. ethernet_75521)
|
||||
* function if_nametoindex will return >=1 if a valid index, or 0=no match
|
||||
* valid index will be used later in GetAdaptersAddress loop for lookup of adapter IP address
|
||||
*/
|
||||
if_index = if_nametoindex (name_or_ip);
|
||||
|
||||
/* Step 3: Prepare wchar string for friendly name comparision */
|
||||
if (if_index == 0)
|
||||
{
|
||||
size_t if_name_len = strlen (name_or_ip);
|
||||
if (if_name_len >= MAX_ADAPTER_NAME_LENGTH + 4)
|
||||
return INADDR_NONE;
|
||||
/* Name-check only needed if index=0... */
|
||||
wchar_name_or_ip = (wchar_t *) g_try_malloc ((if_name_len + 1) * sizeof(wchar_t));
|
||||
if (wchar_name_or_ip)
|
||||
mbstowcs (wchar_name_or_ip, name_or_ip, if_name_len + 1);
|
||||
/* NOTE: Even if malloc fails here, some comparisions can still be done later... so no exit here! */
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 4: Allocate memory and get adapter addresses.
|
||||
* Buffer allocation loop recommended by MS, since size can be dynamic
|
||||
* https://docs.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getadaptersaddresses
|
||||
*/
|
||||
#define MAX_ALLOC_ITERATIONS 3
|
||||
do
|
||||
{
|
||||
malloc_iterations++;
|
||||
addr_buf = (PIP_ADAPTER_ADDRESSES) g_try_realloc (addr_buf, bufsize);
|
||||
if (addr_buf)
|
||||
ret = GetAdaptersAddresses (AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addr_buf, &bufsize);
|
||||
}
|
||||
while (addr_buf &&
|
||||
ret == ERROR_BUFFER_OVERFLOW &&
|
||||
malloc_iterations < MAX_ALLOC_ITERATIONS);
|
||||
#undef MAX_ALLOC_ITERATIONS
|
||||
|
||||
if (addr_buf == 0 || ret != NO_ERROR)
|
||||
{
|
||||
g_free (addr_buf);
|
||||
g_free (wchar_name_or_ip);
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
/* Step 5: Loop through adapters and check match for index or name */
|
||||
for (eth_adapter = addr_buf; eth_adapter != NULL; eth_adapter = eth_adapter->Next)
|
||||
{
|
||||
/* Check if match for interface index/name: */
|
||||
gboolean any_match = (if_index > 0) && (eth_adapter->IfIndex == if_index);
|
||||
|
||||
/* Check if match for friendly name - but only if NO if_index! */
|
||||
if (!any_match && if_index == 0 && eth_adapter->FriendlyName &&
|
||||
eth_adapter->FriendlyName[0] != 0 && wchar_name_or_ip != NULL)
|
||||
any_match = (_wcsicmp (eth_adapter->FriendlyName, wchar_name_or_ip) == 0);
|
||||
|
||||
/* Check if match for adapter low level name - but only if NO if_index: */
|
||||
if (!any_match && if_index == 0 && eth_adapter->AdapterName &&
|
||||
eth_adapter->AdapterName[0] != 0)
|
||||
any_match = (stricmp (eth_adapter->AdapterName, name_or_ip) == 0);
|
||||
|
||||
if (any_match)
|
||||
{
|
||||
/* We have match for this adapter, lets get its local unicast IP address! */
|
||||
PIP_ADAPTER_UNICAST_ADDRESS uni_addr;
|
||||
for (uni_addr = eth_adapter->FirstUnicastAddress;
|
||||
uni_addr != NULL; uni_addr = uni_addr->Next)
|
||||
{
|
||||
if (uni_addr->Address.lpSockaddr->sa_family == AF_INET)
|
||||
{
|
||||
ip_result = ((PSOCKADDR_IN) uni_addr->Address.lpSockaddr)->sin_addr.S_un.S_addr;
|
||||
break; /* finished, exit unicast addr loop */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free (addr_buf);
|
||||
g_free (wchar_name_or_ip);
|
||||
|
||||
return ip_result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
g_socket_multicast_group_operation (GSocket *socket,
|
||||
GInetAddress *group,
|
||||
@ -2199,7 +2315,7 @@ g_socket_multicast_group_operation (GSocket *socket,
|
||||
mc_req.imr_ifindex = 0; /* Pick any. */
|
||||
#elif defined(G_OS_WIN32)
|
||||
if (iface)
|
||||
mc_req.imr_interface.s_addr = g_htonl (if_nametoindex (iface));
|
||||
mc_req.imr_interface.s_addr = g_socket_w32_get_adapter_ipv4_addr (iface);
|
||||
else
|
||||
mc_req.imr_interface.s_addr = g_htonl (INADDR_ANY);
|
||||
#else
|
||||
@ -2398,18 +2514,8 @@ g_socket_multicast_group_operation_ssm (GSocket *socket,
|
||||
|
||||
if (iface)
|
||||
{
|
||||
#if defined(G_OS_WIN32) && defined (HAVE_IF_NAMETOINDEX)
|
||||
guint iface_index = if_nametoindex (iface);
|
||||
if (iface_index == 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
|
||||
_("Interface not found: %s"), g_strerror (errsv));
|
||||
return FALSE;
|
||||
}
|
||||
/* (0.0.0.iface_index) only works on Windows. */
|
||||
S_ADDR_FIELD(mc_req_src) = g_htonl (iface_index);
|
||||
#if defined(G_OS_WIN32)
|
||||
S_ADDR_FIELD(mc_req_src) = g_socket_w32_get_adapter_ipv4_addr (iface);
|
||||
#elif defined (HAVE_SIOCGIFADDR)
|
||||
int ret;
|
||||
struct ifreq ifr;
|
||||
|
Loading…
Reference in New Issue
Block a user