Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Holger Freyther
Hi,

I am porting a tooling class that I wrote on GST for my SIP and MGCP code
to Pharo. This class will create a socket and then fork a RX and TX process.
I have some issues with 'stopping' the socket. I have created an example
that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to
have more debug output with a re-compiled one).


        | s rx |
        s := Socket newUDP.
        rx := [
                [s waitForData. s halt]
                        on: ConnectionClosed do: [ s halt]
                ] fork.
        "Wait for the process to hit the readSemaphore"
        (Delay forSeconds: 3) wait.
        s close.


My expectation is that I will get the ConnectionClosed signal or at least
that >>#waitForData will return once the socket is closed. This is based
on reading the comment of >>#waitForData.


The Socket>>#waitForData documentation reads like this:
        "Wait for data to arrive.  This method will block until
        data is available or the socket is closed.  If the socket is closed
        a ConnectionClosed exception will be signaled."


I had a look at the socket plugin and the following is happening. First
aio is disabled, the state set to ThisEndClosed, then ::close is called
and in the above case the result is '0' and the following code will be
executed:

 else if (0 == result)
     {
       /* close completed synchronously */
       SOCKETSTATE(s)= Unconnected;
       FPRINTF((stderr, "closeConnection: disconnected\n"));
       SOCKET(s)= -1;
     }


this means that my 'rx' process will happily wait on the readSemaphore
of the Socket and will never be woken up.


My question are probably:

1.) Is this the intended behavior for Socket>>#close and Socket>>#waitForData?
2.) How should I terminate my RX process?

kind regards
        holger

PS: The issue is probably socket specific and not related to UDP.

Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Stéphane Ducasse
I passed your mail to noury and luc because they got a lot of trouble with the socket code.


On Mar 26, 2013, at 12:12 PM, Holger Hans Peter Freyther <[hidden email]> wrote:

> Hi,
>
> I am porting a tooling class that I wrote on GST for my SIP and MGCP code
> to Pharo. This class will create a socket and then fork a RX and TX process.
> I have some issues with 'stopping' the socket. I have created an example
> that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to
> have more debug output with a re-compiled one).
>
>
> | s rx |
> s := Socket newUDP.
> rx := [
> [s waitForData. s halt]
> on: ConnectionClosed do: [ s halt]
> ] fork.
> "Wait for the process to hit the readSemaphore"
> (Delay forSeconds: 3) wait.
> s close.
>
>
> My expectation is that I will get the ConnectionClosed signal or at least
> that >>#waitForData will return once the socket is closed. This is based
> on reading the comment of >>#waitForData.
>
>
> The Socket>>#waitForData documentation reads like this:
> "Wait for data to arrive.  This method will block until
> data is available or the socket is closed.  If the socket is closed
> a ConnectionClosed exception will be signaled."
>
>
> I had a look at the socket plugin and the following is happening. First
> aio is disabled, the state set to ThisEndClosed, then ::close is called
> and in the above case the result is '0' and the following code will be
> executed:
>
> else if (0 == result)
>     {
>       /* close completed synchronously */
>       SOCKETSTATE(s)= Unconnected;
>       FPRINTF((stderr, "closeConnection: disconnected\n"));
>       SOCKET(s)= -1;
>     }
>
>
> this means that my 'rx' process will happily wait on the readSemaphore
> of the Socket and will never be woken up.
>
>
> My question are probably:
>
> 1.) Is this the intended behavior for Socket>>#close and Socket>>#waitForData?
> 2.) How should I terminate my RX process?
>
> kind regards
> holger
>
> PS: The issue is probably socket specific and not related to UDP.
>


Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Sven Van Caekenberghe-2
In reply to this post by Holger Freyther
Hi Holger,

On 26 Mar 2013, at 12:12, Holger Hans Peter Freyther <[hidden email]> wrote:

