MrCSharp
MrCSharp

Reputation: 1143

DatagramSocket can send broadcast packets on phone, but not on PC

I have this weird problem with a datagram socket. Basically what I am doing is building a class that allows my app to announce the services it implements and discover other instances on the same network and their services. I use the DatagramSocket class to broadcast a packet to 255.255.255.255 and other apps on the network would respond to it. This works perfectly when the app on the phone is trying to discover the one on desktop. But the app on desktop can't discover the one on my phone. I ran wireshark to monitor the packets and the phone is sending the packets as expected, but the desktop app doesn't send any packets. I am trying to find out if there is a reason why the app fails to send broadcast packets from my desktop but is capable of doing so when it is running from my phone?

I have tested my code with Windows Firewall turned on and off (only firewall I am using).

Devices I have tested this on are:

Here is the code I am using to broadcast packets:

            if (this.datagramSocket == null)
        {
            //initialize the datagram object
            this.datagramSocket = new DatagramSocket();

            //handle the message received event
            this.datagramSocket.MessageReceived += DatagramSocket_MessageReceived;

            //bind the datagram to a service name / port
            await this.datagramSocket.BindServiceNameAsync(this.finderPort.ToString());
        }

        //get an output stream to write the ping message to
        using (var outputStream = await this.datagramSocket.GetOutputStreamAsync(new HostName(BroadcastAddress), this.advertiserPort.ToString()))
        {

            using (var writer = new DataWriter(outputStream))
            {
                //write the message like[id],[name]
                writer.WriteString("Very Special Message");

                //commit everything to the stream
                await writer.StoreAsync();
            }
        }

the 'advertiserPort' and 'finderPort' are predefined as '1994' and '2206' respectively. the 'BroadcastAddress' is 255.255.255.255

Edit: I also tried the DatagramSocket sample provided by Microsoft with the same results. The sample fails to broadcast anything when running on PC and wireshark shows no packets being sent.

Upvotes: 0

Views: 438

Answers (1)

MrCSharp
MrCSharp

Reputation: 1143

So I finally solved the problem. For some unknown reason, DatagramSocket can send UDP packets to global broadcast address (255.255.255.255) when running on a phone, but fails to do so when running on a PC. However, using directed broadcast address (192.168.1.255 for example) works fine on both platforms.

Problem is, UWP only has API to get global broadcast address and if you want to get the directed broadcast address for your current network, you will need to calculate it.

for the benefit of everyone here I will share the code to calculate that address, and hopefully MS will fix this.

this method helps with getting the subnet mask for the network from the device IP address:

public static IPAddress GetSubnetMask(IPAddress hostAddress)
    {
        var addressBytes = hostAddress.GetAddressBytes();

        if (addressBytes[0] >= 1 && addressBytes[0] <= 126)
            return IPAddress.Parse("255.0.0.0");
        else if (addressBytes[0] >= 128 && addressBytes[0] <= 191)
            return IPAddress.Parse("255.255.255.0");
        else if (addressBytes[0] >= 192 && addressBytes[0] <= 223)
            return IPAddress.Parse("255.255.255.0");
        else
            throw new ArgumentOutOfRangeException();
    }

This method is the one that will give the Directed broadcast address:

        public static IPAddress GetBroadastAddress(IPAddress hostIPAddress)
    {
        var subnetAddress = GetSubnetMask(hostIPAddress);

        var deviceAddressBytes = hostIPAddress.GetAddressBytes();
        var subnetAddressBytes = subnetAddress.GetAddressBytes();

        if (deviceAddressBytes.Length != subnetAddressBytes.Length)
            throw new ArgumentOutOfRangeException();

        var broadcastAddressBytes = new byte[deviceAddressBytes.Length];

        for (var i = 0; i < broadcastAddressBytes.Length; i++)
            broadcastAddressBytes[i] = (byte)(deviceAddressBytes[i] | subnetAddressBytes[i] ^ 255);

        return new IPAddress(broadcastAddressBytes);
    }

Again, I don't have any idea on why there is such difference in the behavior of the same API while running on different device families, but hopefully this code will help someone out there.

Upvotes: 0

Related Questions