Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add uv_if_indextoname and uv_if_indextoiid #1445

Closed
wants to merge 3 commits into from

Conversation

pekkanikander
Copy link
Contributor

if_indextoname(...) is a function defined in <net/if.h>

It is used to convert an IPv6 scope_id into an interface
identifier string such as %eth0 or %lo

There is an identical function in Windows, but I don't have
Windows compilation environment. Hence, Windows
help would be appreciated.

This is needed by nodejs/node#14500
This replaces #1443

pekkanikander added a commit to Ell-i/libuv that referenced this pull request Jul 27, 2017
if_indextoname(...) is a function defined in <net/if.h>

It is used to convert an IPv6 scope_id into an interface
identifier string such as %eth0 or %lo

There is an identical function in Windows, but
that has not been tested.

Adds documentation and an ASSERT to the relevant test case.

PR-URL: libuv#1445
Cross-platform IPv6-capable implementation of :man:`if_indextoname(3)`.
Writes the result to `ifname`, which must be at least `IFNAMSIZ` long.
On success returns the generated string. In case of error returns `NULL`.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A .. versionadded:: tag should be added with a semver-minor jump --> 1.14.0

src/inet.c Outdated
@@ -49,6 +49,9 @@ int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
/* NOTREACHED */
}

char* uv_if_indextoname(unsigned int ifindex, char* ifname) {
return if_indextoname(ifindex, ifname);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: 2-space indentation

.. 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 `IFNAMSIZ` long.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On linux the constant is IF_NAMESIZE so we could add a UV_IF_NAMESIZE constant to avoid platform inconsistencies

src/inet.c Outdated
@@ -49,6 +49,9 @@ int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
/* NOTREACHED */
}