> Hi,
>
> I am porting a tooling class that I wrote on GST for my SIP and MGCP code
> to Pharo. This class will create a socket and then fork a RX and TX process.
> I have some issues with 'stopping' the socket. I have created an example
> that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to
> have more debug output with a re-compiled one).
>
>
> | s rx |
> s := Socket newUDP.
> rx := [
> [s waitForData. s halt]
> on: ConnectionClosed do: [ s halt]
> ] fork.
> "Wait for the process to hit the readSemaphore"
> (Delay forSeconds: 3) wait.
> s close.
>
>
> My expectation is that I will get the ConnectionClosed signal or at least
> that >>#waitForData will return once the socket is closed. This is based
> on reading the comment of >>#waitForData.
>
>
> The Socket>>#waitForData documentation reads like this:
> "Wait for data to arrive.  This method will block until
> data is available or the socket is closed.  If the socket is closed
> a ConnectionClosed exception will be signaled."
>
>
> I had a look at the socket plugin and the following is happening. First
> aio is disabled, the state set to ThisEndClosed, then ::close is called
> and in the above case the result is '0' and the following code will be
> executed:
>
> else if (0 == result)
>     {
>       /* close completed synchronously */
>       SOCKETSTATE(s)= Unconnected;
>       FPRINTF((stderr, "closeConnection: disconnected\n"));
>       SOCKET(s)= -1;
>     }
>
>
> this means that my 'rx' process will happily wait on the readSemaphore
> of the Socket and will never be woken up.
>
>
> My question are probably:
>
> 1.) Is this the intended behavior for Socket>>#close and Socket>>#waitForData?
> 2.) How should I terminate my RX process?
>
> kind regards
> holger
>
> PS: The issue is probably socket specific and not related to UDP.

Maybe I am telling you things you already know, but TCP and UDP are fundamentally different. UDP is really one-shot, try-and-hope, completely asynchronous. In networking you generally only get a ConnectionClosed when you actually read or write (and even then ;-).

The Socket API has many strange methods, most of which you should not touch. You should use SocketStream. Looking in the VM code is also misleading because the 3 platforms (Mac, Win, *nix) are different. In Socket[Stream] there is lots of historic baggage.

I would suggest you look at Smalltalk code that actually works (for TCP, Zinc Client and Server code would do, for UDP, ZTimestampSNTPClient for example).

For your concrete question (2): just start a reading process, wrap it in a handler and clean up. For UDP this will never happen: you will keep on reading nothing. For TCP reading will eventually fail if the other end disappears.

HTH,

Sven

--
Sven Van Caekenberghe
http://stfx.eu
Smalltalk is the Red Pill


Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

NorbertHartl

Am 26.03.2013 um 21:08 schrieb Sven Van Caekenberghe <[hidden email]>:

