Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
EnTerr
Level 9

Re: Command line Editing in Console?

"belltown" wrote:
One thing I wasn't really clear about was the "MX" header; I wasn't sure whether to leave it out, or if using it, what value to use for it. Maybe his devices are taking longer to respond to the SSDP requests, due to the number of devices, or network configuration, or something.

Ah, the MX header Smiley Happy. I know you are stickler for the specs, so you will enjoy this: according to SSDP, the MX header is REQUIRED and "If the search request does not contain an MX header, the device must silently discard and ignore the search request." Not so with Roku - it responds regardless if it's there - and the ECP doco actually codifies it will work w/o MX, based on the example (if they fix it now, it will break bunch of apps that believed the documentation verbatim, so better not to). I found said feature amusingly beneficial when issuing "ST: ssdp:all" - usually (with MX) i got storm of responses - routers, DirecTV - everybody reporting multiple upnp devices. Without MX though? - everybody but Roku shut up.

Also, until a few years ago there was this feature where sending SSDP with "MX: 0" would reboot Roku. All Rokus on the local network, really. Marvelous way to restart them all with a single packet. A datagram sealed with a kiss of death. A kill-a-gram?

I did notice during my own testing that there were times when one or more Rokus did not always respond to SSDP requests. I'd try again later then every device responded.

That's normal. UDP is short for "Unreliable Datagram Protocol" Smiley Tongue. The MX random delay was devised to decrease collisions but some loss or dupes will happen regardless.
0 Kudos
TheEndless
Level 7

Re: Command line Editing in Console?

"belltown" wrote:
It works fine discovering my Rokus, and I know at least one other person whose Rokus were also discovered. So far, TheEndless is the only one who's reported a problem with the discovery mechanism.

FWIW, here's the quick and dirty discovery code I used in my own similar (but not) telnet app I wrote in c# that works as expected on my network...
		private string[] getRokuIPAddresses(int timeout = 5000)
{
List<string> ips = new List<string>();
IPAddress localNetwork = Dns.GetHostAddresses(Environment.GetEnvironmentVariable("COMPUTERNAME")).Where(ia => (ia.AddressFamily == AddressFamily.InterNetwork)).First();
IPEndPoint localEndPoint = new IPEndPoint(localNetwork, 0);
IPEndPoint multicastEndPoint = new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900);

using (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:roku:ecp\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];
var now = DateTime.Now;
while ((DateTime.Now - now).TotalMilliseconds <= timeout)
{
if (udpSocket.Available > 0)
{
int receivedBytes = udpSocket.Receive(receiveBuffer, SocketFlags.None);
if (receivedBytes > 0)
{
var response = Encoding.UTF8.GetString(receiveBuffer, 0, receivedBytes);
var headers = response.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var header in headers)
{
if (header.StartsWith("Location:", StringComparison.OrdinalIgnoreCase))
{
var url = header.Substring(header.IndexOf(":") + 1).Trim();
var ip = new Uri(url).Host;
ips.Add(ip);
}
}
}
}
}
}
ips.Sort();
return ips.ToArray();
}

Note that I get the local computer's IP address from DNS, as I have multiple network adapters (wireless, wired, vmware, etc) and using IPAddress.Any wouldn't work for me. I wonder if that could be the issue with PurpleBug...
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
EnTerr
Level 9

Re: Command line Editing in Console?

"TheEndless" wrote:
Note that I get the local computer's IP address from DNS, as I have multiple network adapters (wireless, wired, vmware, etc) and using IPAddress.Any wouldn't work for me. I wonder if that could be the issue with PurpleBug...

That's probably it! Your PC is multi-homed (on multiple networks) so it's unclear through which interface the discovery should be sent. It's somewhat of a miracle that given code works for you - what's the reason to expect that `.first()` will return the right interface?

