listen( INADDR_ANY, tcp_port, 2 ); question

Discussion to talk about software related topics only.
Post Reply
seulater
Posts: 445
Joined: Fri Apr 25, 2008 5:26 am

listen( INADDR_ANY, tcp_port, 2 ); question

Post by seulater »

i would like to understand the proper close methodology for using a listen call. Specifically how to close dangling open ports that were not properly terminated.

if you look at the typical TCP server connection code:

Code: Select all

 
        int ListenPort = (int) pd;

	// Set up the listening TCP socket
	int fdListen = listen(INADDR_ANY, ListenPort, 2);

	if (fdListen > 0)
	{
		IPADDR	client_addr;
		WORD	port;

		while(1)
		{
            // The accept() function will block until a TCP client requests
            // a connection. Once a client connection is accepting, the 
            // file descriptor fdnet is used to read/write to it. 
			iprintf( "Wainting for connection on port %d...\n", ListenPort );
			int fdnet = accept(fdListen, &client_addr, &port, 0);

			iprintf("Connected to: "); ShowIP(client_addr);
			iprintf(":%d\n", port);

you will notice that this example allows up to 2 client connections to be made. Lets say that a client connects. after the connection is made the client gets it power yanked. Now the TCP server did not receive a proper close. so it still thinks that connection is open. Then after 10 seconds the clients power is restored, and it initiates a new connection, we have one left so we allow it. How can i close the first one, so if this happens again i don't run out of connections ?

I know i can put a timer on it so that if i dont receive anything after so long i can close it, but what if i already got a new connection how can i close the first ?
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: listen( INADDR_ANY, tcp_port, 2 ); question

Post by rnixon »

If the server thinks there is still a connection on the ListenPort, a new connection will not be allowed until the open port is closed. The number of new connection allowed in the listen call is a queue, not an override. This is called a half-open socket and is something that servers always have to deal with. A timer is definitely necessary.

Sometimes things may appear to work, but that usually do to a situation in which there is unacknowledged data pending, so the tcp stack will time it out. But if there is no unacked data, a timer is needed to close the socket.

You can also close the listen socket after a connection is made, and only open it again once the existing connection times out or is closed normally. The listen socket is separate from what you get once you accept.

To make things a little more complicated, you can also have an "override" timer. In this case you can allow a new connection to override an existing connection if some number of seconds expire. It can also be coupled with an inactivity timer.

If it suits your scheme you might want to do both:
1. Close the active connection after a certain amount of inactivity.
2. Allow a new connection to override the existing one after a certain amount of time.

The NetBurner serial to Ethernet factory program does this.
seulater
Posts: 445
Joined: Fri Apr 25, 2008 5:26 am

Re: listen( INADDR_ANY, tcp_port, 2 ); question

Post by seulater »

Thanks,
If the server thinks there is still a connection on the ListenPort, a new connection will not be allowed until the open port is closed
but i tried just this today. I had a client connect, then i unplugged the clients power cable. The server still thought it was connected. I then powered the client back up and it connected again to the server. But i never closed the first connection. so this is what has me confused.

I will look at the demo like you suggested and see what i can gleam off that.
roland.ames

Re: listen( INADDR_ANY, tcp_port, 2 ); question

Post by roland.ames »

Here is some code that I have used to do pretty much what you want. This always allows a new connection to override the old one. fd_Net can be used to indicate whether the connection is open or not. (fd_Net>0 means the connection is open).



#define KEEP_ALIVE_TIMEOUT (1*TICKS_PER_SECOND) // should always be at least one second

#define NETCOMMS_PORT 0xC000

int fd_Net;

void ProcessRxNetComms(void)
{
// process the received data on fd_Net by using read(fd_Net,... )
}


void NetCommsTask( void *pd )
{
int fd_Listen = listen( INADDR_ANY, NETCOMMS_PORT, 1 );
if ( fd_Listen > 0 )
{
while(1)
{
IPADDR client_addr;
WORD client_port;

fd_Net = accept(fd_Listen, &client_addr, &client_port, 0);

if ( fd_Net > 0 )
{
iprintf("fd_Net connected to: ");
ShowIP( client_addr );
iprintf(":%d\n", client_port);

while( fd_Net )
{
fd_set read_fds;
fd_set error_fds;
FD_ZERO( &read_fds );
FD_ZERO( &error_fds );
FD_SET( fd_Listen, &read_fds );
FD_SET( fd_Net, &read_fds );
FD_SET( fd_Net, &error_fds );

if ( select( FD_SETSIZE, &read_fds, (fd_set *)NULL, &error_fds, KEEP_ALIVE_TIMEOUT ) )
{
if ( FD_ISSET( fd_Net, &read_fds ) )
{
ProcessRxNetComms();
}
else if ( FD_ISSET( fd_Net, &error_fds ) )
{
puts("Error on fd_Net");
close(fd_Net);
fd_Net = 0;
}
else if ( FD_ISSET( fd_Listen, &read_fds ) )
{
puts("Read on fd_Listen");
close(fd_Net);
fd_Net = 0;
}
}
else
{ // select() returns zero means timeout
DWORD elapsed = TimeTick - TcpGetLastRxTime(fd_Net);
if ( elapsed > (2*KEEP_ALIVE_TIMEOUT) )
{
puts("Timeout on fd_Net");
close(fd_Net);
fd_Net = 0;
}
else if ( elapsed > KEEP_ALIVE_TIMEOUT )
{
TcpSendKeepAlive(fd_Net);
}
}
}
puts("NetComms Stream Closed");
}
else
{
iprintf( "NetComms accept error: %d\n", fd_Net);
}
}
}
else
{
iprintf( "NetComms listen error: %d\n", fd_Listen);
}
}
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: listen( INADDR_ANY, tcp_port, 2 ); question

Post by lgitlitz »

You might want to take a look at the keep alive example:
C:\nburn\examples\TCP\TCP_simple_keepalive
seulater
Posts: 445
Joined: Fri Apr 25, 2008 5:26 am

Re: listen( INADDR_ANY, tcp_port, 2 ); question

Post by seulater »

Thanks very much for all your help guys!

Does TcpGetLastRxTime & TcpSendKeepAlive work with SSL connections?

I am printing the result of TcpGetLastRxTime, and it returns 0 every time. Yet the client is sending it data every 15 seconds.
User avatar
lgitlitz
Posts: 331
Joined: Wed Apr 23, 2008 11:43 am
Location: San Diego, CA
Contact:

Re: listen( INADDR_ANY, tcp_port, 2 ); question

Post by lgitlitz »

The KeepAlive functions do not currently work for SSL connections, only for regular TCP. I just added this functionality and it will be in the next release.
The problem here is that each SSL socket is linked to a different standard TCP socket. This TCP socket is where encrypted data is sent and received. The SSL socket is where you send and read the decrypted data but this socket is not connected to the normal TCP stack. You need to send and and keepalive and check the last rx time on the underlying TCP socket not the SSL socket. Here are the functions I added to SSL.cpp:

Code: Select all

DWORD SSL_TcpGetLastRxTime( int fd )
{
   SSLSocket_Record * pr = GetSSLRecord( fd );
   if ( pr == NULL )
   {
      return TcpGetLastRxTime( fd );
   }
   else
   {
      return TcpGetLastRxTime( pr->tcp_fd );
   }
}

void SSL_TcpSendKeepAlive( int fd )
{
   SSLSocket_Record * pr = GetSSLRecord( fd );
   if ( pr == NULL )
   {
      TcpSendKeepAlive( fd );
   }
   else
   {
      TcpSendKeepAlive( pr->tcp_fd );
   }
}

-Larry
seulater
Posts: 445
Joined: Fri Apr 25, 2008 5:26 am

Re: listen( INADDR_ANY, tcp_port, 2 ); question

Post by seulater »

ok, that explain why it doesn't work ;)
Post Reply