> Hi Holger,
>
> On 26 Mar 2013, at 12:12, Holger Hans Peter Freyther <[hidden email]> wrote:
>
>> Hi,
>>
>> I am porting a tooling class that I wrote on GST for my SIP and MGCP code
>> to Pharo. This class will create a socket and then fork a RX and TX process.
>> I have some issues with 'stopping' the socket. I have created an example
>> that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to
>> have more debug output with a re-compiled one).
>>
>>
>> | s rx |
>> s := Socket newUDP.
>> rx := [
>> [s waitForData. s halt]
>> on: ConnectionClosed do: [ s halt]
>> ] fork.
>> "Wait for the process to hit the readSemaphore"
>> (Delay forSeconds: 3) wait.
>> s close.
>>
>>
>> My expectation is that I will get the ConnectionClosed signal or at least
>> that >>#waitForData will return once the socket is closed. This is based
>> on reading the comment of >>#waitForData.
>>
>>
>> The Socket>>#waitForData documentation reads like this:
>> "Wait for data to arrive.  This method will block until
>> data is available or the socket is closed.  If the socket is closed
>> a ConnectionClosed exception will be signaled."
>>
>>
>> I had a look at the socket plugin and the following is happening. First
>> aio is disabled, the state set to ThisEndClosed, then ::close is called
>> and in the above case the result is '0' and the following code will be
>> executed:
>>
>> else if (0 == result)
>>    {
>>      /* close completed synchronously */
>>      SOCKETSTATE(s)= Unconnected;
>>      FPRINTF((stderr, "closeConnection: disconnected\n"));
>>      SOCKET(s)= -1;
>>    }
>>
>>
>> this means that my 'rx' process will happily wait on the readSemaphore
>> of the Socket and will never be woken up.
>>
>>
>> My question are probably:
>>
>> 1.) Is this the intended behavior for Socket>>#close and Socket>>#waitForData?
>> 2.) How should I terminate my RX process?
>>
>> kind regards
>> holger
>>
>> PS: The issue is probably socket specific and not related to UDP.
>
> Maybe I am telling you things you already know, but TCP and UDP are fundamentally different. UDP is really one-shot, try-and-hope, completely asynchronous. In networking you generally only get a ConnectionClosed when you actually read or write (and even then ;-).
>
That's not really true. It is implementation specific. IMHO you can open a UDP socket in send and receive mode where the communication is synchronous. So your socket blocks until a datagram socket is received. This has to advantage that the underlying OS registers local and remote port and automatically and accepts only datagrams for the right ports match. As it is in a lot of use cases not preferrable to have blocking sockets while using UDP you use two sockets instead, one for sending and one for receiving. For this you need to register the listening socket for listening to everything.
Disclaimer: I took this from the back of my head and this might by outdated/inproper information. I just wanted to say that you shouldn't mix asynchronous with unidirectional :)

Norbert

> The Socket API has many strange methods, most of which you should not touch. You should use SocketStream. Looking in the VM code is also misleading because the 3 platforms (Mac, Win, *nix) are different. In Socket[Stream] there is lots of historic baggage.
>
> I would suggest you look at Smalltalk code that actually works (for TCP, Zinc Client and Server code would do, for UDP, ZTimestampSNTPClient for example).
>
> For your concrete question (2): just start a reading process, wrap it in a handler and clean up. For UDP this will never happen: you will keep on reading nothing. For TCP reading will eventually fail if the other end disappears.
>
> HTH,
>
> Sven
>
> --
> Sven Van Caekenberghe
> http://stfx.eu
> Smalltalk is the Red Pill
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Sven Van Caekenberghe-2

On 26 Mar 2013, at 23:46, Norbert Hartl <[hidden email]> wrote:

