lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-users] socket: LWIP_ACCEPT problem?


From: David Empson
Subject: Re: [lwip-users] socket: LWIP_ACCEPT problem?
Date: Fri, 07 Mar 2008 11:06:16 +1300

The issue you are encountering is due to standard behaviour of TCP. When a client connects to a server, the client specifies a local port number, and the server's well known port number. These are used along with the IP addresses to uniquely identify a TCP connection.
 
When the server end closes the connection first, and the client reacts by immediately closing its side, the sequence of packets that goes back and forth is like this:
 
1. Server sends FIN
2. Client responds with ACK
3. Client sends FIN (can be merged with the previous ACK packet if the client is fast enough closing its connection)
4. Server responds with ACK
 
Consider what happens if any of these packets is lost.
 
1. If the server's FIN is lost, the server will time out on the ACK response and resend the FIN. The client end doesn't know the connection is closing until it gets the retried FIN.
 
2. If the client's ACK is lost, the server will time out on the ACK response and resend the FIN. The client end discards the repeat FIN as a duplicate and resends the ACK.
 
3. If the client's FIN is lost, the client will time out on the ACK response and resend the FIN. The server end doesn't know that the client has closed its half of the connection until it gets the retried FIN.
 
4. If the server's ACK is lost, the client will time out on the ACK response and resend the FIN. The server end discards the repeat FIN as a duplicate and resends the ACK.
 
There is a timeout on this last "TIMED_WAIT" state, typically two minutes. During this time, the station which closed the connection first (in this case, the server) is waiting in case the other station missed the final ACK and it needs to be resent. At the end of that timeout, it is assumed that the client got the ACK and the server fully closes its connection.
 
If the server is in this state, and the client tries to establish a new connection using the same IP address and port number at both ends, then it is regarded as part of the same connection as the previous one. A connection can't be reopened while it is established or in the closing states (SYN is only valid in the opening stages), so the server rejects or ignores the client's connection attempt.
 
Some TCP/IP stacks might be clever about this and recognise a new connection (SYN) with the same port number by cutting short the TIMED_WAIT delay and immediately closing the old connection. LWIP probably doesn't do that.
 
The problem can easily be avoided by having the client use a different port number for opening a new connection. The normal convention for TCP is that the client allocates a random or incrementing port number in the high range (49152+) for each new connection. Unless it happens to pick the one which was used to the same port on the same server within the last two minutes, this won't be confused with a previous connection in the TIMED_WAIT state.
 
If the client end closes the connection first, then the server goes straight to the CLOSED state as soon as it gets the final ACK. In that case, it is the client which is waiting for two minutes in the TIMED_WAIT state. This will prevent the client reusing the same port number, because it hasn't been fully closed yet.
 
If the server and client close the connection at the same time (their FINs cross in transit) then they will both be in the TIMED_WAIT state for two minutes after both ACKs have been sent and received.
 
The SO_LINGER socket option is typically used to modify the close sequence so that it will do an "abortive close" by sending a RST instead of FIN. This can result in loss of data which hasn't been sent or acknowledged yet. It also doesn't seem to be a complete solution: if the client uses SO_LINGER and sends RST but the server doesn't receive it, then the client still won't be able to open a new connection using the same local port number, because the server won't have fully closed the previous connection. If the server uses SO_LINGER then the client might miss the RST and not know the connection was closed.
 
Is there a particular reason that you need to use the same port number for re-establishing the connection? It is far easier if you just wait two minutes before reconnecting, or use a different local port number for each connection.
 
----- Original Message -----
From: Piero 74
Sent: Thursday, March 06, 2008 9:31 PM
Subject: Re: [lwip-users] socket: LWIP_ACCEPT problem?

My server application in lwip board, does close operation on socket.
My client exit for "connection closed by peer" and close its socket. I'm using a run time enviroment to write in easy way windows test application, so, i cannot set option in socket (i have only basic blocks: listener, connect, read, write and close)

