15

I created a small program to test UPnP Multicast (Visual C# 2010 Express, running on Windows 7 Professional 64 Bit). I can receive the UPnP NOTIFY Messages from UPnP Devices in my Network. But when i send the M-SEARCH Message, i get no Answers.

I have tested the same code on a iOS environment (Monotouch for iOS, running on a iPhone simulator on a Mac). There it runs fine and i get all the search responses from my UPnP devices. I can also see the M-SEARCH message from my windows program.

It looks like Windows (or a Firewall?) is hiding the search responses. Any idea?

Here is the code:

IPEndPoint LocalEndPoint = new IPEndPoint(IPAddress.Any, 1900);
IPEndPoint MulticastEndPoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900);

Socket UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpSocket.Bind(LocalEndPoint);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastEndPoint.Address, IPAddress.Any));
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);

Console.WriteLine("UDP-Socket setup done...\r\n");

string SearchString = "M-SEARCH * HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:3\r\n\r\n";

UdpSocket.SendTo(Encoding.UTF8.GetBytes(SearchString), SocketFlags.None, MulticastEndPoint);

Console.WriteLine("M-Search sent...\r\n");

byte[] ReceiveBuffer = new byte[64000];

int ReceivedBytes = 0;

while (true)
{
    if (UdpSocket.Available > 0)
    {
        ReceivedBytes = UdpSocket.Receive(ReceiveBuffer, SocketFlags.None);

        if (ReceivedBytes > 0)
        {
            Console.WriteLine(Encoding.UTF8.GetString(ReceiveBuffer, 0, ReceivedBytes));
        }
    }
}
H H
  • 263,252
  • 30
  • 330
  • 514
Jörn
  • 545
  • 1
  • 4
  • 11
  • What is MulticastEndPoint set to? – simonc Oct 09 '12 at 07:59
  • Are you sure that the M-SEARCH you see on iOS is the one from your Windows program? Have you tried another UPnP discovery tool on your Windows box? – Pavel Zdenek Oct 09 '12 at 14:25
  • @PavelZdenek: Yes I'm sure. I have attached some extra characters on the M-SEARCH message so I could recognize the message on iOS. – Jörn Oct 10 '12 at 06:06

3 Answers3

19

Yeah, I solved the problem! Small mistake, big impact:

My program is sending the M-SEARCH on port 1900 which is bound to the UPnP multicast group. Because i bound the LocalEndPoint to the same port, the UPnP devices answers with unicast to port 1900. On iOS it worked, because my program was the only service bound to this port. But on the PC, i found several services bound to port 1900 (found with "netstat -p UDP -a"). So the unicast messages from the UPnP devices was absorbed by one of the other services.

The solution: I bound the LocalEndPoint to a free port (e.g. 60000), and now it works fine!

IPEndPoint LocalEndPoint = new IPEndPoint(IPAddress.Any, 60000);
Jörn
  • 545
  • 1
  • 4
  • 11
  • 1
    You were faster than me :-) Yeah, Windows by default runs SSDP service. Have a look with netstat option -b – Pavel Zdenek Oct 10 '12 at 10:03
  • I have the same Problem but I can't change my Port. Is there any other way to fix this Problem? – Kingpin May 21 '14 at 09:02
  • 5
    Don't bind to a specific port (60000), just ask for an ephemeral (0)! Or one day this may fail because someone else is using 60000 – Nas Banov Mar 02 '16 at 22:23
5

On create of local endpoint use port 0 (zero) to bind a free port not using a fixed port. Another point discovered. Binding IPAddress.Any or IPAddress.Loopback get responses from Microsoft (local?) system where as binding to one of the LAN address(es) get responses from the local net. Getting first IPV4 address can be done like this:

IPAddress localNetwork = Dns.GetHostAddresses(Environment.GetEnvironmentVariable("COMPUTERNAME")).Where(ia => (ia.AddressFamily == AddressFamily.InterNetwork)).First();
VBWebProfi
  • 309
  • 3
  • 4
  • There is no really boundary to IPV4, I've found the IP V6 multicast addresses FF02::C (link-local), FF05::C (site-local), FF08::C (organization-local) and FF0E::C (global). Note that scope of IP V4 is site-local. Found at [Wikipedia - SSDP](https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol) – VBWebProfi Feb 10 '18 at 19:31
  • ``Environment.GetEnvironmentVariable("COMPUTERNAME")`` can be replaced by ``Environment.MachineName``. – VBWebProfi Feb 10 '18 at 19:35
  • Thanks for this one. IPAddress.Any was returning 0.0.0.0 for my machine and nothing was being sent/received (I have about 30 VPNs and other network adapters configured so that might be cause). – apc Oct 17 '18 at 15:14
1

For posterity: setting all these options above is unnecessary for M-SEARCH and might even be counter-productive:

UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(MulticastEndPoint.Address, IPAddress.Any));
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 2);
UdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);

So don't do it.

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