> Am 26.03.2013 um 21:08 schrieb Sven Van Caekenberghe <[hidden email]>:
>
>> Hi Holger,
>>
>> On 26 Mar 2013, at 12:12, Holger Hans Peter Freyther <[hidden email]> wrote:
>>
>>> Hi,
>>>
>>> I am porting a tooling class that I wrote on GST for my SIP and MGCP code
>>> to Pharo. This class will create a socket and then fork a RX and TX process.
>>> I have some issues with 'stopping' the socket. I have created an example
>>> that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to
>>> have more debug output with a re-compiled one).
>>>
>>>
>>> | s rx |
>>> s := Socket newUDP.
>>> rx := [
>>> [s waitForData. s halt]
>>> on: ConnectionClosed do: [ s halt]
>>> ] fork.
>>> "Wait for the process to hit the readSemaphore"
>>> (Delay forSeconds: 3) wait.
>>> s close.
>>>
>>>
>>> My expectation is that I will get the ConnectionClosed signal or at least
>>> that >>#waitForData will return once the socket is closed. This is based
>>> on reading the comment of >>#waitForData.
>>>
>>>
>>> The Socket>>#waitForData documentation reads like this:
>>> "Wait for data to arrive.  This method will block until
>>> data is available or the socket is closed.  If the socket is closed
>>> a ConnectionClosed exception will be signaled."
>>>
>>>
>>> I had a look at the socket plugin and the following is happening. First
>>> aio is disabled, the state set to ThisEndClosed, then ::close is called
>>> and in the above case the result is '0' and the following code will be
>>> executed:
>>>
>>> else if (0 == result)
>>>   {
>>>     /* close completed synchronously */
>>>     SOCKETSTATE(s)= Unconnected;
>>>     FPRINTF((stderr, "closeConnection: disconnected\n"));
>>>     SOCKET(s)= -1;
>>>   }
>>>
>>>
>>> this means that my 'rx' process will happily wait on the readSemaphore
>>> of the Socket and will never be woken up.
>>>
>>>
>>> My question are probably:
>>>
>>> 1.) Is this the intended behavior for Socket>>#close and Socket>>#waitForData?
>>> 2.) How should I terminate my RX process?
>>>
>>> kind regards
>>> holger
>>>
>>> PS: The issue is probably socket specific and not related to UDP.
>>
>> Maybe I am telling you things you already know, but TCP and UDP are fundamentally different. UDP is really one-shot, try-and-hope, completely asynchronous. In networking you generally only get a ConnectionClosed when you actually read or write (and even then ;-).
>>
> That's not really true. It is implementation specific. IMHO you can open a UDP socket in send and receive mode where the communication is synchronous. So your socket blocks until a datagram socket is received. This has to advantage that the underlying OS registers local and remote port and automatically and accepts only datagrams for the right ports match. As it is in a lot of use cases not preferrable to have blocking sockets while using UDP you use two sockets instead, one for sending and one for receiving. For this you need to register the listening socket for listening to everything.
> Disclaimer: I took this from the back of my head and this might by outdated/inproper information. I just wanted to say that you shouldn't mix asynchronous with unidirectional :)
>
> Norbert

I politely disagree ;-)

But I am willing to learn: so please provide some references of such UDP usage.

http://en.wikipedia.org/wiki/Datagram

>> The Socket API has many strange methods, most of which you should not touch. You should use SocketStream. Looking in the VM code is also misleading because the 3 platforms (Mac, Win, *nix) are different. In Socket[Stream] there is lots of historic baggage.
>>
>> I would suggest you look at Smalltalk code that actually works (for TCP, Zinc Client and Server code would do, for UDP, ZTimestampSNTPClient for example).
>>
>> For your concrete question (2): just start a reading process, wrap it in a handler and clean up. For UDP this will never happen: you will keep on reading nothing. For TCP reading will eventually fail if the other end disappears.
>>
>> HTH,
>>
>> Sven
>>
>> --
>> Sven Van Caekenberghe
>> http://stfx.eu
>> Smalltalk is the Red Pill
>>
>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Esteban A. Maringolo
2013/3/26 Sven Van Caekenberghe <[hidden email]>:
> I politely disagree ;-)
>
> But I am willing to learn: so please provide some references of such UDP usage.

I can't speak about all the implementations, but several years ago I
did an UDP Socket wrapper for Dolphin Smalltalk 5 which basically
wrapped the Win32 API.

AFAIR, there were no connection exceptions, nor state whatsoever, just
open a udp socket to a destination address and send datagrams through
it, hopefully they'll reach the desired destination.

On the other side the server is non blocking, just listening at an
address and port, but it was event-based: on each datagram received it
fired an event.

Regards!

Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Holger Freyther
In reply to this post by Sven Van Caekenberghe-2
On Wed, Mar 27, 2013 at 12:25:20AM +0100, Sven Van Caekenberghe wrote:


> I politely disagree ;-)
>
> But I am willing to learn: so please provide some references of such UDP usage.
>
> http://en.wikipedia.org/wiki/Datagram

I am not sure which part you are disagreeing to. But you can definately use
connect on a SOCK_DGRAM. The benefit is that you can then use read/write on
filedescriptor instead of sendto/recv. An example is here[1].

holger


[1] http://cgit.osmocom.org/openbsc/tree/openbsc/src/osmo-bsc_mgcp/mgcp_main.c#n242

Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Holger Freyther
In reply to this post by Sven Van Caekenberghe-2
On Tue, Mar 26, 2013 at 09:08:09PM +0100, Sven Van Caekenberghe wrote:

