3

I am trying to Emulate Belkin wemo switch from my Home automation controller to send voice command from amazon Echo.The controller supports lua language.

I am following up this file to send the UDP data from port 1900 of Controller to port 50000 of Echo. right now every time i send the data the Socket take the random port send data not from port 1900. Echo only make valid connection and reply if the data comes from the port 1900. I am scratching my head from last two days to make is work but havent figured it out yet.

Bellow is my code.

strData1 =
  'HTTP/1.1 200 OK' .. 
 'HOST: 239.255.255.250:1900'..
 'CACHE-CONTROL: max-age=100'..
 'EXT:'..
 'LOCATION: http://192.168.1.152:49153/description.xml'..
 'SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.19.0'..
 'hue-bridgeid: B8AC6FFFFEC53475'..
 'ST: upnp:rootdevice'..
 'USN: uuid:2f402f80-da50-11e1-9b23-b8ac6fc53475::upnp:rootdevice'

 local socket = require "socket"
 local udp = socket.udp()

 udp:settimeout(0)
 udp:setsockname('*', 1900)
 udp:setpeername('192.168.1.102', 50000) -- Echo IP and Port number
 udp:sendto(strData1,'192.168.1.102',50000)
Prakash.DTI
  • 913
  • 2
  • 9
  • 19
  • 1
    First, I suggest you wrap all the `udp` function calls in `assert` in order to be sure that everything works fine. Second, you have set the timeout value to `0`, which means that it'll timeout every time. Set it to a positive value `udp:settimeout(1)` or to nil if you want it to block indefinitely. – kingJulian Jan 17 '18 at 16:49
  • changed the udp:settimeout(1) dint helped. Also put assert now i got the error it says "address already in use" when setting socket name(udp:setsockname('*', 1900)). How can i close the socket if system is running any? – Prakash.DTI Jan 18 '18 at 07:57
  • 1
    Based on [this](http://w3.impa.br/~diego/software/luasocket/reference.html) you have to use the `close` function. Also, I suggest you use that function in conjuction with `select` in order to get a list with the sockets ready for reading and a list with the sockets ready for writing. – kingJulian Jan 18 '18 at 09:01
  • @kingJulian where is “select” function? – Prakash.DTI Jan 18 '18 at 10:40
  • 1
    It's in the link but let's take this over to the [chat](https://chat.stackoverflow.com/rooms/163397/room-for-kingjulian-and-prakash-dti) – kingJulian Jan 18 '18 at 11:17

1 Answers1

1

You were almost there: the documentation states that when using setpeername, send must be used instead of sendto.

Also, I guess it was a typo, but you are trying to send Data instead of strData1. Here is the corrected version:

strData1 =
  'HTTP/1.1 200 OK' .. 
 'HOST: 239.255.255.250:1900'..
 'CACHE-CONTROL: max-age=100'..
 'EXT:'..
 'LOCATION: http://192.168.1.152:49153/description.xml'..
 'SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.19.0'..
 'hue-bridgeid: B8AC6FFFFEC53475'..
 'ST: upnp:rootdevice'..
 'USN: uuid:2f402f80-da50-11e1-9b23-b8ac6fc53475::upnp:rootdevice'

 local socket = require "socket"
 local udp = socket.udp()

 udp:settimeout(0)
 udp:setoption('reuseaddr',true)
 udp:setsockname('*', 1900)
 udp:setpeername('192.168.1.102', 50000) -- Echo IP and Port number
 udp:send(strData1)

Tcpdump's capture shows that the source port is correct:

22:40:45.653222 IP my.super.secret.ip.1900 > 192.168.1.102.50000: UDP, length 280

Prakash.DTI
  • 913
  • 2
  • 9
  • 19
Aif
  • 11,015
  • 1
  • 30
  • 44
  • 2
    You don't supply the IP:port to `send()`. The rule about send/sendto is strange. You can use either at the BSD Sockets level, but if connected you just don't supply the IP:port to `sendto()`: just a null address pointer. Maybe that's not possible in LUA source. – user207421 Jan 27 '18 at 22:07
  • I am getting error on this line “ udp:setsockname('*', 1900)”. It’s says “already running sockets on Port 1900”. I have not created any socket on port 1900.i don’t know the socket name so I cannot use the close() function. How can I get list of running socket? Or can we force close socket on port 1900? I can’t find anything in API:( – Prakash.DTI Jan 28 '18 at 04:19
  • 1
    @Prakash.DTI You *must* use the close function, and make whatever adjustments are necessary to make it possible. – user207421 Jan 28 '18 at 05:40
  • Normally we close the Socket that we initiated earlier like... udp = socket.udp()then we use the udp:close() to close the socket but the system that am working on is a linux home automation controller when i execute "udp:setsockname('*', 1900)" it says that socket already running on that Port. How do i get the Socket name to use the close() function on it? – Prakash.DTI Jan 28 '18 at 10:54
  • @Prakash.DTI what’s the output of netstat -laputen? – Aif Jan 28 '18 at 12:13
  • udp 0 0 0.0.0.0:1900 0.0.0.0:* 3970/director udp 0 0 0.0.0.0:1900 0.0.0.0:* 3970/director udp 0 0 0.0.0.0:1900 0.0.0.0:* 3473/sysmand udp 0 0 0.0.0.0:1900 0.0.0.0:* 3382/c4server udp 0 0 0.0.0.0:1902 0.0.0.0:* 3970/director – Prakash.DTI Jan 28 '18 at 12:19
  • 1
    It looks like you have a daemon listening on that port already. Either bind your private ip (rather than *) in the lua file, or make the daemon listen on a dedicated ip. Or to make it simpler, just kill those processes for your testing purpose. – Aif Jan 28 '18 at 12:22
  • if i do private ip like this.. `local socket = require "socket" udp= socket.udp() assert(udp:settimeout(1)) assert(udp:setsockname('192.168.1.106', 1900))` Output:address already in use – Prakash.DTI Jan 28 '18 at 12:32
  • `udp:setoption('reuseaddr',true)` is the solution. this will enable to use one port with Multiple Socket. @Aif for pointing me in right direction. Please also add this line to your answer. – Prakash.DTI Jan 28 '18 at 18:01
  • This is not working when using the TCP connection. even after setting the option 'reuseaddr'to 'true'i am getting 'address already in use' error. I know there is ngix server running on Port 80 but like my previous UDP connection how can i run two thread on same Port 80? `local socket = require "socket" local tcp = socket.tcp() local ControllersIP = C4: GetControllerNetworkAddress() tcp:settimeout(5) tcp:setoption('reuseaddr',true) assert(tcp:setsockname(ControllersIP, 80)) tcp:setpeername(EchoIP, 50000) tcp:send(file) tcp:close()` – Prakash.DTI Aug 29 '19 at 04:13