char* uv_if_indextoname(unsigned int ifindex, char* ifname) {
return if_indextoname(ifindex, ifname);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I would probably change the signature of the function so it returns an int so it returns 0 on success or -errno on error.

On Windows apparently if if_indextoname returns NULL there's no way to check the error, so it's probably better use this other method explained in the documentation:

The if_indextoname function is implemented for portability of applications with Unix environments, but the ConvertInterface functions are preferred. The if_indextoname function can be replaced by a call to the ConvertInterfaceIndexToLuid function to convert an interface index to a NET_LUID followed by a call to the ConvertInterfaceLuidToNameA to convert the NET_LUID to the ANSI interface name.

If the if_indextoname fails and returns a NULL pointer, it is not possible to determine an error code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@santigimeno I can do this (at least the first version), but I have difficulty in figuring out in which file(s) I should place the Unix and Windows versions. Could you please suggest suitable source files for the source code?

--Pekka

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@saghul and @santigimeno I have read the contribution instructions a few times. The problem is that some of the related functions are already in src/inet.c, and some of them are in src/uv-common.c. None of them are so far in src/unix/ or src/win. Hence, in src/unix/ or src/win there are basically no existing files where I could add this function. I would not think the right choice is to create yet another source file for just this simple function.

So, since there seems to be already some #ifdef _WIN32 conditionals in src/uv-common.c, and since all Unix variants (including Linux) should have the same underlying function signature anyway, I'm now moving the source code from src/inet.c (where it would belong IMHO) to src/uv-common.c, with the actual implementation behind #ifdef _WIN32. Personally, I find the solution ugly due to the new #ifdef, but I couldn't find any better place.

pekkanikander added a commit to Ell-i/libuv that referenced this pull request Jul 28, 2017
if_indextoname(...) is a function defined in <net/if.h>

It is used to convert an IPv6 scope_id into an interface
identifier string such as %eth0 or %lo

The Windows implementation has not been tested.

Adds documentation and an ASSERT to the relevant test case.

PR-URL: libuv#1445
@pekkanikander
Copy link
Contributor Author

I pushed a rewritten version. The Windows version has not been tested, since I have no possibility to even compile it.

pekkanikander added a commit to Ell-i/libuv that referenced this pull request Jul 28, 2017
if_indextoname(...) is a function defined in <net/if.h>

It is used to convert an IPv6 scope_id into an interface
identifier string such as %eth0 or %lo

The Windows implementation has not been tested.

Adds documentation and an ASSERT to the relevant test case.

PR-URL: libuv#1445
Copy link
Contributor

@cjihrig cjihrig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the ideal way to organize the code. Left some other comments too.

include/uv.h Outdated
# define UV_IF_NAMESIZE IF_NAMESIZE
#elif defined(IFNAMSIZ)
# define UV_IF_NAMESIZE IFNAMSIZ
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if neither of these constants are defined for some reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If neither of them are defined, then presumably the underlying OS does not support if_indextoname either. Should that invoke an #error or #warning?

For the next version I'll place there a #warning, but of course that can be removed, if needed.


.. versionadded:: 1.14.0

.. c:function:: char* uv_if_indextoname(unsigned int ifindex, char* ifname)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documented return type seems to be out of sync with the actual return type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lenght -> length

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documentation needs to be updated as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to describe the error codes. I could not decipher from the documentation what Windows does in various error conditions.

src/uv-common.c Outdated
strncpy(ifname, InterfaceName, UV_IF_NAMESIZE);
return 0;
#else
const int saved_errno = errno;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to save, assign, and restore errno.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to be defensive. But of course YMMV.

src/uv-common.c Outdated
const int saved_errno = errno;
errno = 0;
if (NULL == if_indextoname(ifindex, ifname)) {
assert(errno);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need this I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that if the function returns NULL, errno should be non-zero, but again tried to be defensive.

src/uv-common.c Outdated
NET_LUID InterfaceLuid;
int error = ConvertInterfaceIndexToLuid(ifindex, &InterfaceLuid);
if (NO_ERROR != error) {
return -error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at how errors are returned from other Windows functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to have a look at the other Windows functions. I hope I did the right thing.

saghul
saghul previously requested changes Jul 30, 2017
Copy link
Member

@saghul saghul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review round 2.

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 zero. If the interface is not found,
returns `UV__ENXIO`. If the interface name is longer than what the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore. The souble underscore variants are internal.

Writes the result to `ifname`, which must be at least `UV_IF_NAMESIZE`
long. On success, returns zero. If the interface is not found,
returns `UV__ENXIO`. If the interface name is longer than what the
function can handle, returns `UV__ENAMETOOLONG` (Windows only. Should
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

long. On success, returns zero. If the interface is not found,
returns `UV__ENXIO`. If the interface name is longer than what the
function can handle, returns `UV__ENAMETOOLONG` (Windows only. Should
not happen ever.) In Windows, may also return other error values under
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh, famous last works :-)

src/uv-common.c Outdated
@@ -225,6 +225,30 @@ 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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other functions we have which write to a buffer take a second length parameter. I'd like us to do the same here. It would be an in-out parameter. See this similar API: http://docs.libuv.org/en/v1.x/fs_poll.html#c.uv_fs_poll_getpath

Please make sure the terminating NULL byte is handled consistently.

src/uv-common.c Outdated
}
if (!ConvertInterfaceLuidToAName(
InterfaceLuid, InterfaceName, sizeof(InterfaceName)) {
return GetLastError();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't work, you need to convert the windows error into a UV error.

include/uv.h Outdated
#elif defined(IFNAMSIZ)
# define UV_IF_NAMESIZE IFNAMSIZ
#else
# warning "Cannot define UV_IF_NAMESIZE: neither IF_NAMESIZE nor IFNAMSIZ defined."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should define this ourselves to some consdervative value. Just to play safe.

src/uv-common.c Outdated
#ifdef _WIN32
NET_LUID InterfaceLuid;
char InterfaceName[NDIS_IF_MAX_STRING_SIZE + 1];
if (!ConvertInterfaceIndexToLuid(ifindex, &InterfaceLuid)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like having Windows APIs in uv-common, let's split this and have it in src/unix/core.c and src/win/util.c please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to split into src/unix/getaddrinfo.c and src/win/getaddrinfo.c instead, since the interface names are integral parts of IPv6 link local addresses.

pekkanikander added a commit to Ell-i/libuv that referenced this pull request Aug 3, 2017
if_indextoname(...) is a function defined in <net/if.h>

It is used to convert an IPv6 scope_id into an interface
identifier string such as %eth0 or %lo

The Windows implementation has not been tested.

Adds documentation and an ASSERT to the relevant test case.

PR-URL: libuv#1445
@pekkanikander
Copy link
Contributor Author

I tried to address all review round 2 comments. The Windows version is still completely untested, since I have no possibility of even compiling it.

char ifname_buf[UV_IF_NAMESIZE];
if (NULL == if_indextoname(ifindex, ifname_buf)) {
return -errno;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: remove braces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but you guys are looking for trouble...

}
{
const int required_len = strlen(ifname_buf) + 1;
const int ifname_len = *sizep;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: we usually define local variables at the beginning of the function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do, but then I cannot use const. Which I consider bad style. But YMMV.

*sizep = required_len;
if (ifname_len < required_len) {
return UV_ENAMETOOLONG;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: remove braces


int uv_if_indextoname(unsigned int ifindex, char* ifname, size_t *sizep) {
char ifname_buf[UV_IF_NAMESIZE];
if (NULL == if_indextoname(ifindex, ifname_buf)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we set ifname_buf[UV_IF_NAMESIZE - 1] to zero to be sure is NULL terminated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is needed, the underlying implementation should never return anything that is even close to IFNAMSIZ in length. But I can add such an assignment if you want to have both a belt and suspenders.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pekkanikander you're right, I was overthinking. I was looking into the musl implementation and saw it was returning the result of strncpy and thought that it could happen that the buffer would end up not NULL terminated in some cases. But that's not possible as ifreq.ifr_name is of size IFNAMSIZ. Sorry for the noise.

if (ifname_len < required_len) {
return UV_ENAMETOOLONG;
}
memcpy(ifname, ifname_buf, required_len);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be strcpy()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? strcpy is unsafe. I could use strncpy, but since we already know the length of the name, why to use strncpy which is less efficient that memcpy?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this case strcpy should be safe as we know ifname is least of the size of ifname_buf but you're right memcpy should do it.

Copy link
Member

@santigimeno santigimeno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some comments

int uv_if_indextoname(unsigned int ifindex, char* ifname, size_t *sizep) {
char ifname_buf[UV_IF_NAMESIZE];
int required_len;
const int ifname_len = *sizep;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: we usually separate declaration from assignment.

if (NULL == if_indextoname(ifindex, ifname_buf))
return -errno;

ifname_buf[sizeof(ifname_buf)-1] = '\0'; // To be _really_ sure
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should drop this as I was wrong,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dropped the separate assignment, but also changed strlen to strnlen to avoid running over the buffer even in the case there was some obscure internal hiccup.

NET_LUID InterfaceLuid;
char InterfaceName[NDIS_IF_MAX_STRING_SIZE + 1];
int required_len;
const int ifname_len = *sizep;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: separate declaration from assignment


if (!ConvertInterfaceIndexToLuid(ifindex, &InterfaceLuid)) {
return uv_translate_sys_error(GetLastError());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop braces

@santigimeno
Copy link
Member

@santigimeno
Copy link
Member

It looks there are issues on the Windows side:

src\win\getaddrinfo.c(387): error C2065: 'NDIS_IF_MAX_STRING_SIZE': undeclared identifier [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(387): error C2057: expected constant expression [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(387): error C2466: cannot allocate an array of constant size 0 [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(387): error C2133: 'InterfaceName': unknown size [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(391): warning C4013: 'ConvertInterfaceIndexToLuid' undefined; assuming extern returning int [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(394): warning C4013: 'ConvertInterfaceLuidToAName' undefined; assuming extern returning int [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(395): warning C4034: sizeof returns 0 [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(399): error C2065: 'ifname_buf': undeclared identifier [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(399): warning C4034: sizeof returns 0 [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]
src\win\getaddrinfo.c(399): error C2109: subscript requires array or pointer type [c:\workspace\libuv-test-commit-windows\nodes\win2016-vs2015\libuv.vcxproj]

@pekkanikander
Copy link
Contributor Author

Unfortunately I have no ability to address the Windows issues. As I have mentioned a couple of times, I have last time used Windows back in 2001, and never developed any code on Windows. Hence, I am not able to even guess what should be included or what else could be wrong.

I will address the remaining style comments either later today or tomorrow.

@saghul
Copy link
Member

saghul commented Aug 5, 2017

@pekkanikander Microsoft's documentation is pretty good. Searching for the function names will yield its documentation page, which mentions which file needs to be included. As an example: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365826(v=vs.85).aspx

@pekkanikander
Copy link
Contributor Author

@saghul To be specific, and to give you an understanding of what I don't know:

For ConvertInterfaceIndexToLuid and ConvertInterfaceIndexToLuid, which of the following is correct?

  1. #include <Netioapi.h>
  2. #include <netioapi.h>
  3. #include <Iphlpapi.h>
  4. #include <iphlpapi.h>

And are they really without any prefix path?

@saghul
Copy link
Member

saghul commented Aug 6, 2017

Number 4 would be correct. No, there is no prefix path needed.

@pekkanikander
Copy link
Contributor Author

The next question is where to place #include <iphlpapi.h>? To the beginning of src/win/getaddrinfo.c? Or src/win/winsock.h? Or somewhere else?

Now it is there, but in a wrong place. But this might compile under Windows; it would be nice to see what compilation errors there are now on Windows.

@saghul
Copy link
Member

saghul commented Aug 6, 2017

You can place it in getaddrinfo.c, where it's actually used. Just like another import file, there is nothing special about it, so at the top.

@pekkanikander
Copy link
Contributor Author

#include <iphlpapi.h> moved to its hopefully proper place.

Copy link
Member

@santigimeno santigimeno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments after testing this on Windows. Still, the test fails as the device_name does not match the scoped_addr. On my VM is Ethernet vs ethernet_32768. Haven't investigated it though.

ifname_len = *sizep;

if (!ConvertInterfaceIndexToLuid(ifindex, &InterfaceLuid))
return uv_translate_sys_error(GetLastError());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It returns zero on success not on error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I don't understand this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry now I did understand. Fixed.

return uv_translate_sys_error(GetLastError());

if (!ConvertInterfaceLuidToAName(
InterfaceLuid, InterfaceName, sizeof(InterfaceName)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some issues here:

  • s/ConvertInterfaceLuidToAName/ConvertInterfaceLuidToNameA
  • It should be &InterfaceLuid.
  • It returns zero on success

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@pekkanikander
Copy link
Contributor Author

What happens to this next? As far as I understand, it is now the Windows side which is holding this back. And as I have written, I don't know Windows at all.

So, any suggestions on how to proceed?

This is needed for making NodeJS to handle IPv6 link local packets correctly with UDP.

@bnoordhuis
Copy link
Member

We'll have to wait until someone contributes Windows support.

@pekkanikander
Copy link
Contributor Author

Any idea how to find such someone? All the programmers I know are either Linux or Unix (including Mac OS X) folks.

@BridgeAR
Copy link

As this currently blocks a PR on Node.js PTAL @santigimeno @saghul @cjihrig.

if (r == ERROR_FILE_NOT_FOUND)
return UV_ENXIO;
else if (r != 0)
return UV_EINVAL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though there is only one other error besides ERROR_FILE_NOT_FOUND, perhaps this should call uv_translate_sys_error() to be a little less confusing.

interface_name,
sizeof(interface_name));
if (r != 0)
return UV_EINVAL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use uv_translate_sys_error() I think. One of the errors returned by ConvertInterfaceLuidToNameA() is ERROR_NOT_ENOUGH_MEMORY, which doesn't really correspond to UV_EINVAL.


int uv_if_indextoname(unsigned int ifindex, char* ifname, size_t* sizep) {
NET_LUID interface_luid;
char interface_name[NDIS_IF_MAX_STRING_SIZE + 1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a comment that NDIS_IF_MAX_STRING_SIZE does not include the NULL.

else if (r != 0)
return UV_EINVAL;

r = ConvertInterfaceLuidToNameA(&interface_luid,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to use ConvertInterfaceLuidToNameA() instead of ConvertInterfaceLuidToNameW()? My experience has been that on Windows, libuv uses the W variants of these functions, and then converts them.

if (r != 0)
return UV_EINVAL;

required_len = strnlen(interface_name, sizeof(interface_name)) + 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be safe to use strlen() here, right?

*sizep = required_len;

if (ifname_len < required_len)
return UV_ENOBUFS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the success case, we should be returning a string length in *sizep. In the case of UV_ENOBUFS, it should be a size (length + 1). Right now, the UV_ENOBUFS case is correct, but the success case is not.


ifname_len = *sizep;

*sizep = snprintf(ifname, ifname_len, "%d", ifindex) + 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here about the *sizep value in the two different scenarios.

@@ -200,3 +200,28 @@ void uv_freeaddrinfo(struct addrinfo* ai) {
if (ai)
freeaddrinfo(ai);
}


int uv_if_indextoname(unsigned int ifindex, char* ifname, size_t* sizep) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of the same comments from the Windows code apply here as well.

@pekkanikander
Copy link
Contributor Author

pekkanikander commented Sep 20, 2017

@cjihrig @refack @bzoz and all: As I have written above, I have no Windows experience. Given my schedule and the my previous struggling with the changes requested on the Windows version, I have no option but to refrain from doing any more work on the Windows version. Last time it took several hours for getting such "small" changes right, and then another one of you came and basically rewrote the whole Windows version.

The NodeJS PR requires only the uv_if_indextoiid anyway; I did not understand initially that Windows does not need if_indextoname, as Windows even has a genuine inbuilt implementation if if_indextoname. I was just told not to use it.

Hence, unless someone jumps in and volunteers to take care of the Windows side, I will simply remove the uv_if_indextoname completely, leaving only the (later added) uv_if_indextoiid.

So, which of the following:

  1. Someone volunteers and takes care of the Windows side?
  2. I remove uv_if_indextoname completely?
  3. We let this PR to rotten until the hell freezes?

@cjihrig
Copy link
Contributor

cjihrig commented Sep 20, 2017

If you're unwilling or unable to implement the Windows pieces, then someone else should probably take over the PR. Unfortunately, the Windows side needs to work as well before we can accept this.

@pekkanikander
Copy link
Contributor Author

I am unable to make any reasonable changes to the Windows pieces, since I cannot compile nor test it. I haven't much touched Windows since 2001 or so; I am basically unable to use modern Windows versions (i.e extremely clumsy due to the UI changes). Windows XP is the latest version I am somewhat comfortable with, but I don't have it installed anywhere any more.

As I wrote, the uv_if_indextoiid should be sufficient for the NodeJS PR. I don't see any significant Windows-dependent comments to that side; the couple of minor comments I can probably handle.

So, unless someone else volunteers for taking over (for the Windows), I'll simply remove the uv_if_indextoname. That should take care of the current NodeJS needs.

@cjihrig
Copy link
Contributor

cjihrig commented Sep 20, 2017

My Windows setup isn't great either. I use Windows 7 inside of VirtualBox on my mac. For the purposes of working on libuv, you can get away with pretty much only using the command line. It's a bit of a pain to get setup, but then you can at least compile and run the test suite locally.

@pekkanikander
Copy link
Contributor Author

Any update on this?

@cjihrig
Copy link
Contributor

cjihrig commented Sep 26, 2017

I'll try to spend some time on this tomorrow.

@bzoz
Copy link
Member

bzoz commented Sep 27, 2017

As I understand, we only need uv_if_indextoid for Node PR (both on Linux and Windows). If so, there really is no reason for uv_if_indextoname then, we can drop it.

In any case I can pickup the Windows side of this if needed.

cjihrig pushed a commit to cjihrig/libuv that referenced this pull request Oct 20, 2017
if_indextoname(...) is a function defined in <net/if.h>

It is used to convert an IPv6 scope_id into an interface
identifier string such as %eth0 or %lo

uv_if_indextoiid is a cross-platform implementation that
returns an IPv6 interface identifier.  On Unix/Linux
it calls if_indextoname, on Windows it uses snprintf
to return the numeric interface identifier as a string.

Adds documentation and an ASSERT to the relevant test case.

PR-URL: libuv#1445
@cjihrig
Copy link
Contributor

cjihrig commented Oct 20, 2017

@pekkanikander sorry it took longer than I had expected to get to this. I reworked this PR in cjihrig@f939aa6. Feel free to use that however you want. The corresponding CI run is https://ci.nodejs.org/view/libuv/job/libuv-test-commit/534/.

if_indextoname(...) is a function defined in <net/if.h>

It is used to convert an IPv6 scope_id into an interface
identifier string such as %eth0 or %lo

uv_if_indextoiid is a cross-platform implementation that
returns an IPv6 interface identifier.  On Unix/Linux
it calls if_indextoname, on Windows it uses snprintf
to return the numeric interface identifier as a string.

Adds documentation and an ASSERT to the relevant test case.

PR-URL: libuv#1445

Reworked based on f939aa6
@pekkanikander
Copy link
Contributor Author

This is now a version reworked based on Colin's version. Thanks Colin!

The Windows version is directly taken from Colin's work. The documentation and Unix version I double checked, trying to fix even the tiny nits.

Copy link
Member

@santigimeno santigimeno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM with a couple of comments

Maximum IPv6 interface identifier name length. Defined as
`IFNAMSIZ` on Unix and `IF_NAMESIZE` on Linux and Windows.

.. versionadded:: 1.15.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're now targeting 1.16.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;

r = snprintf(buffer, *size, "%d", ifindex) + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the + 1 location correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This I'd leave for @cjihrig to comment

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the + 1 should be dropped. r represents an error or the string length (no NULL) on success, so I think the rest of the logic is correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in f82e7de

@santigimeno
Copy link
Member

r represents an error or the string length (no NUL) on success,
so Colin thinks the rest of the logic is correct.
Copy link
Contributor

@cjihrig cjihrig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I can review this, but LGTM

@cjihrig cjihrig dismissed saghul’s stale review November 1, 2017 15:29

Dismissing as it looks like everything has been addressed, and the PR has changed quite a bit since.

@cjihrig
Copy link
Contributor

cjihrig commented Nov 1, 2017

@saghul I dismissed your old review since the PR has changed since then, and it appears that the objections had been addressed. Would you care to take another look at this?

@cjihrig cjihrig mentioned this pull request Nov 3, 2017
cjihrig pushed a commit that referenced this pull request Nov 6, 2017
uv_if_indextoname() is used to convert an IPv6 scope_id
to an interface identifier string such as %eth0 or %lo.

uv_if_indextoiid() returns an IPv6 interface identifier.
On Unix it calls uv_if_indextoname(). On Windows it uses
snprintf() to return the numeric interface identifier as
a string.

Refs: nodejs/node#14500
PR-URL: #1445
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@cjihrig
Copy link
Contributor

cjihrig commented Nov 6, 2017

Landed in 695afe8. Thanks for the contribution and for sticking with it!

@cjihrig cjihrig closed this Nov 6, 2017
@pekkanikander
Copy link
Contributor Author

Thank you @cjihrig and all! I'll proceed with nodejs/node#14500 on this Wednesday; don't have time tomorrow.

cjihrig added a commit to cjihrig/libuv that referenced this pull request Nov 9, 2017
This commit moves the net/if.h include into src/getaddrinfo.c to
prevent AIX compilation errors. With these symbols exposed
publicly, Node.js compilation failed on AIX by exposing Free(),
which conflicts with another API.

Refs: nodejs/node#16835
Refs: libuv#1445
PR-URL: libuv#1622
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@cjihrig cjihrig mentioned this pull request Nov 9, 2017
cjihrig pushed a commit that referenced this pull request Nov 10, 2017
NDIS_IF_MAX_STRING_SIZE does not appear to be available on
some Windows systems. This commit defines it using the same logic
used by Wireshark.

See: https://github.com/boundary/wireshark/blob/07eade8124fd1d5386161591b52e177ee6ea849f/capture_win_ifnames.c#L42-L44
Refs: nodejs/node#16835
Refs: #1445
PR-URL: #1623
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants