Closing TCP connections

Discussion to talk about software related topics only.
SeeCwriter
Posts: 608
Joined: Mon May 12, 2008 10:55 am

Closing TCP connections

Post by SeeCwriter »

I've noticed that when a host (i.e. PC) closes a TCP connection with a NB module, the module responds with an ACK, as it should, but it never responds with the FIN flag set. So the host ends up issuing a reset after a timeout period, about 30-sec.

Is there something the firmware should be doing other than calling close() on the socket?

I'm using v2.8.7, on a MOD5441X, but it's the same on previous versions.
SeeCwriter
Posts: 608
Joined: Mon May 12, 2008 10:55 am

Re: Closing TCP connections

Post by SeeCwriter »

Never mind. I found the cause in my firmware.
SeeCwriter
Posts: 608
Joined: Mon May 12, 2008 10:55 am

Re: Closing TCP connections

Post by SeeCwriter »

It's all coming back to me as to why I did what I did. It looks like the only way to determine if a TCP socket has closed is to use function ReadWithTimeout. But if there's no data, the program is forced to stall for 50msec using the smallest timeout. If I have several sockets open, that can be a lot of time to process them all. Function dataavail only tells you if there's data waiting, it knows nothing about the socket state. The keepalive function also doesn't tell you the state of the socket.

What I would like is a function that returns the state of the socket immediately. No timeouts. Is that possible?
User avatar
TomNB
Posts: 541
Joined: Tue May 10, 2016 8:22 am

Re: Closing TCP connections

Post by TomNB »

One of the issues with the TCP protocol is there is no way to tell is a socket is connected unless you try to interact with it. So you can't have a function that checks and returns immediately. Some things you can do is have your application keep a list of the status of each socket
- Use keepalive and close any sockets that don't respond,
- Use a data timeout. Keep a timer for each socket and if data has not been sent or received in the last x amount of time, close the socket
I'm sure there are other methods as well.
SeeCwriter
Posts: 608
Joined: Mon May 12, 2008 10:55 am

Re: Closing TCP connections

Post by SeeCwriter »

Isn't it normally the Ethernet controller that responds with an ACK packet after receiving a valid TCP packet? But even if it isn't in this case here, when a valid packet is received and the FIN flag is set, why doesn't the ACK packet include setting the FIN flag as well?

I use timeouts. But because the timeout is 5-minutes, a host times out waiting for a FIN response and sends a reset packet to the module. The keep alive function isn't that useful because it doesn't provide any feedback. The function's description says "This function checks to see if the other end of a TCP connection is still responding...". Yet it returns no information. It may "check" but it doesn't tell anyone the results. It seems like TcpSendKeepAlive is the perfect place to return an error code indicating whether the socket is still open or not.
User avatar
TomNB
Posts: 541
Joined: Tue May 10, 2016 8:22 am

Re: Closing TCP connections

Post by TomNB »

If the other side did a proper close, then you should not have any delays on read functions. Lets say you have a tcp connection between a netburner and another client. The client does a proper close, and that will be handled by the netburner tcp stack.

If you are in a blocking read() or ReadWithTimeout(), they will return immediately with a negative value.

If you call a read function after the close with the client was completed, it will return immediately with a negative value.

I just ran this scenario using the TCP Sever example and telnet with my 2.8.7 release to verify. My previous comments were to check sockets that were not properly closed by a client. If you wanted to run the same test, change the example to a ReadWithTimout() instead of a read(), telnet in, send a few chars, the close the telnet session properly using "quit", not sure what happens if you just abort out of it.
SeeCwriter
Posts: 608
Joined: Mon May 12, 2008 10:55 am

Re: Closing TCP connections

Post by SeeCwriter »

There are two scenarios that I am dealing with. The first is to detect when a tcp connection (socket) has been closed by the host. What TomNB posted works for that. The other scenario is when there is an open connection, but data is coming in slow, such as from a telnet connection. I don't want the firmware to have to stall for 50msec on every open socket waiting for data to arrive. The firmware has other things to do. And TomNB's example doesn't handle this situation.
I came up with the following functions that seem to work. Function IsSocketReadable Is called to determine if a connection is pending. And SocketClosing is called during a test of all open sockets to see if any have closed.

Code: Select all

/*
 - Returns TRUE if the given socket (file descriptor) is readable.
*/
static bool IsSocketReadable( int fd )
{
  FD_ZERO( &fds_list );                 // reset file descriptor list.
  FD_SET( fd, &fds_list );              //  check for readability.
  return ZeroWaitSelect( FD_SETSIZE, &fds_list, NULL, NULL ) != 0;   // check for readability and return immediately.
}

/*
  - Returns TRUE if the given socket file descriptor has been closed by the other side.
*/
static bool SocketClosing( int fd )
{
  FD_ZERO( &fds_list );                 // reset file descriptor list.
  FD_SET( fd, &fds_list );              // add to list to be checked.
  return ZeroWaitSelect( FD_SETSIZE, NULL, NULL, &fds_list ) != 0;   // check for error event and return immediately.
}
Tests show that the firmware closes its socket consistently under 1msec after the host closes the socket.
User avatar
TomNB
Posts: 541
Joined: Tue May 10, 2016 8:22 am

Re: Closing TCP connections

Post by TomNB »

The second problem seems more like an architecture issue, meaning it is a good connection, but slow, as opposed to a half-open socket or an aborted one. I can't tell exactly what your application is doing, but if you have a task managing multiple tcp connections, have you tried using the select() call? That way any faster connections get serviced with no delay, you can detect errors, close sockets, etc. There is a multi socket example in the \nburn\examples folder under TCP. If you have a loop that services a bunch of tcp connections with read() or ReadWithTimeout(), you will definitely get a lot of lag if the connections are slow. Use select().
User avatar
pbreed
Posts: 1081
Joined: Thu Apr 24, 2008 3:58 pm

Re: Closing TCP connections

Post by pbreed »

The correct thing to do is put the time sensitive other stuff in a different task.

Your select will work...

So will

int dataavail(int fd);

Data avail will tell you if data is availible on the socket, it won't tell you if its closed...
To get that you need to combine it with the TCP state.
SeeCwriter
Posts: 608
Joined: Mon May 12, 2008 10:55 am

Re: Closing TCP connections

Post by SeeCwriter »

The functions I posted earlier solved this issue for me. I didn't have to create a separate task, just call those functions before calling dataavail on the sockets. Function SocketClosing tells me if the connection has been closed by the host. And IsSocketReadable tells me if a tcp connection is pending.
Post Reply