mirror of
https://github.com/zeromq/libzmq.git
synced 2025-03-20 18:48:16 +00:00
Implemented network interface name resolution on Windows platform
Added fallback mechanism for specific socket binding on Windows platform with IPv6 enabled
This commit is contained in:
parent
3996d4e20d
commit
f6962903a7
@ -235,10 +235,141 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif (defined ZMQ_HAVE_WINDOWS)
|
||||||
|
|
||||||
|
int zmq::tcp_address_t::get_interface_name(unsigned long index, char ** dest) const {
|
||||||
|
char * buffer = (char*)malloc(IF_MAX_STRING_SIZE);
|
||||||
|
alloc_assert(buffer);
|
||||||
|
|
||||||
|
char * if_name_result = NULL;
|
||||||
|
|
||||||
|
if_name_result = if_indextoname(index, buffer);
|
||||||
|
|
||||||
|
if (if_name_result == NULL) {
|
||||||
|
free(buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = buffer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmq::tcp_address_t::wchar_to_utf8(const WCHAR * src, char ** dest) const {
|
||||||
|
int rc;
|
||||||
|
int buffer_len = WideCharToMultiByte(CP_UTF8, 0,
|
||||||
|
src, -1,
|
||||||
|
NULL, 0,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
char * buffer = (char*) malloc(buffer_len);
|
||||||
|
alloc_assert(buffer);
|
||||||
|
|
||||||
|
rc = WideCharToMultiByte(CP_UTF8, 0,
|
||||||
|
src, -1,
|
||||||
|
buffer, buffer_len,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
free(buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = buffer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmq::tcp_address_t::resolve_nic_name(const char *nic_, bool ipv6_, bool is_src_)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
bool found = false;
|
||||||
|
const int max_attempts = 10;
|
||||||
|
|
||||||
|
int iterations = 0;
|
||||||
|
IP_ADAPTER_ADDRESSES * addresses = NULL;
|
||||||
|
IP_ADAPTER_ADDRESSES * current_addresses = NULL;
|
||||||
|
unsigned long out_buf_len = sizeof(IP_ADAPTER_ADDRESSES);
|
||||||
|
|
||||||
|
do {
|
||||||
|
addresses = (IP_ADAPTER_ADDRESSES *) malloc(out_buf_len);
|
||||||
|
alloc_assert(addresses);
|
||||||
|
|
||||||
|
rc = GetAdaptersAddresses(AF_UNSPEC,
|
||||||
|
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER,
|
||||||
|
NULL,
|
||||||
|
addresses, &out_buf_len);
|
||||||
|
if (rc == ERROR_BUFFER_OVERFLOW) {
|
||||||
|
free(addresses);
|
||||||
|
addresses = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iterations++;
|
||||||
|
} while ((rc == ERROR_BUFFER_OVERFLOW) && (iterations < max_attempts));
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
current_addresses = addresses;
|
||||||
|
while (current_addresses) {
|
||||||
|
char * if_name = NULL;
|
||||||
|
char * if_friendly_name = NULL;
|
||||||
|
int str_rc1, str_rc2;
|
||||||
|
|
||||||
|
str_rc1 = get_interface_name(current_addresses->IfIndex, &if_name);
|
||||||
|
str_rc2 = wchar_to_utf8(current_addresses->FriendlyName, &if_friendly_name);
|
||||||
|
|
||||||
|
// Find a network adapter by its "name" or "friendly name"
|
||||||
|
if (
|
||||||
|
((str_rc1 == 0) && (!strcmp(nic_, if_name)))
|
||||||
|
|| ((str_rc2 == 0) && (!strcmp(nic_, if_friendly_name)))
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Iterate over all unicast addresses bound to the current network interface
|
||||||
|
IP_ADAPTER_UNICAST_ADDRESS_LH * unicast_address = current_addresses->FirstUnicastAddress;
|
||||||
|
IP_ADAPTER_UNICAST_ADDRESS_LH * current_unicast_address = unicast_address;
|
||||||
|
|
||||||
|
while (current_unicast_address) {
|
||||||
|
ADDRESS_FAMILY family = current_unicast_address->Address.lpSockaddr->sa_family;
|
||||||
|
|
||||||
|
if (family == AF_INET ||
|
||||||
|
(ipv6_ && family == AF_INET6)
|
||||||
|
) {
|
||||||
|
if (is_src_)
|
||||||
|
memcpy(&source_address, current_unicast_address->Address.lpSockaddr,
|
||||||
|
(family == AF_INET) ? sizeof(struct sockaddr_in)
|
||||||
|
: sizeof(struct sockaddr_in6));
|
||||||
|
else
|
||||||
|
memcpy(&address, current_unicast_address->Address.lpSockaddr,
|
||||||
|
(family == AF_INET) ? sizeof(struct sockaddr_in)
|
||||||
|
: sizeof(struct sockaddr_in6));
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_unicast_address = current_unicast_address->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_rc1 == 0) free(if_name);
|
||||||
|
if (str_rc2 == 0) free(if_friendly_name);
|
||||||
|
|
||||||
|
current_addresses = current_addresses->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
errno = ENODEV;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// On other platforms we assume there are no sane interface names.
|
// On other platforms we assume there are no sane interface names.
|
||||||
// This is true especially of Windows.
|
|
||||||
int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_src_)
|
int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_src_)
|
||||||
{
|
{
|
||||||
LIBZMQ_UNUSED (nic_);
|
LIBZMQ_UNUSED (nic_);
|
||||||
@ -323,7 +454,18 @@ int zmq::tcp_address_t::resolve_interface (const char *interface_, bool ipv6_, b
|
|||||||
|
|
||||||
// Resolve the literal address. Some of the error info is lost in case
|
// Resolve the literal address. Some of the error info is lost in case
|
||||||
// of error, however, there's no way to report EAI errors via errno.
|
// of error, however, there's no way to report EAI errors via errno.
|
||||||
rc = getaddrinfo (interface_, NULL, &req, &res);
|
|
||||||
|
rc = getaddrinfo(interface_, NULL, &req, &res);
|
||||||
|
|
||||||
|
#if defined ZMQ_HAVE_WINDOWS
|
||||||
|
// Resolve specific case on Windows platform when using IPv4 address
|
||||||
|
// with ZMQ_IPv6 socket option.
|
||||||
|
if ((req.ai_family = AF_INET6) && (rc == WSAHOST_NOT_FOUND)) {
|
||||||
|
req.ai_family = AF_INET;
|
||||||
|
rc = getaddrinfo(interface_, NULL, &req, &res);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -72,6 +72,11 @@ namespace zmq
|
|||||||
int resolve_interface (const char *interface_, bool ipv6_, bool is_src_ = false);
|
int resolve_interface (const char *interface_, bool ipv6_, bool is_src_ = false);
|
||||||
int resolve_hostname (const char *hostname_, bool ipv6_, bool is_src_ = false);
|
int resolve_hostname (const char *hostname_, bool ipv6_, bool is_src_ = false);
|
||||||
|
|
||||||
|
#if defined ZMQ_HAVE_WINDOWS
|
||||||
|
int get_interface_name(unsigned long index, char ** dest) const;
|
||||||
|
int wchar_to_utf8(const WCHAR * src, char ** dest) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
union {
|
union {
|
||||||
sockaddr generic;
|
sockaddr generic;
|
||||||
sockaddr_in ipv4;
|
sockaddr_in ipv4;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user