> Maybe I am telling you things you already know, but TCP and UDP are fundamentally different. UDP is really one-shot, try-and-hope, completely asynchronous. In networking you generally only get a ConnectionClosed when you actually read or write (and even then ;-).

Yes, but at least for the unix platform on close the aio/select handler is
removing the socket from the registration. So there is no way to read the
zero from the dead socket. :)

> For your concrete question (2): just start a reading process, wrap it in a handler and clean up. For UDP this will never happen: you will keep on reading nothing. For TCP reading will eventually fail if the other end disappears.

Do you have an example for "handler and clean up"? I resorted to code
like this for now in my 'blocking' read.

        [self dataAvailable]
            whileFalse: [[self waitForDataFor: 10] on: ConnectionTimedOut do: []].

But I have not ported my client code so I don't know if the above is
working or not. This way I will get the ConnectionClosed exception at
least within 10 seconds.

thank you

holger

Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Sven Van Caekenberghe-2
In reply to this post by Holger Freyther

On 27 Mar 2013, at 08:03, Holger Hans Peter Freyther <[hidden email]> wrote:

> On Wed, Mar 27, 2013 at 12:25:20AM +0100, Sven Van Caekenberghe wrote:
>
>> I politely disagree ;-)
>>
>> But I am willing to learn: so please provide some references of such UDP usage.
>>
>> http://en.wikipedia.org/wiki/Datagram
>
> I am not sure which part you are disagreeing to. But you can definately use
> connect on a SOCK_DGRAM. The benefit is that you can then use read/write on
> filedescriptor instead of sendto/recv. An example is here[1].
>
> holger
>
> [1] http://cgit.osmocom.org/openbsc/tree/openbsc/src/osmo-bsc_mgcp/mgcp_main.c#n242

OK, but I would doubt that such API usage would change the basic semantics of UDP.
And I never said that you couldn't do a connect on a UDP socket.

Sven
Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Sven Van Caekenberghe-2
In reply to this post by Holger Freyther

On 27 Mar 2013, at 08:11, Holger Hans Peter Freyther <[hidden email]> wrote:

> On Tue, Mar 26, 2013 at 09:08:09PM +0100, Sven Van Caekenberghe wrote:
>
>> Maybe I am telling you things you already know, but TCP and UDP are fundamentally different. UDP is really one-shot, try-and-hope, completely asynchronous. In networking you generally only get a ConnectionClosed when you actually read or write (and even then ;-).
>
> Yes, but at least for the unix platform on close the aio/select handler is
> removing the socket from the registration. So there is no way to read the
> zero from the dead socket. :)
>
>> For your concrete question (2): just start a reading process, wrap it in a handler and clean up. For UDP this will never happen: you will keep on reading nothing. For TCP reading will eventually fail if the other end disappears.
>
> Do you have an example for "handler and clean up"? I resorted to code
> like this for now in my 'blocking' read.
>
> [self dataAvailable]
>    whileFalse: [[self waitForDataFor: 10] on: ConnectionTimedOut do: []].
>
> But I have not ported my client code so I don't know if the above is
> working or not. This way I will get the ConnectionClosed exception at
> least within 10 seconds.
>
> thank you
>
> holger

It is still not clear to me if this is for UDP or TCP, I would be surprised of #dataAvailable or #waitForData: actually work for UDP. I gave you some pointers to examples that do work. Your code snippet looks reasonable to me, but I would set timeouts on the socket(streams) and use regular read/write operations and then loop.

Sven


Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

NorbertHartl
In reply to this post by Sven Van Caekenberghe-2

Am 27.03.2013 um 00:25 schrieb Sven Van Caekenberghe <[hidden email]>:

