0

I want to create a socket bound to any port on the local machine so I can simulate socketpair() on Windows. When I want this socket to be IPv6, what value should I set for sin6_scope_id? Do I actually have to enumerate the adapters and find the loopback adapter in order to fill in that field?

In other words, what do I need to do with this in order to bind to any local port?

struct sockaddr_in6 addr;
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(0);
addr.sin6_flowinfo = 0;
addr.sin6_addr = in6addr_loopback;
addr.sin6_scope_id = ????;
Myria
  • 3,372
  • 1
  • 24
  • 42

1 Answers1

2

Some socket gurus might know a direct way to set it. But it's easier to just query the system for it. This will correctly set both "flowinfo" and "scope_id" for you.

General approach is this:

Invoke getifaddrs to get a list of ifaddrs instances.

Enumerate the list of ifaddrs returned from this api until you find the AF_INET6 adapter with the IFF_LOOPBACK bit set on the ifa_flags member. This is the adapter you want to bind to.

Now that you have a pointer to the ifaddrs instance, cast its ifa_addr member to a (sockaddr_in6*). Copy this structure into your own addr and set the port.

Some sample code below:

struct sockaddr_in6 addr = {0};
ifaddrs* pList = NULL;
ifaddrs* pAdapterFound = NULL;
ifaddrs* pAdapter = NULL;
getifaddrs(&pList);
pAdapter = pList;
while (pAdapter)
{
    if ((pAdapter->ifa_addr != NULL) && 
        (family == pAdapter->ifa_addr->sa_family == AF_INET6) &&
        (pAdapter->ifa_flags & IFF_LOOPBACK))
    {
        pAdapterFound = pAdapter;
        break;
    }
    pAdapter = pAdapter->ifa_next;
}

if (pAdapterFound)
{    
    // C++ way to copy the sockaddr_in6 struct
    addr = *(reinterpret_cast<sockaddr_in6*>(pAdapterFound->ifa_addr));  // C++

    // If you are coding in C instead of C++
    // memcpy(&addr, pAdapterFound->ifa_addr, sizeof(addr));

    addr.sin6_port = htons(0); // or whatever port you want to bind to
}

freeifaddrs(pList);

You are welcome to reference a helper function I have called GetSocketAddressForAdapter. You could invoke it as follows:

GetSocketAddressforAdapter(AF_INET6, "::1", 0, &address);
selbie
  • 100,020
  • 15
  • 103
  • 173
  • This is for Windows; I suppose I need `GetAdaptersAddresses`? The whole reason I'm doing this is because Windows doesn't have `socketpair` and there's no other way to interrupt `select` or `WSAPoll`. By the way, use `memcpy` (or `std::memcpy`) in C++ also to avoid violating aliasing rules with that `reinterpret_cast`. – Myria Oct 29 '19 at 00:56
  • You should specify your question with the Windows tag. The problem with the GetAdaptersAddresses is that it doesn't return back a sockaddr_in6 structure. You might need the `SIOCGLIFNUM` socket ioctl instead. Can you explain the aliasing problem to me ? – selbie Oct 29 '19 at 01:06
  • https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – Myria Oct 29 '19 at 01:46