diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 3fea708a8d3..435da10ae6b 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -271,6 +271,21 @@ API and :man:`inet_pton(3)`. On success they return 0. In case of error the target `dst` pointer is unmodified. +.. c:macro:: UV_IF_NAMESIZE + + Maximum IPv6 interface identifier name lenght. Defined as + `IFNAMSIZ` in Unix and `IF_NAMESIZE` in Linux and Windows. + + .. versionadded:: 1.14.0 + +.. c:function:: char* uv_if_indextoname(unsigned int ifindex, char* ifname) + + Cross-platform IPv6-capable implementation of :man:`if_indextoname(3)`. + Writes the result to `ifname`, which must be at least `UV_IF_NAMESIZE` long. + On success returns the generated string. In case of error returns `NULL`. + + .. versionadded:: 1.14.0 + .. c:function:: int uv_exepath(char* buffer, size_t* size) Gets the executable path. diff --git a/include/uv-unix.h b/include/uv-unix.h index d7754509b1e..4deb03af832 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/include/uv.h b/include/uv.h index 6aa43a271c2..af1bfc55d2b 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1392,6 +1392,14 @@ UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size); UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst); +#if defined(IF_NAMESIZE) +# define UV_IF_NAMESIZE IF_NAMESIZE +#elif defined(IFNAMSIZ) +# define UV_IF_NAMESIZE IFNAMSIZ +#endif + +UV_EXTERN int uv_if_indextoname(unsigned int ifindex, char* ifname); + UV_EXTERN int uv_exepath(char* buffer, size_t* size); UV_EXTERN int uv_cwd(char* buffer, size_t* size); diff --git a/src/inet.c b/src/inet.c index da63a688c4e..9c4188506dc 100644 --- a/src/inet.c +++ b/src/inet.c @@ -49,7 +49,6 @@ int uv_inet_ntop(int af, const void* src, char* dst, size_t size) { /* NOTREACHED */ } - static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { static const char fmt[] = "%u.%u.%u.%u"; char tmp[UV__INET_ADDRSTRLEN]; diff --git a/src/uv-common.c b/src/uv-common.c index bc7d1379d13..e1b2b944449 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -225,6 +225,35 @@ int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) { return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size); } +int uv_if_indextoname(unsigned int ifindex, char* ifname) { +#ifdef _WIN32 + NET_LUID InterfaceLuid; + int error = ConvertInterfaceIndexToLuid(ifindex, &InterfaceLuid); + if (NO_ERROR != error) { + return -error; + } + char InterfaceName[NDIS_IF_MAX_STRING_SIZE + 1]; + int status = ConvertInterfaceLuidToAName(InterfaceLuid, InterfaceName, sizeof(InterfaceName)); + if (NETIO_ERROR_SUCCESS != status) { + return -status; + } + if (strlen(InterfaceName) >= UV_IF_NAMESIZE) { + return UV__ENAMETOOLONG; + } + strncpy(ifname, InterfaceName, UV_IF_NAMESIZE); + return 0; +#else + const int saved_errno = errno; + errno = 0; + if (NULL == if_indextoname(ifindex, ifname)) { + assert(errno); + return -errno; + } + errno = saved_errno; + return 0; +#endif +} + int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c index 156fccde39d..75e34d64168 100644 --- a/test/test-ip6-addr.c +++ b/test/test-ip6-addr.c @@ -67,6 +67,9 @@ TEST_IMPL(ip6_addr_link_local) { iface_index = address->address.address6.sin6_scope_id; device_name = address->name; + ASSERT(0 == uv_if_indextoname(iface_index, scoped_addr)); + ASSERT(0 == strcmp(device_name, scoped_addr)); + #ifdef _WIN32 snprintf(scoped_addr, sizeof(scoped_addr), @@ -96,6 +99,8 @@ TEST_IMPL(ip6_addr_link_local) { uv_free_interface_addresses(addresses, count); + ASSERT(0 != uv_if_indextoname((unsigned int)-1, scoped_addr)); + MAKE_VALGRIND_HAPPY(); return 0; }