Looking further, there seem to be bunch of unnecessary (likely counter-productive) incantations like ReuseAddress (no need, since ephemeral port/0), AddMembership (no need, response comes as unicast), MulticastTimeToLive (no worries, you won't break Internet), MulticastLoopback (why would i want my own host to receive my cast). My view is the less customization one does to an item, the better the odds it to work now and in the future. I.e. do whatever tweaks needed to start working, then stop.

... and then i take exception to my rule by always sending "MX: 1" (in case it ever gets fixed). Hmm. The explanation is that i avoid poking things i don't fully understand (multicast options) but don't mind future-proofing things i have researched well. I think.
0 Kudos
TheEndless
Level 7

Re: Command line Editing in Console?

"EnTerr" wrote:
"TheEndless" wrote:
Note that I get the local computer's IP address from DNS, as I have multiple network adapters (wireless, wired, vmware, etc) and using IPAddress.Any wouldn't work for me. I wonder if that could be the issue with PurpleBug...

That's probably it! Your PC is multi-homed (on multiple networks) so it's unclear on which the discovery should be sent. It's somewhat of a miracle that given code works for you - what's the reason to expect that `.first()` will return the right interface?

Since it's querying DNS instead of just looking at the local network interfaces, the assumption is that DNS will only return the valid network IP, so .First() should always be valid.

"EnTerr" wrote:
Looking further, there seem to be bunch of unnecessary (likely counter-productive) incantations like ReuseAddress (no need, since ephemeral port/0), AddMembership (no need, response comes as unicast), MulticastTimeToLive (no worries, you won't break Internet), MulticastLoopback (why would i want my own host to receive my cast). My view is the less customization one does to an item, the better the odds it to work now and in the future. I.e. do whatever tweaks needed to start working, then stop. (And then i take exception to my rule by always sending "MX: 1", in case it ever gets fixed)

I have no answers/reasons for any of those. I got the majority of the broadcast code from an example I found online: http://stackoverflow.com/questions/1279 ... -discovery
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
EnTerr
Level 9

Re: Command line Editing in Console?

"TheEndless" wrote:
Since it's querying DNS instead of just looking at the local network interfaces, the assumption is that DNS will only return the valid network IP, so .First() should always be valid.

I did not say .first() will be invalid. Rather, it's a crapshoot whether the first IP you get is the one where the Rokus are.

Say your PC is 192.168.1.23 on one of the interfaces and 192.168.2.42 on the other - which one the discovery datagram should be sent to? The first is wired, the second is wireless (or the other way around. or they are all wired - it doesn't matter). I don't know on which segment your UPnP devices are and neither can the program. For extra fun, there might be Rokus on all segments.

For the outbound datagram, @belltown likely gets the preferred IP - and so it happens that's not where your Rokus are.

I have no answers/reasons for any of those. I got the majority of the broadcast code from an example I found online: http://stackoverflow.com/questions/1279 ... -discovery

Oh i see. The poor chap there was struggling to get the code working. I looked and I too couldn't find good, short C# examples of SSDP. Here is one more, this one uses async/await http://stackoverflow.com/questions/1409 ... t-reliable
0 Kudos
belltown
Level 7

Re: Command line Editing in Console?

"TheEndless" wrote:
"belltown" wrote:
It works fine discovering my Rokus, and I know at least one other person whose Rokus were also discovered. So far, TheEndless is the only one who's reported a problem with the discovery mechanism.

Note that I get the local computer's IP address from DNS, as I have multiple network adapters (wireless, wired, vmware, etc) and using IPAddress.Any wouldn't work for me. I wonder if that could be the issue with PurpleBug...


Thanks for the code. It's very similar to what I'm doing. You are correct that I'm using IPAddress.Any to determine the endpoint to which I bind to receive SSDP discovery responses. If the system picks an address corresponding to an adapter that does not support multicast (or an adapter connected to a subnet to which your Rokus are not attached), then the socket will not receive the SSDP packets, which is what I assume is happening.

You're using the default multicast adapter to transmit the SSDP discovery requests, as am I so far, the default multicast adapter being determined by the routing table. If this is the same adapter as that returned by a DNS lookup on the host machine, then the SSDP packets will be received by the same adapter that sent them. I assume that's what's happening in your case, otherwise it wouldn't work. The default multicast adapter, determined by the routing table, and the first DNS entry returned by a DNS lookup on the host computer are probably generally the same; the latter I believe starts with a DNS lookup on the preferred adapter's DNS server. I doubt that the default multicast adapter address and default host DNS address are guaranteed to be the same though.

What I might end up doing is iterating through the list of network interfaces, looking for an interface that is up and supports multicast and IPv4, and use that interface for the multicast transmissions, then bind to its IP address, so I'm guaranteed to get the SSDP packets sent from and received by the same interface.

I'm not too concerned about people having Rokus attached to different adapters on different subnets that aren't reachable by the SSDP request sent on the chosen interface. I suppose I could send out SSDP requests on all interfaces, but that doesn't seem worth it unless people start clamoring that they're in that situation and can't work around it by typing in their Rokus' IP addresses manually.

I'll implement the change to PurpleBug over the weekend when I implement the font-changing code.
https://github.com/belltown/
0 Kudos
EnTerr
Level 9

Re: Command line Editing in Console?

"belltown" wrote:
You're using the default multicast adapter to transmit the SSDP discovery requests, as am I so far, the default multicast adapter being determined by the routing table.

No. His code (originating from the linked SO) is not using the "default multicast adapter" (poetic license? the one with best route metric in reality) of yours. Rather, it binds to the 1st local IP looked up (via DNS in this case, albeit there is another way) and sends from there. Naturally listening on the same socket gets datagrams from the same network (you don't use 2 separate sockets, right? it would make no sense).

I'm not too concerned about people having Rokus attached to different adapters on different subnets that aren't reachable by the SSDP request sent on the chosen interface.

Then you needn't change anything since that's TheEndless's case - being on 2+ LANs at the same time and i bet so it happens the Rokus are on the interface with unfavorable metric (the WiFi? i won't mind looking at your "route print" if you want it investigated further).
0 Kudos
TheEndless
Level 7

Re: Command line Editing in Console?

"EnTerr" wrote:
"TheEndless" wrote:
Since it's querying DNS instead of just looking at the local network interfaces, the assumption is that DNS will only return the valid network IP, so .First() should always be valid.

I did not say .first() will be invalid. Rather, it's a crapshoot whether the first IP you get is the one where the Rokus are.

Hehe.. I think we got stuck in BrightScript land there for a second. By "valid/invalid", I didn't mean null.. I meant the one I needed. Looking through my network connections, my wired connection is the only one with a DNS server defined (and wireless, but that one isn't currently connected), so perhaps that's why it works. All I know for sure is that IPAddress.Any doesn't work on my network, and this code does. As I mentioned above, this was a quick and dirty solution for a small utility I wrote to make running r2d2_bitmaps and parsing its output easier. I only posted it to give belltown something to compare to, so he could potentially figure out why his code doesn't work for me...

"EnTerr" wrote:
I'm not too concerned about people having Rokus attached to different adapters on different subnets that aren't reachable by the SSDP request sent on the chosen interface.

Then you needn't change anything since that's TheEndless's case - being on 2+ LANs at the same time and i bet so it happens the Rokus are on the interface with unfavorable metric (the WiFi? i won't mind looking at your "route print" if you want it investigated further).

No, that is not my case. I have multiple network adapters, but I only use the wired ethernet connection for access to my network and the internet. Occasionally I may enable the wireless interface, bring up a VMWare machine, or connect to a VPN via Cisco AnyConnect, but none of those have anything to do with my Rokus. As this is intended as a tool for developers, I'd expect more complex network configurations to be more the norm than the exception (although, I would argue that mine is not more complex, as I haven't done any custom network configuration). In contrast, Eclipse's debug console is able to discover all of my Rokus, as are several different Roku remote apps I've installed, so this discovery issue, so far, is specific to PurpleBug.
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
0 Kudos
belltown
Level 7