If i write a server with the same enviroment, and use it with client, the problem doesn't happen (so: client can reuse the same local port)

I want to know only how lwip manage this situation and why doesn't accept connection.... i'm trying to understand using debugger, but it's very difficoult debug a tcp connection!
And if there is a work aorund... i'm thinking to try SO_LINGER option in my server.... but i don't know if it's correct.

PS: i'm using lwip on embedded system.

Thanks,
Piero

2008/3/5, Bikram Chatterjee <address@hidden>:
> I have a simple client on pc running windows.
>
> If the client fixs his local port, accept function accept connection only the first time, after seems it doesn't accept.
>
> If my client changes its local port for EVERY attempt, accept works weel!!!
>
> What is the problem???

A TCP connection is uniquely identified by six tuple at any end point
(src_addr, src_port, dst_addr, dst_port). You see that in your case
none of the parameters in the tuple has changed in the second
connection. So the stack has no way of separating packets from this
new connection from that of the previous one.

Are you sure that the second connection actually have originated from
the client? The stack on your client m/c should have stopped it.


Bikram

On Wed, Mar 5, 2008 at 10:12 PM, Bill Auerbach
<address@hidden> wrote:
>
> I wrote that because for me the client (Win32) wouldn't reopen the port if I clicked Close and then Open in my program.  Setting SO_LINGER resolved this.  You didn't mention your client, so I guessed (wrong).
>
> How to fix from lwIP?  Nothing you've written indicates it is lwIP, especially if a 3rd party client works.

> ________________________________

>
> From: lwip-users-bounces+bauerbach=address@hidden [mailto:address@hidden] On Behalf Of Piero 74
> Sent: Wednesday, March 05, 2008 10:47 AM
>
> To: Mailing list for lwIP users
> Subject: Re: [lwip-users] socket: LWIP_ACCEPT problem?
>
> Now i'm using a simple client which i wrote....
> By my board will work with a third part client, so, i cannot know if this pc application will set SO_LINGER.
>
> So, how i can fix the problem from lwip code???
>
> thanks,
> Piero
>
>
> 2008/3/5, Bill Auerbach <address@hidden>:
>
> Change the client's SO_LINGER option so it doesn't hang on to the connection.
>
> Bill
> ________________________________

>
> From: lwip-users-bounces+bauerbach=address@hidden [mailto:address@hidden] On Behalf Of Piero 74
> Sent: Wednesday, March 05, 2008 10:14 AM
> To: Mailing list for lwIP users
> Subject: [lwip-users] socket: LWIP_ACCEPT problem?
>
> Hi all.
>
> I'm testing socket on lwip 130rc1
>
> this is a piece of my code:
>
>   // Create a new tcp connection handle
>   //----------------------------------------------------------
>   sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
>   serv_addr.sin_family = AF_INET;
>   serv_addr.sin_addr.s_addr = INADDR_ANY;
>   serv_addr.sin_port = htons(20000);
>   bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
>   //    setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, bOptLen);
>   listen(sockfd, 0);
>   //----------------------------------------------------------
>
>   // Loop forever
>   while(1)
>   {
>     // Wait for connection.
>     //------------------------------------------------------
>     newsockfd = accept(sockfd, &addr, &addrlen);
>     bOptVal = TRUE;
>     //------------------------------------------------------
>     for (i=0; i<10; i++)
>     {
>       // send 10 hello world!
>       lwip_write(newsockfd, provatx, 12);
>     }
>
>     // close connection
>     close(newsockfd);
>   }
>
> I have a simple client on pc running windows.
>
> If the client fixs his local port, accept function accept connection only the first time, after seems it doesn't accept.
>
> If my client changes its local port for EVERY attempt, accept works weel!!!
>
> What is the problem???
>
> bye,
> Piero

reply via email to

[Prev in Thread] Current Thread [Next in Thread]