0

I'm trying to send a multicast packet on all my network interfaces(2 LAN, one wifi). I initialy followed this tutorial.

The problem I encounter, is that it seems that the packet seems to be with only one of my IP address.

Here is my current code.

private static void SendOnAllCards(int port, String address)
{
    using (Socket mSendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
    {
        mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
                                    new MulticastOption(IPAddress.Parse(address)));
        mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255);
        mSendSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        mSendSocket.Bind(new IPEndPoint(IPAddress.Any, port));
        IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(address), port);
        mSendSocket.Connect(ipep);


        byte[] bytes = Encoding.ASCII.GetBytes("This is my welcome message");
        mSendSocket.Send(bytes, bytes.Length, SocketFlags.None);
    }
}

I tried to do it manually:

private static void SendOnAllCards(int port, string remoteAddressSrc)
{
    foreach (IPAddress remoteAddress in Dns.GetHostAddresses(Dns.GetHostName()).Where(i=>i.AddressFamily == AddressFamily.InterNetwork))
    {

        using (Socket mSendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
        {
            mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
                                        new MulticastOption(IPAddress.Parse(remoteAddressSrc)));
            mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255);
            mSendSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            mSendSocket.Bind(new IPEndPoint(IPAddress.Any, port));
            IPEndPoint ipep = new IPEndPoint(remoteAddress, port);
            mSendSocket.Connect(ipep);


            byte[] bytes = Encoding.ASCII.GetBytes("This is my welcome message");
            mSendSocket.Send(bytes, bytes.Length, SocketFlags.None);
        }
    }
}

This works, but it implies I've to create as many socket that I've IP(in this sample I create them on each send, but it's just a test), and I don't like the way I've to obtain all my IPs.

So what is the right way to do this?

Edit second bonus question: Why is this working when I specify the local ip in the Connect, which specify the remote address, but doesn't on the Bind?

J4N
  • 19,480
  • 39
  • 187
  • 340

2 Answers2

1

Seems that we have to iterate on network interfaces, make a Bind on the local IP and do a Send*To* call:

public void SendTestMessage()
{
    foreach (IPAddress localIp in
        Dns.GetHostAddresses(Dns.GetHostName()).Where(i => i.AddressFamily == AddressFamily.InterNetwork))
    {
        IPAddress ipToUse = localIp;
        using (var mSendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
        {
            mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
                                        new MulticastOption(_multicastIp, localIp));
            mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255);
            mSendSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            mSendSocket.MulticastLoopback = true;
            mSendSocket.Bind(new IPEndPoint(ipToUse, _port));


            byte[] bytes = Encoding.ASCII.GetBytes("This is my welcome message");
            var ipep = new IPEndPoint(_multicastIp, _port);
            mSendSocket.SendTo(bytes, ipep);
        }
    }
}
J4N
  • 19,480
  • 39
  • 187
  • 340
0

You could find the network adapters using the WMI class Win32_NetworkAdapter. You might have to refine the results that querying for instances of that brings, because there are many 'virtual adapters' created by both windows and third party software. I wrote up a quick posh script to retreive the adapters using WMI. This should only display adapaters that have IP addresses. This is just to show the WMI information that you could query to retreive the activate adapeters.

$networkadapters = @(Get-CimInstance -ClassName Win32_NetworkAdapter -Property *)
$networkadapters_configs = @($networkadapters | Get-CimAssociatedInstance -ResultClassName Win32_NetworkAdapterConfiguration)

0..($networkadapters.Length-1) | %{
    if($networkadapters_configs[$_].IPAddress -gt '') {
        Write-Output "Adapter #$($_)" 
        Write-Output $networkadapters[$_]
        Write-Output "Config #$($_)" 
        Write-Output $networkadapters_configs[$_]
    }
}
Jake H
  • 1,720
  • 1
  • 12
  • 13
  • I'm not sure to understand how it helps me? – J4N Mar 06 '13 at 16:05
  • You could then use the IP information assigned to each network card to broadcast your multicast messages. In your original post, you were iterating over the IP addresses that are assigned to the host, but it is possible to have multiple IP addresses per NIC. This is an example of extracting the network adapter IP bindings using WMI, which can then be used to accurately send those messages. – Jake H Mar 06 '13 at 16:27
  • My problem is not about finding network interfaces, but how to send data through a socket to multiple interfaces – J4N Mar 06 '13 at 16:34
  • By finding and sending the multicast to the unique IP addresses assigned to the network interfaces, you would send the packet to each possible multicast group. You can have multiple ips per nic, and each IP can belong in a distinct multicast group, or they may all belong to one. If you want to send multicast to every possible multicast group, you'll need to iterate the IPs and send it to each. – Jake H Mar 06 '13 at 19:13
  • Ahh, I realize you are not [joining any multicast group](http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.joinmulticastgroup.aspx) at all in your example code. I believe this is your primary problem. You can still have seperate multicast groups (from vpn connections, for example), but for most purposes joining before socket binding will work. Heres some relevant source code that shows sending multicast messages, including configuring the socket: [multicastdotnet](https://code.google.com/p/multicastdotnet/source/browse/trunk/Multicast/Multicast/MulticastBroadcaster.cs) – Jake H Mar 06 '13 at 19:23
  • Joining multicast group is for UdpClient, I'm doing this on the client side. But I can't use UdpClient to send messages(because it's impossible to have a non-exclusive use of the port/ip + specify the port that I'm sending the data from(not the destination one), which is required by the protocol I'm implementing – J4N Mar 06 '13 at 21:56
  • And I'm joining the multicast group with the SetSocketOption, AddMembership with the multicast option – J4N Mar 06 '13 at 21:57