Re: Command line Editing in Console?

"EnTerr" wrote:
"belltown" wrote:
You're using the default multicast adapter to transmit the SSDP discovery requests, as am I so far, the default multicast adapter being determined by the routing table.

No. His code (originating from the linked SO) is not using the "default multicast adapter" (poetic license? the one with best route metric in reality) of yours. Rather, it binds to the 1st local IP looked up (via DNS in this case, albeit there is another way) and sends from there.

I'm still trying to figure this socket stuff out. My understanding is that the socket used for binding only affects receipt of IP packets. In order to specify which network interface is used to send a multicast datagram, you need to specify the IP_MULTICAST_IF socket option.

From MSDN:

IP_MULTICAST_IF ... Gets or sets the outgoing interface for sending IPv4 multicast traffic. This option does not change the default interface for receiving IPv4 multicast traffic.

The input value for setting this option is a 4-byte IPv4 address in network byte order. This DWORD parameter can also be an interface index in network byte order. Any IP address in the 0.x.x.x block (first octet of 0) except IPv4 address 0.0.0.0 is treated as an interface index. An interface index is a 24-bit number, and the 0.0.0.0/8 IPv4 address block is not used (this range is reserved). The interface index can be used to specify the default interface for multicast traffic for IPv4. If optval is zero , the default interface for receiving multicast is specified for sending multicast traffic.


