2
votes

I have a C# .NET client which listens for UDP multicast messages. I need to receive messages on a single network interface. Sometimes I will not see the messages being received. When I disable the other interfaces, it works.

I attempted to set socket options to a specific interface using code from similar questions on this site, however, I'm unsure if this only affects sending multicast messages and not receiving them?

After my research, I see that the routing table causes this behavior and one solution is to change the routing table, but I prefer not to go that route.

Is it better to join the multicast group on all the interfaces? How would I do that using a UdpClient.

This is the code used to setup my UdpClient:

Getting the interfaces:

public static IEnumerable<NetworkInterface> GetAvailableMulticastInterfaces()
{
    NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
    List<NetworkInterface> availableInterfaces = new List<NetworkInterface>();

    foreach (NetworkInterface adapter in nics)
    {
        IPInterfaceProperties ip_properties = adapter.GetIPProperties();

        if (!adapter.GetIPProperties().MulticastAddresses.Any())
            continue; // most of VPN adapters will be skipped
        if (!adapter.SupportsMulticast)
            continue; // multicast is meaningless for this type of connection
        if (OperationalStatus.Up != adapter.OperationalStatus)
            continue; // this adapter is off or not connected
        IPv4InterfaceProperties p = adapter.GetIPProperties().GetIPv4Properties();
        if (null == p)
            continue; // IPv4 is not configured on this adapter

        availableInterfaces.Add(adapter);
    }

    return availableInterfaces;
}

Setting the Interface:

NetworkInterface networkInterface = Common.Utilities.Network.GetAvailableMulticastInterfaces().Where(nic => nic.Id == attributes.SelectedNetworkInterfaceId).FirstOrDefault();

Getting the Interface Index:

networkInterfaceIndex  = (int)IPAddress.HostToNetworkOrder(networkInterface.GetIPProperties().GetIPv4Properties().Index);

Binding the UdpClient:

public void Listen(string multicastGroupAddress, int port, int? networkInterfaceIndex = null)
{
    IpAddress = multicastGroupAddress;
    Port = port;

    _multicastEndPoint = new IPEndPoint(IPAddress.Parse(multicastGroupAddress), port);

    Listener = new UdpClient();
    Listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

    if (networkInterfaceIndex != null)
        Listener.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, networkInterfaceIndex.Value);

    var localEndpoint = new IPEndPoint(IPAddress.Any, port);
    Listener.Client.Bind(localEndpoint);
    Listener.JoinMulticastGroup(IPAddress.Parse(multicastGroupAddress));

    while (true)
        Process();
}
1

1 Answers

1
votes

Ok, so I came back to this and found the right operation to use. One must join on multiple interfaces using

var availableMulticastNics = Utils.GetAvailableMulticastInterfaces();
var listener = new UdpClient();
listener.Client.Bind(new IPEndPoint(IPAddress.Any, endpoint.Port));

foreach (var ni in availableMulticastNics)
{
    listener.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastEndPoint.Address, ni.GetIPProperties().GetIPv4Properties().Index));
}
// Ready to read socket

Instead of listener.JoinMulticastGroup(ni.GetIPProperties().GetIPv4Properties().Index, multicastEndPoint.Address). Otherwise, I get a SocketException that tells me invalid argument, which someone can shed some light on if they can.