>
> On 26 Mar 2013, at 23:46, Norbert Hartl <[hidden email]> wrote:
>
>> Am 26.03.2013 um 21:08 schrieb Sven Van Caekenberghe <[hidden email]>:
>>
>>> Hi Holger,
>>>
>>> On 26 Mar 2013, at 12:12, Holger Hans Peter Freyther <[hidden email]> wrote:
>>>
>>>> Hi,
>>>>
>>>> I am porting a tooling class that I wrote on GST for my SIP and MGCP code
>>>> to Pharo. This class will create a socket and then fork a RX and TX process.
>>>> I have some issues with 'stopping' the socket. I have created an example
>>>> that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to
>>>> have more debug output with a re-compiled one).
>>>>
>>>>
>>>> | s rx |
>>>> s := Socket newUDP.
>>>> rx := [
>>>> [s waitForData. s halt]
>>>> on: ConnectionClosed do: [ s halt]
>>>> ] fork.
>>>> "Wait for the process to hit the readSemaphore"
>>>> (Delay forSeconds: 3) wait.
>>>> s close.
>>>>
>>>>
>>>> My expectation is that I will get the ConnectionClosed signal or at least
>>>> that >>#waitForData will return once the socket is closed. This is based
>>>> on reading the comment of >>#waitForData.
>>>>
>>>>
>>>> The Socket>>#waitForData documentation reads like this:
>>>> "Wait for data to arrive.  This method will block until
>>>> data is available or the socket is closed.  If the socket is closed
>>>> a ConnectionClosed exception will be signaled."
>>>>
>>>>
>>>> I had a look at the socket plugin and the following is happening. First
>>>> aio is disabled, the state set to ThisEndClosed, then ::close is called
>>>> and in the above case the result is '0' and the following code will be
>>>> executed:
>>>>
>>>> else if (0 == result)
>>>>  {
>>>>    /* close completed synchronously */
>>>>    SOCKETSTATE(s)= Unconnected;
>>>>    FPRINTF((stderr, "closeConnection: disconnected\n"));
>>>>    SOCKET(s)= -1;
>>>>  }
>>>>
>>>>
>>>> this means that my 'rx' process will happily wait on the readSemaphore
>>>> of the Socket and will never be woken up.
>>>>
>>>>
>>>> My question are probably:
>>>>
>>>> 1.) Is this the intended behavior for Socket>>#close and Socket>>#waitForData?
>>>> 2.) How should I terminate my RX process?
>>>>
>>>> kind regards
>>>> holger
>>>>
>>>> PS: The issue is probably socket specific and not related to UDP.
>>>
>>> Maybe I am telling you things you already know, but TCP and UDP are fundamentally different. UDP is really one-shot, try-and-hope, completely asynchronous. In networking you generally only get a ConnectionClosed when you actually read or write (and even then ;-).
>>>
>> That's not really true. It is implementation specific. IMHO you can open a UDP socket in send and receive mode where the communication is synchronous. So your socket blocks until a datagram socket is received. This has to advantage that the underlying OS registers local and remote port and automatically and accepts only datagrams for the right ports match. As it is in a lot of use cases not preferrable to have blocking sockets while using UDP you use two sockets instead, one for sending and one for receiving. For this you need to register the listening socket for listening to everything.
>> Disclaimer: I took this from the back of my head and this might by outdated/inproper information. I just wanted to say that you shouldn't mix asynchronous with unidirectional :)
>>
>> Norbert
>
> I politely disagree ;-)
>
> But I am willing to learn: so please provide some references of such UDP usage.
>
> http://en.wikipedia.org/wiki/Datagram
>
If I find the time I dig out some things from the past. I just can't follow your reasoning that the way UDP is defined means unidirectional. TCP defines a connection, UDP does not. Connections are not required to have end-to-end communication. A remote port is a service identifier and local port is a client identifier. A port pair defines a communication channel. TCP just adds roles to both ends and defines stream sequences and transmission windows.
Maybe I misunderstood you then I take everything back :)

Norbert