From MSDN:

The default interface used for IPv4 multicast is determined by the networking stack in Windows. An application can determine the default interface used for IPv4 multicast using the GetIpForwardTable function to retrieve the IPv4 routing table. The network interface with the lowest value for the routing metric for a destination IP address of 224.0.0.0 is the default interface for IPv4 multicast. The routing table can also be displayed from the command prompt with the following command: route print. The IP_MULTICAST_IF socket option can be used to set the default interface to send IPv4 multicast packets.


From MSDN:

Each multicast transmission is sent from a single network interface, even if the host has more than one multicast-capable interface. A socket option is available to override the default for subsequent transmissions from a given socket. For example ... (IP_MULTICAST_IF example) ... An address of INADDR_ANY may be used to revert to the default interface. Note that this address might be different from the one the socket is bound to.



From a Stack Overflow post:

The IP_MULTICAST_IF or IPV6_MULTICAST_IF settings tell your socket which interface to send its multicast packets on. It's a separate, independent setting from the interface that you bound your socket to with bind(), since bind() controls which interface(s) the socket receives multicast packets from.


It wouldn't surprise me if there's something I'm missing here though.
https://github.com/belltown/
0 Kudos
EnTerr
Level 9

Re: Command line Editing in Console?

"TheEndless" wrote:
"EnTerr" wrote:
I did not say .first() will be invalid. Rather, it's a crapshoot whether the first IP you get is the one where the Rokus are.
Hehe.. I think we got stuck in BrightScript land there for a second. By "valid/invalid", I didn't mean null.. I meant the one I needed.
That's exactly what i meant too, no confusion there. I say you were lucky .first() was giving the IP you needed but the result may be different. Why don't you do the simple experiment of printing all results (foreach), instead of the 1st only? That may shed some light. (if there is only 1 result returned and PurpleBug still does not discover, then i was wrong. Simple)

Looking through my network connections, my wired connection is the only one with a DNS server defined (and wireless, but that one isn't currently connected), so perhaps that's why it works.
I doubt that because that DNS server won't actually be consulted. Instead the DNS resolver library sorts it out internally (it might also use the etc/hosts file and WINS). You may feel the resolver would give undue preference to the IP with DNS but that doesn't sound right either.

All I know for sure is that IPAddress.Any doesn't work on my network, and this code does. As I mentioned above, this was a quick and dirty solution for a small utility I wrote to make running r2d2_bitmaps and parsing its output easier. I only posted it to give belltown something to compare to, so he could potentially figure out why his code doesn't work for me...
He cannot reproduce your unique circumstances (i.e. make P-B not discover) and just staring at the code so far did not lead to agreement. Why don't you PM me your "route print" results? Maybe i find proof - or i back-pedal - or well, maybe nothing.

... Occasionally I may enable the wireless interface, bring up a VMWare machine, or connect to a VPN via Cisco AnyConnect, but none of those have anything to do with my Rokus.
Oh - Cisco AnyConnect, you say? I wouldn't put it past it to <expletive> up the network configuration, knowing what it is known for doing.

As this is intended as a tool for developers, I'd expect more complex network configurations to be more the norm than the exception (although, I would argue that mine is not more complex, as I haven't done any custom network configuration). In contrast, Eclipse's debug console is able to discover all of my Rokus, as are several different Roku remote apps I've installed, so this discovery issue, so far, is specific to PurpleBug.
You are right in that developers' machines will tend to have hairier network configs (the mere fact of VM or VPN see to that). Let's not forget P-B is a gift horse though, shan't stare too long in its UPnP mouth. As of me - i am got engaged because of the mystery it not working for you, since i like solving puzzles.
0 Kudos