1

I am having problem implementing SSDP discovery in windows 8 metro program. Below is the code:

public async Task SearchForDevices()
    {
        var socket = new DatagramSocket();
        socket.MessageReceived += async (sender, args) =>
                                            {
                                                Debug.WriteLine("Received data" + DateTime.Now);
                                                DataReader reader = args.GetDataReader();

                                                uint count = reader.UnconsumedBufferLength;
                                                string data = reader.ReadString(count);
                                                Debug.WriteLine(data);
                                                var response = new Dictionary<string, string>();
                                                foreach (
                                                    string x in
                                                        data.Split(new[] {"\r\n", "\n"}, StringSplitOptions.None))
                                                {
                                                    if (x.Contains(":"))
                                                    {
                                                        string[] strings = x.Split(':');
                                                        response.Add(strings[0].ToLower(), x.Remove(0, strings[0].Length + 1));
                                                    }
                                                }

                                                Device device = await GetXml(response);
                                                Debug.WriteLine("Device found");
                                                if (DeviceFound != null)
                                                    DeviceFound(this, new DeviceFoundEventArgs(device));
                                            };
        await socket.BindEndpointAsync(null, "");
        HostName hostName = new HostName("239.255.255.250");
        socket.JoinMulticastGroup(hostName);

        string message = "M-SEARCH * HTTP/1.1\r\n" +
                               "HOST: " + hostName.DisplayName + ":1900\r\n" +
                               "ST: upnp:rootdevice\r\n" +
                               "MAN: \"ssdp:discover\"\r\n" +
                               "MX: 3\r\n\r\n";

        DateTime start = DateTime.Now;
        TimeSpan interval = new TimeSpan(0, 0, 30);
        Debug.WriteLine(start);
        IOutputStream stream = await socket.GetOutputStreamAsync(hostName, "1900");
        var writer = new DataWriter(stream) { UnicodeEncoding = UnicodeEncoding.Utf8 };
        writer.WriteString(message);
        await writer.StoreAsync();
        await Task.Delay(1500);
    }

This code is not reliable at all. about 50% times it can't find a connected device while other discover can find. But sometimes it works.

My network sniffer (SmartSniff) sometimes can't even capture its SSDP request even though I have made the call many times.

I don't think this is an async problem since it does work occasionally. Please help me ! Thanks!

Hao Liu
  • 47
  • 6
  • I'm not certain you want to pass *hostName* into GetOutputStreamAsync. The fact that this is a multicast socket makes this a hard problem. But I think something else is afoot if you don't even see your "message" hit the wire with your packet sniffer. – selbie Dec 31 '12 at 11:26

3 Answers3

2

Try to bind the local endpoint to the IP address assigned to the local network adapter on which you want the UDP multicast request to be sent out.

The fact that you are not seeing the outgoing UDP packet with your packet sniffer makes me believe that the request is sent on a network interface different from the one that you are capturing on. I assume you have multiple network interfaces (e. g. Ethernet and WLAN). When dealing with multicast you have to make sure your requests are sent out on all network interfaces to physically reach all connected networks.

See also Query Local IP Address.

Community
  • 1
  • 1
candritzky
  • 351
  • 4
  • 11
0

I think you will have to force SocketOptionName.ReuseAddress on your socket. I can't explain why i think so, you are clearly not doing the same mistake as @Joern of trying to use port 1900 for the local endpoint. But it's the only difference i can see and his situation still applies: there is very likely another UPnP control point already running on your Windows box. Try disabling the UPnP service in Windows admin tools and see if your code runs more reliably.

Or try to rewrite the UDP socket establishing in @Joern's way. I am not a C# guru but it's always suspicious when certain APIs allow you to do the same thing in multiple different ways.

Community
  • 1
  • 1
Pavel Zdenek
  • 7,146
  • 1
  • 23
  • 38
  • No - entirely unnecessary. When doing M-SEARCH, any ephemeral local port is enough so ReuseAddress does nothing. – Nas Banov Mar 02 '16 at 22:15
0

If i am correctly guessing that await Task.Delay(1500); means you allow the task to run 1.5secs before finishing, then you had an interesting reason for the problem.

You see, "MX: 3" in M-SEARCH means "reply with random delay, up to 3 seconds". Given that you wait only 1.5 seconds, it makes sense that roughly 50% of responses are lost to you ;-)

Nas Banov
  • 28,347
  • 6
  • 48
  • 67