Should RTCS_selectall() return on a TCP ack?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Should RTCS_selectall() return on a TCP ack?

Jump to solution
1,172 Views
theJoel
Contributor III

MQX 3.8

MCF52259

CW10.2

I am using all the default socket options for this connection.

From the user guide RTCS_selectall (for a stream socket) should return on:

Data or Shutdown requests that are initiated by the remote endpoint.


But I'm seeing after a send(), my call to RTCS_selectall() is returning (after blocking only briefly) with a valid socket handle when NO data was transmitted (verified with Wireshark). The code falls through to recv() but blocks indefinitely, there is no data to receive.


I believe found the code within RTCS that wakes my task from RTCS_selectall(). It is in TCP_Process_ack() [tcp_send.c]


        if ( tcb->sndlen == 0 ) {

            /*
            ** Notify socket layer in case some task is blocked on select()
            ** waiting for this data.
            */

            _SOCK_select_signal(tcb->SOCKET, tcb->state, 1);

            TCP_Event(tcb, TCPS_TACKED);   /* all data to send got acked */

        } /* Endif */


So, this seems totally contrary to the point of TCP. Yet, the comment indicates this is a useful move. Why should my server care that the client TCP stack has ACK'd my data? That is a layer-3 acknowledgement. It doesn't tell me anything about the client application. And the send() call itself was blocking.. it wouldn't have returned until RTCS had buffered all the data.


What am I doing wrong here? This feels like a bug and yet has existed in RTCS since MQX 3.1.. although curiously not in RTCS 2.97.


If it's not a bug.. how do I distinguish between RTCS_selectall() waking me up with data versus no data (only a TCP ack received)?



Thanks,

+Joel.

Labels (1)
0 Kudos
1 Solution
692 Views
butok
NXP Employee
NXP Employee

The RTCS_selectall() is not BSD-like function, it monitors (wake up on) all events that can be potentially interesting for an application. Probably this is the reason of your confusion. To avoid it, it is good to implement the BSD-like "select" function => we will think about it.

View solution in original post

0 Kudos
6 Replies
692 Views
Martin_
NXP Employee
NXP Employee

The send() may be made non-blocking by using socket option OPT_SEND_NOWAIT.

RTCS User's Guide will be modified with the description of the discussed behavior (RTCS_selectall returns when in a connected stream, all sent data is acknowledged). Thanks for pointing this out !

692 Views
theJoel
Contributor III

why do you mention OPT_SEND_NOWAIT ?  How does this impact the RTCS_selectall() behaviour?

All the examples in the manual show selectset()/selectall() immediately followed by recv(). recv() is only good if there is new data or if the connection is closed by the remote endpoint.

How is waking on "all sent data is acknowledged" a useful case? This is a TCP Ack, not an indication that the remote endpoint has actually processed the send() data or has more space available.

I don't see a good way to write an application with this behaviour. Do we add an extra non-blocking recv() call, just in case we get a TCP Ack with no data, so we can go back to sleep after a send()?

If you're saying this is actually the intended behaviour, then not only the manual has bugs, but the echo, EDS, and TFTP server implementations included with RTCS also have bugs.

0 Kudos
692 Views
Martin_
NXP Employee
NXP Employee

From what I understand, the problem is that your application is does: listen() -> RTCS_selectall() -> accept() -> RTCS_selectall() -> recv() with unlimited timeout.

I beleive you can solve the problem in application level to do: listen -> RTCS_selectall() -> accept() -> recv() with a timeout. You can set recv() timeout using the socket option of OPT_RECEIVE_TIMEOUT.

0 Kudos
692 Views
theJoel
Contributor III

Well, I still need the RTCS_selectall() to wake on new connections and on data from existing connections. Your explanation doesn't work as is.

But I think I understand the workaround now. When RTCS_selectall() returns there are three cases (other than error codes):

  1. A new incoming connection (on listen sock)
  2. Data on an already connected sock
  3. No Data on an already connected sock

I can distinguish case 1 from the return value of RTCS_selectall(). For 2 and 3 I have to actually call recv() in a polling mode (or with very small OPT_RECEIVE_TIMEOUT) and see if there is anything to do.

This is not very BSD-socket-friendly. The received TCP Ack should have no affect on my application layer protocol.

Why doesn't any of the included RTCS code handle this 3rd case?? What is the use case for waking a task with no data?

0 Kudos
693 Views
butok
NXP Employee
NXP Employee

The RTCS_selectall() is not BSD-like function, it monitors (wake up on) all events that can be potentially interesting for an application. Probably this is the reason of your confusion. To avoid it, it is good to implement the BSD-like "select" function => we will think about it.

0 Kudos
692 Views
theJoel
Contributor III

I guess I made some assumptions.. everything seems to follow BSD so closely. Also, the documented events that RTCS_selectall() monitors for not incomplete. Updating this should prevent more people from falling into the same trap.

For the record, in my application, I was able to set OPT_RECEIVE_NOWAIT to TRUE, instead of setting OPT_RECEIVE_TIMEOUT to a small value. This is preferable because if recv() returns a length of zero I can just go back to sleep. Using the rx timeout option, you have to make an additional call to RTCS_geterror() after the recv() call to determine if there truly was nothing to recv().

Also note: the Freescale example code using RTCS_selectall() is still based off the RTCS 2.97 implementation and does NOT handle the newer behaviour of RTCS_selectall().

Cheers,

+Joel.