Hello everyone, I am currently trying to get a list of UPnP device via SSDP (Simple Service Discovery Protocol). A minimalistic working NodeJS example looks like this: var dgram = require('dgram'); var message = new Buffer( "M-SEARCH * HTTP/1.1\r\n" + "HOST:239.255.255.250:1900\r\n" + "MAN:\"ssdp:discover\"\r\n" + "ST:ssdp:all\r\n" + "MX:1\r\n" + "\r\n" ); var client = dgram.createSocket("udp4"); client.on("message", function (msg, rinfo) { console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port); }); client.send(message, 0, message.length, 1900, "239.255.255.250"); client.close(); I tried to recreate the same functionality in Pharo with the following piece of code: | message udpSocket host | message := 'M-SEARCH * HTTP/1.1\r\n' , 'HOST:239.255.255.250:1900\r\n' , 'MAN:"ssdp:discover"\r\n' , 'ST:ssdp:all\r\n' , 'MX:1\r\n' , '\r\n'. udpSocket := Socket newUDP. host := (NetNameResolver addressFromString: '239.255.255.250'). udpSocket sendData: message toHost: host port: 1900. "udpSocket waitForData." Transcript show: 'Received: ' , udpSocket receiveData. udpSocket closeAndDestroy. Unfortunately, this script hangs both in Pharo3 and Pharo4 (OS X 10.10, Pharo 30856 and 40611). When I interrupt with Cmd+. the debugger shows the method Socket>>waitForDataIfClosed: and the hang is apparently in the line self readSemaphore wait Could anyone give me some advice if I should to do this differently or what the issue with the Pharo script is? Thanks in advance, Manfred
Hi Manfred, Did you see/study the example/test UDPSocketEchoTest ? Also, UDP is very primitive: it is send and forget, returns no errors, and is totally asynchronous. Listening should best be done in a separate process. Here is how I would write your send part: | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' ''). udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 250] port: 1900. udpSocket waitForSendDoneFor: 5. udpSocket closeAndDestroy. Maybe nothing came back because the line ends where wrong ? HTH, Sven
On 18 May 2015, at 11:29, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hello everyone,
I am currently trying to get a list of UPnP device via SSDP (Simple Service Discovery Protocol).
A minimalistic working NodeJS example looks like this:
var dgram = require('dgram'); var message = new Buffer( "M-SEARCH * HTTP/1.1\r\n" + "HOST:239.255.255.250:1900\r\n" + "MAN:\"ssdp:discover\"\r\n" + "ST:ssdp:all\r\n" + "MX:1\r\n" + "\r\n" );
var client = dgram.createSocket("udp4");
client.on("message", function (msg, rinfo) { console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port); }); client.send(message, 0, message.length, 1900, "239.255.255.250"); client.close();
I tried to recreate the same functionality in Pharo with the following piece of code:
| message udpSocket host | message := 'M-SEARCH * HTTP/1.1\r\n' , 'HOST:239.255.255.250:1900\r\n' , 'MAN:"ssdp:discover"\r\n' , 'ST:ssdp:all\r\n' , 'MX:1\r\n' , '\r\n'.
udpSocket := Socket newUDP. host := (NetNameResolver addressFromString: '239.255.255.250'). udpSocket sendData: message toHost: host port: 1900. "udpSocket waitForData." Transcript show: 'Received: ' , udpSocket receiveData. udpSocket closeAndDestroy.
Unfortunately, this script hangs both in Pharo3 and Pharo4 (OS X 10.10, Pharo 30856 and 40611). When I interrupt with Cmd+. the debugger shows the method Socket>>waitForDataIfClosed: and the hang is apparently in the line self readSemaphore wait
Could anyone give me some advice if I should to do this differently or what the issue with the Pharo script is?
Thanks in advance, Manfred
Hello Sven, thanks for your fast reply. On Mon, May 18, 2015 at 11:41 AM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
Hi Manfred,
Did you see/study the example/test UDPSocketEchoTest ?
unfortunately I did not see this class, yet. But I did look at the Socket class itself and Socket>>timeTestUDP (in Pharo3).
Also, UDP is very primitive: it is send and forget, returns no errors, and is totally asynchronous. Listening should best be done in a separate process.
Yes, UDP is primitive but the SSDP specification requires using UDP. Here is how I would write your send part:
| message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 250] port: 1900. udpSocket waitForSendDoneFor: 5. udpSocket closeAndDestroy.
Thanks for this snippet. For some reasons I do not understand yet, this gives me the expected result in contrast to my own version. I modified it like this to print the results on the Transcript: | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover"' 'ST:ssdp:all' 'MX:1' ''). udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 250] port: 1900. udpSocket waitForSendDoneFor: 5. udpSocket waitForData. [udpSocket dataAvailable ] whileTrue: [ | buffer | buffer := ByteArray new: 1024. udpSocket receiveUDPDataInto: buffer. Transcript show: 'Received: ', buffer. [udpSocket waitForDataFor: 1] on: Error do: [ ]. ]. udpSocket closeAndDestroy. Currently, this will work for me, since I am not interested in continuously detecting new devices. But you mentioned reading should in general be done in a separate process. Would you reuse the existing udpSocket instance in this case or create a separate one for reading? Maybe nothing came back because the line ends where wrong ?
The lineendings I used are required by the SSDP specification.
HTH,
Sven
Thanks, Manfred
On 18 May 2015, at 11:29, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hello everyone,
I am currently trying to get a list of UPnP device via SSDP (Simple Service Discovery Protocol).
A minimalistic working NodeJS example looks like this:
var dgram = require('dgram'); var message = new Buffer( "M-SEARCH * HTTP/1.1\r\n" + "HOST:239.255.255.250:1900\r\n" + "MAN:\"ssdp:discover\"\r\n" + "ST:ssdp:all\r\n" + "MX:1\r\n" + "\r\n" );
var client = dgram.createSocket("udp4");
client.on("message", function (msg, rinfo) { console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port); }); client.send(message, 0, message.length, 1900, "239.255.255.250"); client.close();
I tried to recreate the same functionality in Pharo with the following piece of code:
| message udpSocket host | message := 'M-SEARCH * HTTP/1.1\r\n' , 'HOST:239.255.255.250:1900\r\n' , 'MAN:"ssdp:discover"\r\n' , 'ST:ssdp:all\r\n' , 'MX:1\r\n' , '\r\n'.
udpSocket := Socket newUDP. host := (NetNameResolver addressFromString: '239.255.255.250'). udpSocket sendData: message toHost: host port: 1900. "udpSocket waitForData." Transcript show: 'Received: ' , udpSocket receiveData. udpSocket closeAndDestroy.
Unfortunately, this script hangs both in Pharo3 and Pharo4 (OS X 10.10, Pharo 30856 and 40611). When I interrupt with Cmd+. the debugger shows the method Socket>>waitForDataIfClosed: and the hang is apparently in the line self readSemaphore wait
Could anyone give me some advice if I should to do this differently or what the issue with the Pharo script is?
Thanks in advance, Manfred
On 18 May 2015, at 12:44, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hello Sven,
thanks for your fast reply.
On Mon, May 18, 2015 at 11:41 AM, Sven Van Caekenberghe <sven@stfx.eu> wrote: Hi Manfred,
Did you see/study the example/test UDPSocketEchoTest ?
unfortunately I did not see this class, yet. But I did look at the Socket class itself and Socket>>timeTestUDP (in Pharo3).
We removed #timeTestUDP in Pharo 4 and higher, I believe, and replaced it with proper tests/examples.
Also, UDP is very primitive: it is send and forget, returns no errors, and is totally asynchronous. Listening should best be done in a separate process.
Yes, UDP is primitive but the SSDP specification requires using UDP.
Here is how I would write your send part:
| message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 250] port: 1900. udpSocket waitForSendDoneFor: 5. udpSocket closeAndDestroy.
Thanks for this snippet. For some reasons I do not understand yet, this gives me the expected result in contrast to my own version.
I modified it like this to print the results on the Transcript:
| message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover"' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 250] port: 1900. udpSocket waitForSendDoneFor: 5. udpSocket waitForData. [udpSocket dataAvailable ] whileTrue: [ | buffer | buffer := ByteArray new: 1024. udpSocket receiveUDPDataInto: buffer. Transcript show: 'Received: ', buffer. [udpSocket waitForDataFor: 1] on: Error do: [ ]. ]. udpSocket closeAndDestroy.
Currently, this will work for me, since I am not interested in continuously detecting new devices. But you mentioned reading should in general be done in a separate process. Would you reuse the existing udpSocket instance in this case or create a separate one for reading?
I think if it is only for a one time use, it is OK like you are doing it.
Maybe nothing came back because the line ends where wrong ?
The lineendings I used are required by the SSDP specification.
I meant that writing '\r\n' has no effect in Pharo, this is not processed (you could do this manually, of course). This is why I did it with the #join: That is the difference and why it works now, I guess.
HTH,
Sven
Thanks, Manfred
On 18 May 2015, at 11:29, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hello everyone,
I am currently trying to get a list of UPnP device via SSDP (Simple Service Discovery Protocol).
A minimalistic working NodeJS example looks like this:
var dgram = require('dgram'); var message = new Buffer( "M-SEARCH * HTTP/1.1\r\n" + "HOST:239.255.255.250:1900\r\n" + "MAN:\"ssdp:discover\"\r\n" + "ST:ssdp:all\r\n" + "MX:1\r\n" + "\r\n" );
var client = dgram.createSocket("udp4");
client.on("message", function (msg, rinfo) { console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port); }); client.send(message, 0, message.length, 1900, "239.255.255.250"); client.close();
I tried to recreate the same functionality in Pharo with the following piece of code:
| message udpSocket host | message := 'M-SEARCH * HTTP/1.1\r\n' , 'HOST:239.255.255.250:1900\r\n' , 'MAN:"ssdp:discover"\r\n' , 'ST:ssdp:all\r\n' , 'MX:1\r\n' , '\r\n'.
udpSocket := Socket newUDP. host := (NetNameResolver addressFromString: '239.255.255.250'). udpSocket sendData: message toHost: host port: 1900. "udpSocket waitForData." Transcript show: 'Received: ' , udpSocket receiveData. udpSocket closeAndDestroy.
Unfortunately, this script hangs both in Pharo3 and Pharo4 (OS X 10.10, Pharo 30856 and 40611). When I interrupt with Cmd+. the debugger shows the method Socket>>waitForDataIfClosed: and the hang is apparently in the line self readSemaphore wait
Could anyone give me some advice if I should to do this differently or what the issue with the Pharo script is?
Thanks in advance, Manfred
Thanks for the explanation. Best, Manfred On Mon, May 18, 2015 at 12:49 PM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 18 May 2015, at 12:44, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hello Sven,
thanks for your fast reply.
On Mon, May 18, 2015 at 11:41 AM, Sven Van Caekenberghe <sven@stfx.eu> wrote: Hi Manfred,
Did you see/study the example/test UDPSocketEchoTest ?
unfortunately I did not see this class, yet. But I did look at the Socket class itself and Socket>>timeTestUDP (in Pharo3).
We removed #timeTestUDP in Pharo 4 and higher, I believe, and replaced it with proper tests/examples.
Also, UDP is very primitive: it is send and forget, returns no errors, and is totally asynchronous. Listening should best be done in a separate process.
Yes, UDP is primitive but the SSDP specification requires using UDP.
Here is how I would write your send part:
| message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 250] port: 1900. udpSocket waitForSendDoneFor: 5. udpSocket closeAndDestroy.
Thanks for this snippet. For some reasons I do not understand yet, this gives me the expected result in contrast to my own version.
I modified it like this to print the results on the Transcript:
| message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover"' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 250] port: 1900. udpSocket waitForSendDoneFor: 5. udpSocket waitForData. [udpSocket dataAvailable ] whileTrue: [ | buffer | buffer := ByteArray new: 1024. udpSocket receiveUDPDataInto: buffer. Transcript show: 'Received: ', buffer. [udpSocket waitForDataFor: 1] on: Error do: [ ]. ]. udpSocket closeAndDestroy.
Currently, this will work for me, since I am not interested in continuously detecting new devices. But you mentioned reading should in general be done in a separate process. Would you reuse the existing udpSocket instance in this case or create a separate one for reading?
I think if it is only for a one time use, it is OK like you are doing it.
Maybe nothing came back because the line ends where wrong ?
The lineendings I used are required by the SSDP specification.
I meant that writing '\r\n' has no effect in Pharo, this is not processed (you could do this manually, of course). This is why I did it with the #join:
That is the difference and why it works now, I guess.
HTH,
Sven
Thanks, Manfred
On 18 May 2015, at 11:29, Manfred Kröhnert < mkroehnert42@googlemail.com> wrote:
Hello everyone,
I am currently trying to get a list of UPnP device via SSDP (Simple Service Discovery Protocol).
A minimalistic working NodeJS example looks like this:
var dgram = require('dgram'); var message = new Buffer( "M-SEARCH * HTTP/1.1\r\n" + "HOST:239.255.255.250:1900\r\n" + "MAN:\"ssdp:discover\"\r\n" + "ST:ssdp:all\r\n" + "MX:1\r\n" + "\r\n" );
var client = dgram.createSocket("udp4");
client.on("message", function (msg, rinfo) { console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port); }); client.send(message, 0, message.length, 1900, "239.255.255.250"); client.close();
I tried to recreate the same functionality in Pharo with the following piece of code:
| message udpSocket host | message := 'M-SEARCH * HTTP/1.1\r\n' , 'HOST:239.255.255.250:1900\r\n' , 'MAN:"ssdp:discover"\r\n' , 'ST:ssdp:all\r\n' , 'MX:1\r\n' , '\r\n'.
udpSocket := Socket newUDP. host := (NetNameResolver addressFromString: '239.255.255.250'). udpSocket sendData: message toHost: host port: 1900. "udpSocket waitForData." Transcript show: 'Received: ' , udpSocket receiveData. udpSocket closeAndDestroy.
Unfortunately, this script hangs both in Pharo3 and Pharo4 (OS X 10.10, Pharo 30856 and 40611). When I interrupt with Cmd+. the debugger shows the method Socket>>waitForDataIfClosed: and the hang is apparently in the line self readSemaphore wait
Could anyone give me some advice if I should to do this differently or what the issue with the Pharo script is?
Thanks in advance, Manfred
On Mon, May 18, 2015 at 6:49 PM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
I meant that writing '\r\n' has no effect in Pharo, this is not processed (you could do this manually, of course).
Is this something we should consider implementing to ease the way for newcomers? What downsides can you think of? cheers -ben
On 18 May 2015, at 14:31, Ben Coman <btc@openinworld.com> wrote:
On Mon, May 18, 2015 at 6:49 PM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
I meant that writing '\r\n' has no effect in Pharo, this is not processed (you could do this manually, of course).
Is this something we should consider implementing to ease the way for newcomers? What downsides can you think of? cheers -ben
Nah, even in C, you need (s)printf for escape sequences to be interpreted. In any case, without error handling, this will do: | input escapes | escapes := { $n -> Character cr. $r -> Character lf. $\ -> $\ } asDictionary. input := 'foo\\bar\n\r'. String streamContents: [ :out | | in ch | in := input readStream. [ in atEnd ] whileFalse: [ ch := in next. ch = $\ ifTrue: [ out nextPut: (escapes at: in next) ] ifFalse: [ out nextPut: ch ] ] ] Sven
Hi, apparently I am missing something else. I can find devices when connected to a 'regular' LAN. However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . Any further ideas? Thanks, Manfred
On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi, apparently I am missing something else.
I can find devices when connected to a 'regular' LAN.
However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: .
Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
Thanks, Manfred
Hi Sven, On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi, apparently I am missing something else.
I can find devices when connected to a 'regular' LAN.
However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: .
Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well. Manfred
On 18 May 2015, at 16:34, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi, apparently I am missing something else.
I can find devices when connected to a 'regular' LAN.
However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: .
Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
I don't know then, I used the UDP stuff before in various applications and it worked fine. Just like with all networking code, you sometimes get in a stuck state when developing (i.e. running incomplete code). Getting stuck means you are waiting forever for an answer that is not coming.
From a distance I can't help much more, just double check that your initial message is completely correct and that you send it to the right host:port.
Sven
On 18 May 2015, at 4:44 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 18 May 2015, at 16:34, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi, apparently I am missing something else.
I can find devices when connected to a 'regular' LAN.
However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: .
Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
The socket API is a bit confusing, since it mixes together the API's that match the primitives for sending/receiving TCP/UDP. To receive UDP data on the socket, you need something like: | message udpSocket host buffer read| message := (String crlf join: #('M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover"' 'ST:ssdp:all' 'MX:1')). udpSocket := Socket newUDP. host := (NetNameResolver addressFromString: '239.255.255.250'). udpSocket sendData: message toHost: host port: 1900. buffer := String new:4096. "MX:1 means we expect replies within 1 second, let's be on the safe side and wait 2" 2 seconds wait. read := 1. [read > 0] whileTrue: [ read := (udpSocket receiveUDPDataInto: buffer) first. Transcript show: (buffer copyFrom:1 to:read)] Cheers, Henry
Hupps, was reading the old code, I guess this isn't applicable. Sorry :/
On 18 May 2015, at 5:15 , Henrik Johansen <henrik.s.johansen@veloxit.no> wrote:
On 18 May 2015, at 4:44 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 18 May 2015, at 16:34, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com> wrote:
Hi, apparently I am missing something else.
I can find devices when connected to a 'regular' LAN.
However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: .
Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
The socket API is a bit confusing, since it mixes together the API's that match the primitives for sending/receiving TCP/UDP. To receive UDP data on the socket, you need something like:
| message udpSocket host buffer read| message := (String crlf join: #('M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover"' 'ST:ssdp:all' 'MX:1')).
udpSocket := Socket newUDP. host := (NetNameResolver addressFromString: '239.255.255.250'). udpSocket sendData: message toHost: host port: 1900. buffer := String new:4096. "MX:1 means we expect replies within 1 second, let's be on the safe side and wait 2" 2 seconds wait. read := 1. [read > 0] whileTrue: [ read := (udpSocket receiveUDPDataInto: buffer) first. Transcript show: (buffer copyFrom:1 to:read)]
Cheers, Henry
Hi Manfred, I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255). So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options. You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g. socket setOption: 'IP_MULTICAST_IF' value: multicastInterface. If I do remember correctly you have to set the following options for sending/receiving: Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL) Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended. Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP) Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested). imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq. Hope this helps. CU, Udo On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
Hello Udo, thanks for your detailed reply. I am going to try your suggestions and report back afterwards. Not sure though if I get to try it before next weekend. The address I am sending to is definitely a multi-cast address (as defined in the SSDP spec). But what makes me wonder is why the minimal NodeJS example works in both cases without modifications (regular router/accesspoint + camera accesspoint) and the Pharo one only receives data in the first case. But maybe there is something happening behind the curtains in NodeJS when it comes to multi-cast addresses. Thanks, Manfred On Mon, May 18, 2015 at 11:29 PM, Udo Schneider < udo.schneider@homeaddress.de> wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
This should have been 'IP_ADD_MEMBERSHIP' of course: imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group: [ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork. The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' ''). udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy. Hope this helps. CU, Udo On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
Ultimate fallback, use Wireshark to compare packets on the wire between using node.js and Pharo. http://en.wikiversity.org/wiki/Wireshark/IPv4_multicast cheers -ben On Tue, May 19, 2015 at 6:17 AM, Udo Schneider <udo.schneider@homeaddress.de
wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
True - having Wireshark is always a good idea. Just a warning in the multicast context though: The fact that Wireshark sees multicast datagrams (when recieving) does only imply that your NIC is in promiscuous mode or that /a/ process on the node did subscribe to the multicast group. It does not necessarily mean that /your/ process will get the datagram via it's socket. Debugging multicast is a little bit tricky. With unicast or broadcast datagrams (doesn't matter if Ethernet or IP) it's quite easy: The NIC accepts every Broadcast L2 datagram and forwards it to the IP stack which processes every L3 broadcast datagram. For unicast the NIC only accepts datagrams sent to it's MAC address and the IP stack only processes them when sent to (one if) it's IP addresses. With multicast being "something in between" you have to convince the NIC (IP Multicast addresses map to specific Ethernet MACs) and the IP Stack to process the datagram although it's neither directly sent to their MAC/IP nor a broadcast. CU, Udo On 19/05/15 04:17, Ben Coman wrote:
Ultimate fallback, use Wireshark to compare packets on the wire between using node.js and Pharo. http://en.wikiversity.org/wiki/Wireshark/IPv4_multicast cheers -ben
On Tue, May 19, 2015 at 6:17 AM, Udo Schneider <udo.schneider@homeaddress.de <mailto:udo.schneider@homeaddress.de>> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900 <http://239.255.255.250:1900>' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu> <mailto:sven@stfx.eu <mailto:sven@stfx.eu>>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>
<mailto:mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
Hi Udo, It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected. I do think making all this cross platform could be a bit harder, we'll see. Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
Hi Sven, you got me :-) I had this as a package sometime ago for my own purposes (mDNS). So I knew it does work and how to do it. It's just I can't find that damned package anymore...
I do think making all this cross platform could be a bit harder, we'll see. It's not that hard. The socket API is the same on all supported platforms. No surprises on *nix based OS. The only exception is Windows where the API is the same but where you might run into some packet drops due to strange personal FW products and "value-add" NDIS drivers for NICs. The situation has gotten much better though since Windows Vista/7 are using multicast for some of their services out of the box.
I will recreate it though. Should I simply publish a package or add this as a slice? Best Regards, Udo On 19/05/15 10:20, Sven Van Caekenberghe wrote:
Hi Udo,
It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected.
I do think making all this cross platform could be a bit harder, we'll see.
Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
On 19 May 2015, at 10:30, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Hi Sven,
you got me :-)
I had this as a package sometime ago for my own purposes (mDNS). So I knew it does work and how to do it. It's just I can't find that damned package anymore...
Did you look in all your package caches ?
I do think making all this cross platform could be a bit harder, we'll see. It's not that hard. The socket API is the same on all supported platforms. No surprises on *nix based OS. The only exception is Windows where the API is the same but where you might run into some packet drops due to strange personal FW products and "value-add" NDIS drivers for NICs. The situation has gotten much better though since Windows Vista/7 are using multicast for some of their services out of the box.
I will recreate it though. Should I simply publish a package or add this as a slice?
Thanks a lot, Udo, a good multicast example would be super cool. If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice. If it is larger and more application/framework oriented, then maybe a standalone package is more interesting. We try to keep the image as modular as possible. This route would be a bit more work for you, but might make more sense if you also see it possibly growing in the future.
Best Regards,
Udo
On 19/05/15 10:20, Sven Van Caekenberghe wrote:
Hi Udo,
It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected.
I do think making all this cross platform could be a bit harder, we'll see.
Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
Did you look in all your package caches ? I did. Must have been a victim of cleaning ... but maybe TimeMachine has something ... thanks for the reminder.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice. The package was pretty simple. Basically only adding a few convenience methods around Socket>>#setOption:value: . Still I think a usage example in form of a class comment and test case might be appropriate. So unless Multicast should be part of the base image I'll start with a separate package first.
CU, udo On 19/05/15 10:38, Sven Van Caekenberghe wrote:
On 19 May 2015, at 10:30, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Hi Sven,
you got me :-)
I had this as a package sometime ago for my own purposes (mDNS). So I knew it does work and how to do it. It's just I can't find that damned package anymore...
Did you look in all your package caches ?
I do think making all this cross platform could be a bit harder, we'll see. It's not that hard. The socket API is the same on all supported platforms. No surprises on *nix based OS. The only exception is Windows where the API is the same but where you might run into some packet drops due to strange personal FW products and "value-add" NDIS drivers for NICs. The situation has gotten much better though since Windows Vista/7 are using multicast for some of their services out of the box.
I will recreate it though. Should I simply publish a package or add this as a slice?
Thanks a lot, Udo, a good multicast example would be super cool.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice.
If it is larger and more application/framework oriented, then maybe a standalone package is more interesting. We try to keep the image as modular as possible. This route would be a bit more work for you, but might make more sense if you also see it possibly growing in the future.
Best Regards,
Udo
On 19/05/15 10:20, Sven Van Caekenberghe wrote:
Hi Udo,
It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected.
I do think making all this cross platform could be a bit harder, we'll see.
Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
On 19 May 2015, at 10:53, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Did you look in all your package caches ? I did. Must have been a victim of cleaning ... but maybe TimeMachine has something ... thanks for the reminder.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice. The package was pretty simple. Basically only adding a few convenience methods around Socket>>#setOption:value: . Still I think a usage example in form of a class comment and test case might be appropriate. So unless Multicast should be part of the base image I'll start with a separate package first.
Since Socket is a fundamental part, and multicast is a key feature, I think it would logical to move it to the image itself, with a test case.
CU,
udo
On 19/05/15 10:38, Sven Van Caekenberghe wrote:
On 19 May 2015, at 10:30, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Hi Sven,
you got me :-)
I had this as a package sometime ago for my own purposes (mDNS). So I knew it does work and how to do it. It's just I can't find that damned package anymore...
Did you look in all your package caches ?
I do think making all this cross platform could be a bit harder, we'll see. It's not that hard. The socket API is the same on all supported platforms. No surprises on *nix based OS. The only exception is Windows where the API is the same but where you might run into some packet drops due to strange personal FW products and "value-add" NDIS drivers for NICs. The situation has gotten much better though since Windows Vista/7 are using multicast for some of their services out of the box.
I will recreate it though. Should I simply publish a package or add this as a slice?
Thanks a lot, Udo, a good multicast example would be super cool.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice.
If it is larger and more application/framework oriented, then maybe a standalone package is more interesting. We try to keep the image as modular as possible. This route would be a bit more work for you, but might make more sense if you also see it possibly growing in the future.
Best Regards,
Udo
On 19/05/15 10:20, Sven Van Caekenberghe wrote:
Hi Udo,
It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected.
I do think making all this cross platform could be a bit harder, we'll see.
Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
On 19 May 2015, at 11:01 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 19 May 2015, at 10:53, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Did you look in all your package caches ? I did. Must have been a victim of cleaning ... but maybe TimeMachine has something ... thanks for the reminder.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice. The package was pretty simple. Basically only adding a few convenience methods around Socket>>#setOption:value: . Still I think a usage example in form of a class comment and test case might be appropriate. So unless Multicast should be part of the base image I'll start with a separate package first.
Since Socket is a fundamental part, and multicast is a key feature, I think it would logical to move it to the image itself, with a test case.
It's not just multicast... As a Socket newbie I recently spent longer than I care to admit learning you need to set SO_BROADCAST to true to not get a primitive failure when sending to a broadcast address. At least the comments in sqUnixSocket were entertaining! Though I realize which options are actually supported depends on the VM, moving the list of potentially available cross-platform options (and a description of what they're used for) to a comment in the image (setOption: value: being the obvious location) might be a nice first step. Cheers, Henry P.S. On the plus side, I'm now able to turn my PC into a better remote for multi-cam GoPro setups than the GoPro remote itself is :)
On 29 May 2015, at 18:23, Henrik Johansen <henrik.s.johansen@veloxit.no> wrote:
On 19 May 2015, at 11:01 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 19 May 2015, at 10:53, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Did you look in all your package caches ? I did. Must have been a victim of cleaning ... but maybe TimeMachine has something ... thanks for the reminder.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice. The package was pretty simple. Basically only adding a few convenience methods around Socket>>#setOption:value: . Still I think a usage example in form of a class comment and test case might be appropriate. So unless Multicast should be part of the base image I'll start with a separate package first.
Since Socket is a fundamental part, and multicast is a key feature, I think it would logical to move it to the image itself, with a test case.
It's not just multicast... As a Socket newbie I recently spent longer than I care to admit learning you need to set SO_BROADCAST to true to not get a primitive failure when sending to a broadcast address. At least the comments in sqUnixSocket were entertaining!
Though I realize which options are actually supported depends on the VM, moving the list of potentially available cross-platform options (and a description of what they're used for) to a comment in the image (setOption: value: being the obvious location) might be a nice first step.
Please help in the documentation effort.
Cheers, Henry
P.S. On the plus side, I'm now able to turn my PC into a better remote for multi-cam GoPro setups than the GoPro remote itself is :)
I am sure you will blog about this !
Sven Van Caekenberghe-2 wrote
I am sure you will blog about this !
Yes, pleeeeeeease!! ----- Cheers, Sean -- View this message in context: http://forum.world.st/Issue-with-UDP-Sockets-tp4827014p4829352.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.
On 29 May 2015, at 7:24 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 29 May 2015, at 18:23, Henrik Johansen <henrik.s.johansen@veloxit.no> wrote:
On 19 May 2015, at 11:01 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 19 May 2015, at 10:53, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Did you look in all your package caches ? I did. Must have been a victim of cleaning ... but maybe TimeMachine has something ... thanks for the reminder.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice. The package was pretty simple. Basically only adding a few convenience methods around Socket>>#setOption:value: . Still I think a usage example in form of a class comment and test case might be appropriate. So unless Multicast should be part of the base image I'll start with a separate package first.
Since Socket is a fundamental part, and multicast is a key feature, I think it would logical to move it to the image itself, with a test case.
It's not just multicast... As a Socket newbie I recently spent longer than I care to admit learning you need to set SO_BROADCAST to true to not get a primitive failure when sending to a broadcast address. At least the comments in sqUnixSocket were entertaining!
Though I realize which options are actually supported depends on the VM, moving the list of potentially available cross-platform options (and a description of what they're used for) to a comment in the image (setOption: value: being the obvious location) might be a nice first step.
Please help in the documentation effort.
I later found the option names are already documented in getOption:, but since that wasn't of much help (at least to me), I suggest introducing a more specific error than primitiveFailure. Implementing that, the new test revealed a bug; empty UDP payloads will not be sent. A suggested fix for both these issues can be found in SLICE-Issue-15657-Empty-UDP-packets-are-not-sent-HenrikSperreJohansen.1 Cheers, Henry
Thanks henrik A better API would be so great. Stef Le 1/6/15 15:18, Henrik Johansen a écrit :
On 29 May 2015, at 7:24 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 29 May 2015, at 18:23, Henrik Johansen <henrik.s.johansen@veloxit.no> wrote:
On 19 May 2015, at 11:01 , Sven Van Caekenberghe <sven@stfx.eu> wrote:
On 19 May 2015, at 10:53, Udo Schneider <udo.schneider@homeaddress.de> wrote:
Did you look in all your package caches ? I did. Must have been a victim of cleaning ... but maybe TimeMachine has something ... thanks for the reminder.
If it is just a small example, like one class, maybe it could be added to the image, in which case it should indeed be a slice. The package was pretty simple. Basically only adding a few convenience methods around Socket>>#setOption:value: . Still I think a usage example in form of a class comment and test case might be appropriate. So unless Multicast should be part of the base image I'll start with a separate package first. Since Socket is a fundamental part, and multicast is a key feature, I think it would logical to move it to the image itself, with a test case. It's not just multicast... As a Socket newbie I recently spent longer than I care to admit learning you need to set SO_BROADCAST to true to not get a primitive failure when sending to a broadcast address. At least the comments in sqUnixSocket were entertaining!
Though I realize which options are actually supported depends on the VM, moving the list of potentially available cross-platform options (and a description of what they're used for) to a comment in the image (setOption: value: being the obvious location) might be a nice first step. Please help in the documentation effort. I later found the option names are already documented in getOption:, but since that wasn't of much help (at least to me), I suggest introducing a more specific error than primitiveFailure. Implementing that, the new test revealed a bug; empty UDP payloads will not be sent.
A suggested fix for both these issues can be found in SLICE-Issue-15657-Empty-UDP-packets-are-not-sent-HenrikSperreJohansen.1
Cheers, Henry
On Sat, May 30, 2015 at 12:23 AM, Henrik Johansen <henrik.s.johansen@veloxit.no> wrote:
P.S. On the plus side, I'm now able to turn my PC into a better remote for multi-cam GoPro setups than the GoPro remote itself is :)
That is cool to hear. Now as much as frameworks are important, I think cool little end-user apps like this are important to hook people into Pharo. You really need only *one* feature that people find compelling. Do you need any community support to polish it, then push it on GoPro sites? (not that I have a GoPro, but maybe I'll need to get one) cheers -ben
Hi Udo, is your mDNS code available somewhere? I thought about that some time ago that it could be a nice way to announce a pharo service to the network. Or in my case using it as a foundation for orchestrating images. Norbert
Am 19.05.2015 um 10:30 schrieb Udo Schneider <udo.schneider@homeaddress.de>:
Hi Sven,
you got me :-)
I had this as a package sometime ago for my own purposes (mDNS). So I knew it does work and how to do it. It's just I can't find that damned package anymore...
I do think making all this cross platform could be a bit harder, we'll see. It's not that hard. The socket API is the same on all supported platforms. No surprises on *nix based OS. The only exception is Windows where the API is the same but where you might run into some packet drops due to strange personal FW products and "value-add" NDIS drivers for NICs. The situation has gotten much better though since Windows Vista/7 are using multicast for some of their services out of the box.
I will recreate it though. Should I simply publish a package or add this as a slice?
Best Regards,
Udo
On 19/05/15 10:20, Sven Van Caekenberghe wrote:
Hi Udo,
It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected.
I do think making all this cross platform could be a bit harder, we'll see.
Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
is your mDNS code available somewhere? I thought about that some time ago that it could be a nice way to announce a pharo service to the network. Or in my case using it as a foundation for orchestrating images. No it's not in form a ready to go package. I'd have to check whether I saved the Workspace somewhere.
Getting the multicast stuff to work was easy. But getting further basically meant implementing a complete name resolver with an understanding of most DNS payloads. Wasn't worth the effort. CU, Udo On 19.05.2015 11:54, Norbert Hartl wrote:
Hi Udo,
is your mDNS code available somewhere? I thought about that some time ago that it could be a nice way to announce a pharo service to the network. Or in my case using it as a foundation for orchestrating images.
Norbert
Am 19.05.2015 um 10:30 schrieb Udo Schneider <udo.schneider@homeaddress.de>:
Hi Sven,
you got me :-)
I had this as a package sometime ago for my own purposes (mDNS). So I knew it does work and how to do it. It's just I can't find that damned package anymore...
I do think making all this cross platform could be a bit harder, we'll see. It's not that hard. The socket API is the same on all supported platforms. No surprises on *nix based OS. The only exception is Windows where the API is the same but where you might run into some packet drops due to strange personal FW products and "value-add" NDIS drivers for NICs. The situation has gotten much better though since Windows Vista/7 are using multicast for some of their services out of the box.
I will recreate it though. Should I simply publish a package or add this as a slice?
Best Regards,
Udo
On 19/05/15 10:20, Sven Van Caekenberghe wrote:
Hi Udo,
It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected.
I do think making all this cross platform could be a bit harder, we'll see.
Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
oh yes! + 1000000000 Le 19/5/15 10:20, Sven Van Caekenberghe a écrit :
Hi Udo,
It would be good if some of this knowledge could be added inside the image, as class comment or methods comments. Even better would be an example combined with a unit test, like UDPSocketEchoTest and TCPSocketEchoTest - the unit test would then actively ensure this functionality is protected.
I do think making all this cross platform could be a bit harder, we'll see.
Sven
On 19 May 2015, at 00:17, Udo Schneider <udo.schneider@homeaddress.de> wrote:
This should have been 'IP_ADD_MEMBERSHIP' of course:
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq.
The "server" could be something like this (execute in first playground). I used another IP address (#[239 255 255 251]) because #[239 255 255 250] might already be part of the multicast group because of other processes and this shows the "whole" process of subscribing to a multicast group:
[ | udpSocket | udpSocket := Socket newUDP. udpSocket setPort: 1900. imrMultiaddr := #[239 255 255 251]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. udpSocket setOption: 'IP_ADD_MEMBERSHIP' value: ipMreq. udpSocket setOption: 'IP_MULTICAST_LOOP' value: 1. "udpSocket setOption: 'SO_REUSEADDR' value: 1." udpSocket waitForData. buffer := ByteArray new: 256. data := udpSocket receiveUDPDataInto: buffer. bytesRead := data at: 1. sender := data at: 2. senderPort := data at: 3. more := data at: 4. result := buffer copyFrom: 1 to: bytesRead. udpSocket closeAndDestroy. result asString inspect. ] fork.
The "client" (execute in different playground): | message udpSocket | message := String crlf join: #( 'M-SEARCH * HTTP/1.1' 'HOST:239.255.255.250:1900' 'MAN:"ssdp:discover' 'ST:ssdp:all' 'MX:1' '').
udpSocket := Socket newUDP. udpSocket sendData: message toHost: #[239 255 255 251] port: 1900. (udpSocket waitForSendDoneFor: 5). udpSocket closeAndDestroy.
Hope this helps.
CU,
Udo
On 18/05/15 23:29, Udo Schneider wrote:
Hi Manfred,
I just stumbled over the IP address you are using (239.255.255.250). If I remember correctly this is a IPv4 Class D Multicast address. (224.0.0.0-239.255.255.255).
So if you want to transmit datagrams to this IP address or recieve datagrams sent to this multicast groups you have to set appropriate IP Options.
You can set this options using Socket>>#setOption:value: and read them using Socket>>#getOption:. Please note that both methods expect the option to set as a name - not as constant. E.g.
socket setOption: 'IP_MULTICAST_IF' value: multicastInterface.
If I do remember correctly you have to set the following options for sending/receiving:
Sending: IP_MULTICAST_IF (IP_MULTICAST_LOOP) (IP_MULTICAST_TTL)
Sending should AFAIK work w/o setting any option - although IP_MULTICAST_IF is highly recommended.
Receiving: (SO_REUSEADDR) IP_ADD_MEMBERSHIP (IP_DROP_MEMBERSHIP)
Receiving only works if you joined the multicast group previously. So I assume that you need to do something like this (not tested).
imrMultiaddr := #[239 255 255 250]. imrInterface := #[0 0 0 0]. ipMreq := imrMultiaddr , imrInterface. socket setOption: 'MEMBERSHIP' value: ipMreq.
Hope this helps.
CU,
Udo
On 18/05/15 16:34, Manfred Kröhnert wrote:
Hi Sven,
On Mon, May 18, 2015 at 4:14 PM, Sven Van Caekenberghe <sven@stfx.eu <mailto:sven@stfx.eu>> wrote:
> On 18 May 2015, at 15:47, Manfred Kröhnert <mkroehnert42@googlemail.com <mailto:mkroehnert42@googlemail.com>> wrote: > > Hi, > apparently I am missing something else. > > I can find devices when connected to a 'regular' LAN. > > However, I have a camera that creates a Wifi accesspoint and makes itself discoverable via SSDP. > Once I connect to this accesspoint my computer gets a valid IP address assigned and the NodeJS code is able to discover the device. > Unfortunately, the Pharo snippet I posted before does not give me any results and hangs in Socket>>waitForDataIfClosed: . > > Any further ideas?
Are you sure you restarted the image and your code after switching networks ?
I did not check this before. But I just downloaded a fresh 40613 image with PharoLauncher and started it after connecting to the camera accesspoint. The code snippet freezes there as well.
Manfred
participants (9)
-
Ben Coman -
Henrik Johansen -
Manfred Kröhnert -
Norbert Hartl -
Sean P. DeNigris -
stepharo -
Sven Van Caekenberghe -
Udo Schneider -
Udo Schneider