>>> The Socket API has many strange methods, most of which you should not touch. You should use SocketStream. Looking in the VM code is also misleading because the 3 platforms (Mac, Win, *nix) are different. In Socket[Stream] there is lots of historic baggage.
>>>
>>> I would suggest you look at Smalltalk code that actually works (for TCP, Zinc Client and Server code would do, for UDP, ZTimestampSNTPClient for example).
>>>
>>> For your concrete question (2): just start a reading process, wrap it in a handler and clean up. For UDP this will never happen: you will keep on reading nothing. For TCP reading will eventually fail if the other end disappears.
>>>
>>> HTH,
>>>
>>> Sven
>>>
>>> --
>>> Sven Van Caekenberghe
>>> http://stfx.eu
>>> Smalltalk is the Red Pill
>>>
>>>
>>
>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

Sven Van Caekenberghe-2

On 27 Mar 2013, at 10:55, Norbert Hartl <[hidden email]> wrote:

>
> Am 27.03.2013 um 00:25 schrieb Sven Van Caekenberghe <[hidden email]>:
>
>>
>> On 26 Mar 2013, at 23:46, Norbert Hartl <[hidden email]> wrote:
>>
>>> Am 26.03.2013 um 21:08 schrieb Sven Van Caekenberghe <[hidden email]>:
>>>
>>>> Hi Holger,
>>>>
>>>> On 26 Mar 2013, at 12:12, Holger Hans Peter Freyther <[hidden email]> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> I am porting a tooling class that I wrote on GST for my SIP and MGCP code
>>>>> to Pharo. This class will create a socket and then fork a RX and TX process.
>>>>> I have some issues with 'stopping' the socket. I have created an example
>>>>> that shows the issue in Pharo 2.0 and Pharo 1.4 with the pharovm (and to
>>>>> have more debug output with a re-compiled one).
>>>>>
>>>>>
>>>>> | s rx |
>>>>> s := Socket newUDP.
>>>>> rx := [
>>>>> [s waitForData. s halt]
>>>>> on: ConnectionClosed do: [ s halt]
>>>>> ] fork.
>>>>> "Wait for the process to hit the readSemaphore"
>>>>> (Delay forSeconds: 3) wait.
>>>>> s close.
>>>>>
>>>>>
>>>>> My expectation is that I will get the ConnectionClosed signal or at least
>>>>> that >>#waitForData will return once the socket is closed. This is based
>>>>> on reading the comment of >>#waitForData.
>>>>>
>>>>>
>>>>> The Socket>>#waitForData documentation reads like this:
>>>>> "Wait for data to arrive.  This method will block until
>>>>> data is available or the socket is closed.  If the socket is closed
>>>>> a ConnectionClosed exception will be signaled."
>>>>>
>>>>>
>>>>> I had a look at the socket plugin and the following is happening. First
>>>>> aio is disabled, the state set to ThisEndClosed, then ::close is called
>>>>> and in the above case the result is '0' and the following code will be
>>>>> executed:
>>>>>
>>>>> else if (0 == result)
>>>>> {
>>>>>   /* close completed synchronously */
>>>>>   SOCKETSTATE(s)= Unconnected;
>>>>>   FPRINTF((stderr, "closeConnection: disconnected\n"));
>>>>>   SOCKET(s)= -1;
>>>>> }
>>>>>
>>>>>
>>>>> this means that my 'rx' process will happily wait on the readSemaphore
>>>>> of the Socket and will never be woken up.
>>>>>
>>>>>
>>>>> My question are probably:
>>>>>
>>>>> 1.) Is this the intended behavior for Socket>>#close and Socket>>#waitForData?
>>>>> 2.) How should I terminate my RX process?
>>>>>
>>>>> kind regards
>>>>> holger
>>>>>
>>>>> PS: The issue is probably socket specific and not related to UDP.
>>>>
>>>> Maybe I am telling you things you already know, but TCP and UDP are fundamentally different. UDP is really one-shot, try-and-hope, completely asynchronous. In networking you generally only get a ConnectionClosed when you actually read or write (and even then ;-).
>>>>
>>> That's not really true. It is implementation specific. IMHO you can open a UDP socket in send and receive mode where the communication is synchronous. So your socket blocks until a datagram socket is received. This has to advantage that the underlying OS registers local and remote port and automatically and accepts only datagrams for the right ports match. As it is in a lot of use cases not preferrable to have blocking sockets while using UDP you use two sockets instead, one for sending and one for receiving. For this you need to register the listening socket for listening to everything.
>>> Disclaimer: I took this from the back of my head and this might by outdated/inproper information. I just wanted to say that you shouldn't mix asynchronous with unidirectional :)
>>>
>>> Norbert
>>
>> I politely disagree ;-)
>>
>> But I am willing to learn: so please provide some references of such UDP usage.
>>
>> http://en.wikipedia.org/wiki/Datagram
>>
> If I find the time I dig out some things from the past. I just can't follow your reasoning that the way UDP is defined means unidirectional. TCP defines a connection, UDP does not. Connections are not required to have end-to-end communication. A remote port is a service identifier and local port is a client identifier. A port pair defines a communication channel. TCP just adds roles to both ends and defines stream sequences and transmission windows.
> Maybe I misunderstood you then I take everything back :)

