[ST Edge] UDP Broadcast Listener

I’m attempting to write a LAN edge driver where the device broadcasts a message over UDP whenever its state changes. However, I’m struggling to even get the UDP socket to receive messages when running on the hub. When I run basically the same code locally, it seems to work as I would expect.

Here is my listener code.

local udp = socket.udp()
assert(udp:setoption('broadcast', true)) -- Is this needed just for listening?
assert(udp:settimeout(2))
assert(udp:setsockname('*', 0)) -- Would love to specify port but I can't
local _, p = udp:getsockname() -- Instead, for now, grab the port that was assigned for testing purposes
log.debug('Listening on port ' .. p .. '...')

while true do
    local data, ip, port = udp:receivefrom()
    log.debug('Received from ' .. tostring(ip) .. ':' .. tostring(port) .. ' ' .. tostring(data))
end

When running on the hub, I only receive a message if I send a UDP message to the hub’s IP address and the generated port. If I send it to the broadcast IP (255.255.255.255) on the generated port, the message doesn’t show up. But, if I run locally on my machine, I get messages sent to either that machine IP or the broadcast IP.

It seems that when running on the hub, broadcast messages are ignored. Is this expected? Am I doing this all wrong?

Bonus question: Is there no way around passing 0 as the port number? Alternatively, is it possible to listen for UDP messages on all ports (this is a reach, I know).

You might take a look at what @TAustin has been doing… he’s been exploring a lot of the extra driver options.

Even more relevant to what you are doing than my web requestor driver is my UPnP control point library. It is on github if you want to take a look at it. UPnP uses the gamut of TCP, UDP and multicast communications so it’s all covered in there.

This is how I create a socket for SSDP-type discovery:

local multicast_ip = "239.255.255.250"
  local multicast_port = 1900
  local listen_ip = "0.0.0.0"
  local listen_port = 0
  
  local s = assert(socket.udp(), "create discovery socket")
  
  assert(s:setsockname(listen_ip, listen_port), "discovery socket setsockname")

Not sure if the broadcast IP you’re trying to use is functional on the hub. The above should work both on hub and off.

1 Like

@MrCapitalQ

My prior code snippet was for sending things out on the multicast address. I realized you probably really want this, which is how to listen on the multicast address:

-- initialize multicast socket
  m = assert(socket.udp(), "create discovery socket")
  assert(m:setoption('reuseaddr', true))
  assert(m:setsockname(multicast_ip, multicast_port))
  assert(m:setoption("ip-add-membership", {multiaddr = multicast_ip, interface = "0.0.0.0"}), "join multicast group")
  m:settimeout(0)
1 Like

I really appreciate you taking the time to reply and point me to your library as well as the code snippets you posted. Unfortunately I couldn’t get it to work. I suspect you’re onto something with your comment about not being sure if the broadcast IP is functional on the hub. I don’t really have control over that on the broadcasting device so I can’t address that.

The good news is I was able to accomplish my goal (pushing events to the hub) with a different mechanism that was available.

Again, super thankful for those that chimed in and much love for this community.

1 Like