mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-13 15:56:23 +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;
|
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
|
static gboolean
|
||||||
g_socket_multicast_group_operation (GSocket *socket,
|
g_socket_multicast_group_operation (GSocket *socket,
|
||||||
GInetAddress *group,
|
GInetAddress *group,
|
||||||
@ -2199,7 +2315,7 @@ g_socket_multicast_group_operation (GSocket *socket,
|
|||||||
mc_req.imr_ifindex = 0; /* Pick any. */
|
mc_req.imr_ifindex = 0; /* Pick any. */
|
||||||
#elif defined(G_OS_WIN32)
|
#elif defined(G_OS_WIN32)
|
||||||
if (iface)
|
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
|
else
|
||||||
mc_req.imr_interface.s_addr = g_htonl (INADDR_ANY);
|
mc_req.imr_interface.s_addr = g_htonl (INADDR_ANY);
|
||||||
#else
|
#else
|
||||||
@ -2398,18 +2514,8 @@ g_socket_multicast_group_operation_ssm (GSocket *socket,
|
|||||||
|
|
||||||
if (iface)
|
if (iface)
|
||||||
{
|
{
|
||||||
#if defined(G_OS_WIN32) && defined (HAVE_IF_NAMETOINDEX)
|
#if defined(G_OS_WIN32)
|
||||||
guint iface_index = if_nametoindex (iface);
|
S_ADDR_FIELD(mc_req_src) = g_socket_w32_get_adapter_ipv4_addr (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);
|
|
||||||
#elif defined (HAVE_SIOCGIFADDR)
|
#elif defined (HAVE_SIOCGIFADDR)
|
||||||
int ret;
|
int ret;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
Loading…
Reference in New Issue
Block a user