It is probably about terms and how we each interpret them.
I was not trying to be very formal, maybe that was confusing.
Some of the terms you are using are not my standard vocabulary.

But I don't think I said 'unidirectional' in any sentence.

Here is my non-formal high-level description:

A datagram (UDP packet) is a (small) collection of bytes being sent from A to B. Either A or B can be client/server, or sender/receiver. To receive or to be server, you have to be bound to a port (or you listen on the default port assigned to you when sending). Datagrams know their length and sender/destination host:port - but that is mostly implementation.

Semantically, datagrams can get lost or arrive out of order. A or B will never know as there are no guarantees. To add reliability, you need acknowledgements, retries, numbering, and so on. If you do all that with a stream interface, you are building your own TCP layer.

As a (Smalltalk) user, that means that

        #sendUDPData:toHost:port: will not tell you if anything is wrong, for example

                Socket newUDP
                        sendUDPData: #[ 1 2 3 ] toHost: #[ 217 11 221 200 ] port: 12345

                sending 3 bytes to pharo.st:12345 will give no error at all

        #receiveUDPDataInto: will either return a datagram or not, but does not signal any error

                it will also return immediately, so you have to loop

BTW, these are not necessarily disadvantages, but advantages to build specific, efficient, low-level protocols.

Sven

> Norbert
>
>>>> The Socket API has many strange methods, most of which you should not touch. You should use SocketStream. Looking in the VM code is also misleading because the 3 platforms (Mac, Win, *nix) are different. In Socket[Stream] there is lots of historic baggage.
>>>>
>>>> I would suggest you look at Smalltalk code that actually works (for TCP, Zinc Client and Server code would do, for UDP, ZTimestampSNTPClient for example).
>>>>
>>>> For your concrete question (2): just start a reading process, wrap it in a handler and clean up. For UDP this will never happen: you will keep on reading nothing. For TCP reading will eventually fail if the other end disappears.
>>>>
>>>> HTH,
>>>>
>>>> Sven
>>>>
>>>> --
>>>> Sven Van Caekenberghe
>>>> http://stfx.eu
>>>> Smalltalk is the Red Pill
>>>>
>>>>
>>>
>>>
>>
>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Some issues with UDP sockets in Pharo 1.4/Pharo 2.0

NorbertHartl

Am 27.03.2013 um 11:31 schrieb Sven Van Caekenberghe <[hidden email]>:

Semantically, datagrams can get lost or arrive out of order. A or B will never know as there are no guarantees. To add reliability, you need acknowledgements, retries, numbering, and so on. If you do all that with a stream interface, you are building your own TCP layer.

Yes, but using a stream does not necessarily mean that the transport is reliable. It can still be a stream of (modern speak) "eventually consistent" transport :)

I think we discussed it thoroughly and didn't want to hijack the original post.

Norbert