views:

286

answers:

2

I'm trying to figure out how to do the equivalent of an IPV4 broadcast using IPV6.

I'm creating a non-blocking IPV6 UDP socket.

From the side broadcasting i'm literally just doing a sendto "FF02::1" on port 12346.

On the listen side I discovered I need to join the group so I did the following:

    ipv6_mreq membership;
    memset( &membership.ipv6mr_multiaddr, 0, sizeof( in6_addr ) );
    membership.ipv6mr_multiaddr.u.Word[0]   = htons( 0xff02 );
    membership.ipv6mr_multiaddr.u.Word[7]   = htons( 0x0001 );
    membership.ipv6mr_interface             = 0;

    if( enable )
    {
        if ( 0 != setsockopt( m_Socket, SOL_SOCKET, IPV6_JOIN_GROUP, (char*)&membership, sizeof( ipv6_mreq ) ) )
        {
            DisplayError();
            return false;
        }
    }

However setsockopt always returns "WSAENOPROTOOPT". Why? Can anyone help me on this one? I'm at a complete loss.

Edit: I change the level to "IPPROTO_IPV6" but now I get a "WSAEINVAL".

+1  A: 

I think the problem is that you are leaving the ipv6mr_interface value at zero, which isn't good enough if you want to use a link-scope multicast address like ff02::1. You need to set the ipv6mr_interface value to the number corresponding with the local network interface you want the packets to be sent/received on. (You can find out what interface indices are available on the current computer by calling getaddrinfo() and reading the sin6_addr.s6_addr values out of the (struct sockaddr_in6 *)'s that it hands to you)

(If at this point you are thinking to yourself, wouldn't it be so much easier if interface zero acted as an "all interfaces" setting... yes, it would be. Alas, IPv6 doesn't do that for some reason :( )

Jeremy Friesner
Alas under windows I saw that the zone index was 5 for my main adapter. So I tried that index. I also 1 and still had no luck ... Is the interface index the same as the zone index?
Goz
also see: http://msdn.microsoft.com/en-us/library/ms738655(VS.85).aspx
Goz
I'm 99% sure that zone index and interface index are the same thing; so it might be that something else is the problem as well. Under Windows you can call GetAdaptersAddresses() to get to the Ipv6IfIndex field of each adapter's PIP_ADAPTER_ADDRESSES struct. GetAdaptersAddresses() is even more fun than Posix's getaddrinfo() function... check out lines 1034-1124 (and particularly line 1097) of the following file to see my usage of that function: www.lcscanada.com/muscle/muscle/util/NetworkUtilityFunctions.cpp
Jeremy Friesner
Thats not the problem then. There must be something i'm missing. The zone index DOES correspond to the ifindex. In fact just to test my sanity I just tried, in a loop, every zone index from 1 to 50 and I still get a "WSAEINVAL".
Goz
Btw, IPPROTO_IPV6 is correct (not SOL_SOCKET).
Jeremy Friesner
Ah, and one more thing: under Windows, you must bind() the socket to a port BEFORE adding it to the multicast group. (That requirement seems to be a Windows-specific thing; Linux and MacOS/X don't care about the ordering between the bind and the group-join)
Jeremy Friesner
@Jeremy: I know on the IPPROTO_IPV6 ... early mistake. And I DO bind it to a port before trying to add to a multicast group. I get the same error from Mac OSX and the iPhone if that makes any difference to ya!
Goz
Well, in that case I'm out of ideas... if you want to test a known-working implementation (at least, it works for me!), you can do the following: (1) On your Mac, download https://public.msli.com/lcs/muscle/muscle5.31.zip(2) Unzip, then edit muscle/test/Makefile and un-comment the MUSCLE_USE_IPV6 line (at line 6)(3) In the muscle/test folder, enter "make hexterm"(4) When the compile completes, open two Terminal windows(5) In each window, cd to the muscle/test folder and enter: ./hexterm udp=[ff02::1@5]:6666 (Replace the 5 with the appropriate interface/zone number for your machine)
Jeremy Friesner
... (6) enter some hex bytes (e.g. f0 1f 02 03 04) into either window and press return, and you should see both windows print out that they received those bytes from the multicast group.I just tested the above on my Mac and it works here (and the same code works under Linux and Windows AFAIK, although I didn't test them just now). If it works for you, you can see how the networking code (in muscle/test/hexterm.cpp and muscle/util/NetworkUtilityFunctions.cpp) differs from your own; if it doesn't work, then perhaps something else is wrong...
Jeremy Friesner
@Jeremy - Scope and interface indexes are different, you can have multiple addresses on one interface.
Steve-o
+1  A: 

The interface must be set for locally scoped IPv6 because the addresses are only unique to the interface. In simpler terms the address fe80::1 can belong to both eth0 and eth1 but are completely separate.

So this means you need to explicitly send a multicast packet on every up interface that supports multicast, or provide the user with a means of specifying a particular interface.

(edit) If it helps you can check out multicast code here,

http://code.google.com/p/openpgm/source/browse/trunk/openpgm/pgm/

Steve-o
So ar eyou saying I need to bind to address fe80::1 / random port before doing the IPV6_JOIN_GROUP?
Goz
Run through the output of GetAdapterAddresses() and for each unique interface index with an IPv6 address call IPV6_JOIN_GROUP.
Steve-o
Actually I bound BEFORE joining the group and the join went through fine ... Thats perfect :)
Goz
Hopefully bdonlan will award you the bounty because this is the more helpful response in my opinion :)
Goz
Damn, didn't log in in time. Hopefully it got auto-granted to the right person...?
bdonlan
@bdonlan: Nah alas the retarded rule changes for bounties means you needed to explicitly select it unless Steve-o got 2 up-votes for his answer :(
Goz