.netsocketsraspberry-pidgrams

.Net Socket SendTo command not Receiving via UDP on a Raspberry Pi 4 running Buster


I'm using a shared class library (private, not a public one) that has a method that searches local networks for a Manufacturers Test box in order to commission the device my software is running on.

I am running a .Net 6 application on a Raspberry Pi 4 running Buster.

The search uses .Net Sockets, using the SendTo command and waits for the responses. This works running from Visual Studio on my Windows PC, it also works on a different but similar application on a Raspberry PI 3 running Stretch, using the same method.

But on the PI 4, I simply don't get any responses. I've looked on WireShark and it seems to be communicating but I'm not overly sure as I don't really understand this level of networking, but there are no obvious errors being reported at any stage.

public List<EthernetDevice> SearchLocalNetwork()
    {
        //EthernetDevice newDevice = new EthernetDevice();
        var devices = new List<EthernetDevice>();

        foreach (var adapter in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces())
        {
            foreach (var address in adapter.GetIPProperties().UnicastAddresses)
            {
                // We're only interested in IPv4 addresses for now
                if (address.Address.AddressFamily != AddressFamily.InterNetwork)
                {
                    continue;
                }

                // Ignore loopback addresses (e.g., 127.0.0.1)
                if (IPAddress.IsLoopback(address.Address))
                {
                    continue;
                }

                try
                {
                    var ethernetSearch = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    ethernetSearch.ExclusiveAddressUse = false;
                                           
                    var data = new byte[4];
                    var bytBuffer = new byte[256];

                    var broadcastAddress = address.Address.GetAddressBytes();

                    /*if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                        {
                            broadcastAddress[0] = 169;
                            broadcastAddress[1] = 254;

                        }*/

                    // broadcastAddress[2] = 255;
                    broadcastAddress[3] = 255;
                    var newAddress = new IPAddress(broadcastAddress);
                    Console.WriteLine("Broadcast Address: {0}", newAddress);

                    IPEndPoint responder = new IPEndPoint(IPAddress.Any, 0);

                    // IPEndPoint responder = new IPEndPoint(newAddress, 0);
                    EndPoint rep = (EndPoint)responder; // this will be IP Address and Port number: 192.168.10.123:30716
                    int i, endtime;

                    //////////////////////////////////////////////////////////////
                    // Set up a UDP Socket which can broadcast to entire network
                    //////////////////////////////////////////////////////////////
                    ethernetSearch.EnableBroadcast = true;
                    ethernetSearch.ReceiveTimeout = 8000;
                    ethernetSearch.ExclusiveAddressUse = false;                                                
                    

                    // Define an EndPoint which can be used to broadcast. Port 0x77FE
                    // is the configuration port of the XPort Direct.
                    //
                    // IPEndPoint ep = new IPEndPoint(System.Net.IPAddress.Broadcast, 0x77FE);
                    var ep = new IPEndPoint(newAddress, 0x77FE);                        

                    // Set up a message to send, requesting configuration register.
                    // Message F8 does this, and should initiate a reply of F9 followed
                    // by the register details in HEX format
                    for (i = 0; i < 4; data[i++] = 0);
                    data[3] = 0xF8;
                                            
                    // Broadcast the message
                    ethernetSearch.SendTo(data, ep);                                                

                    // The following block of code will run continually until
                    // no more replies are received. At this point, a Socket
                    // Exception will be thrown, and then caught in the Catch
                    // statement. Initially the receive timeout is set to 7000ms
                    // as it takes a while for the broadcast message to go out
                    // and the devices to initiate a reply. After that, they
                    // respond very quickly in succession, so the receive timeout
                    // is reduced to 700ms to reduce the waiting time after the last
                    // reply is received
                    //
                    // The IP Address which sent the response is extracted from the Responding
                    // End Point (REP).
                    endtime = Environment.TickCount + 7000;

                    while (true) // this loop will be exited by the 'break' statement when no more replies are received
                    {
                        while (Environment.TickCount < endtime && ethernetSearch.Available == 0)
                        {
                            Thread.Sleep(2);
                        }

                        if (ethernetSearch.Available > 0)
                        {
                            ethernetSearch.ReceiveFrom(bytBuffer, ref rep);
                        }
                        else
                        {
                            break;
                        }

                        if (bytBuffer[3] == 0xF9) // verify reply code - response to F8 is F9
                        {
                            var iPAdd = rep.ToString().Substring(0, rep.ToString().IndexOf(':'));

                            var port = bytBuffer[25] * 256 + bytBuffer[24];
                            iPAdd += ":" + port;

                            var isDhcp = false;

                            if (bytBuffer[4] == 0 && bytBuffer[5] == 0 && bytBuffer[6] == 0 && bytBuffer[7] == 0)
                            {
                                isDhcp = true;
                            }

                            var device = new EthernetDevice();
                            device.IPAddress = iPAdd.Split(':')[0];
                            device.Port = port;
                            device.DHCP = isDhcp;
                            device.Gateway = bytBuffer[16] + "." + bytBuffer[17] + "." + bytBuffer[18] + "." +
                                             bytBuffer[19];
                            device.BaudRate = 2;
                            devices.Add(device);

                            //if (devices.FirstOrDefault(x => x.IPAddress == device.IPAddress) == null)
                            //{
                            //    devices.Add(device);
                            //}

                            // Set up new end time for waiting for next device
                            endtime = Environment.TickCount + 700;
                        }
                    }

                    // sort the resulting list by IP Address order
                    ethernetSearch.Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }

        return devices;
    }

Its a bit rough but returns a list of test boxes across any networks it detects.

Does anyone have any ideas, is this a OS/Buster issue or a code issue? I'm thinking its more OS at this stage.

I did try setting the buffer sizes in sysctl.conf but is didn't help.

net.core.rmem_max = 16777216
net.core.wmem_max = 4194304

Solution

  • The issue was solved by resetting all UFW rules on the device.

    sudo ufw reset