Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TCP connect in Non Blocking Mode

9 views
Skip to first unread message

Prabhu

unread,
Apr 22, 2008, 2:55:29 AM4/22/08
to
Hi,

My client application tries to connect to the server in the following
manner:

..../
err = connect(sd, (struct sockaddr*) &sa, sizeof(sa));

if(err == -1)
{
if(errno == EINPROGRESS)
{
struct timeval l_connect_timeout;
int l_fds;
l_connect_timeout.tv_usec=0;
l_connect_timeout.tv_sec=30; //30 seconds.

while(1)
{
l_fds=select(sd+1, NULL,&filedes_set,NULL,
&l_connect_timeout);
if(l_fds == 0) //timed out
return 0;
else if(l_fds < 0) //select failed
return 0;
else
{
int l_sock_optval=-1;
int l_sock_optval_len=sizeof(l_sock_optval);
if(getsockopt(sd, SOL_SOCKET, SO_ERROR, (int*)&l_sock_optval,
(socklen_t*)&l_sock_optval_len) !=0)
{

return 0;
}

if(l_sock_optval == 0)
{
//connected to server
break;
}
}


}

}

This works fine. The issue that I face is when the server refuses
connection by sending RST for the SYN from client. The select waits
for 30 seconds and later returns timing out. RST though is sent
immediately by the server. The client application need to capture the
RST as soon as it arrives. How do we achieve that. Why does not the
select return immediately when the RST arrives at client?

Thanks,
Prabhu. S

Dan Lanciani

unread,
Apr 22, 2008, 3:33:08 AM4/22/08
to

Are you sure it doesn't? You have a loop around the select(). When
select() indicates that the socket is writable you retrieve and clear
the socket's stored error with getsockopt(...SO_ERROR...). Then if the
error is not zero you loop back to the select(). Since the socket's
stored error is no longer set (and obviously there is no connection) the
socket is not considered writable by select(). Thus it will block until
your timeout expires. This will happen for any error; not just a refused
connection. Does this code really work fine for any case but success?

Dan Lanciani
ddl@danlan.*com

Prabhu

unread,
Apr 22, 2008, 5:21:08 AM4/22/08
to
On Apr 22, 12:33 pm, ddl@danlan.*com (Dan Lanciani) wrote:

Dan,

Yes. It seems like the code seems like to work for only successful
scenarios. But how can the applications handle RSTs immediately. I
tried the following way to do the connection:

err = connect(sd, (struct sockaddr*) &sa, sizeof(sa));

if(err == -1)
{
if(errno == EINPROGRESS)
{

char lbuf[] = {0x00};

while(1)
{
int temp=0;


if(send(sd,lbuf,0,0 ) == -1) //send zero byte

{
temp = errno;
if(temp== ECONNREFUSED)
{
//connection refused!

return 0;
}
else if(temp== EAGAIN )
{
//try again
}
else if(temp == EHOSTUNREACH)
{
//No route to AG address specified
return 0;
}
else if(temp==ETIMEDOUT)
{
//Connection timed out
return 0;
}
else if(temp == ECONNRESET)
{
//Connection reset by peer
return 0;
}
else
return 0;

}
else
break; //connected to server.
}
}
}

This method was successful. It also helped in catching RSTs
immediately. But the problem with this method is my application
creates hundreds of threads(>500). Each thread would try connecting to
the server. Under stress the application reports SIGPIPEs , possibly
because of 'send' in the connection process. But I observe connections
are successful. Also I see a marked increased in the CPU utilization
by the application with this method.

Thanks,
Prabhu. S

David Schwartz

unread,
Apr 22, 2008, 5:27:23 PM4/22/08
to
On Apr 22, 2:21 am, Prabhu <yespra...@gmail.com> wrote:

> Dan,
>
> Yes. It seems like the code seems like to work for only successful
> scenarios. But how can the applications handle RSTs immediately. I
> tried the following way to do the connection:

Dan already answered that question. The code you demonstrated has a
bug in it, so fix the bug. Then see if you still have the problem with
RSTs.

[snip]


> This method was successful. It also helped in catching RSTs
> immediately. But the problem with this method is my application
> creates hundreds of threads(>500). Each thread would try connecting to
> the server. Under stress the application reports SIGPIPEs , possibly
> because of 'send' in the connection process. But I observe connections
> are successful. Also I see a marked increased in the CPU utilization
> by the application with this method.

That's awful, don't do that. Fix the bug Dan found.

DS

Prabhu

unread,
Apr 22, 2008, 10:02:42 PM4/22/08
to

I did the following to fix. It is working now.:

if(getsockopt(sd, SOL_SOCKET, SO_ERROR, (int*)&l_sock_optval,
(socklen_t*)&l_sock_optval_len) !=0)
{
return 0;
}

if(l_sock_optval == 0)
{
//connection sucess
break;
}
else if(l_sock_optval == ECONNREFUSED)
{
//connection refused.
return 0;
}

This is appropriate, isn't?. Please comment.

Thanks,
Prabhu. S

Dan Lanciani

unread,
Apr 23, 2008, 12:24:59 AM4/23/08
to

| I did the following to fix. It is working now.:
|
| if(getsockopt(sd, SOL_SOCKET, SO_ERROR, (int*)&l_sock_optval,
| (socklen_t*)&l_sock_optval_len) !=0)
| {
| return 0;
| }
|
| if(l_sock_optval == 0)
| {
| //connection sucess
| break;
| }
| else if(l_sock_optval == ECONNREFUSED)
| {
| //connection refused.
| return 0;
| }
|
| This is appropriate, isn't?. Please comment.

It doesn't deal with errors other than ECONNREFUSED. Or at least, it doesn't
deal with them in a way I would consider useful. I assume this code is still
within a loop. What are you trying to accomplish with that loop? You can't
compensate for a select() that falses positive; the select()/SO_ERROR method
of handling asynchronous connect()s implicitly depends on a select() that
does not false in this context. If you are indeed worried about false
positives you need to use a select()/connect() approach. If not then you
should eliminate the loop.

Dan Lanciani
ddl@danlan.*com

EJP

unread,
Apr 25, 2008, 3:55:09 AM4/25/08
to
Prabhu wrote:
> This works fine.

It shouldn't. You're supposed to repeat the connect() call once the
socket FD selects as writable, and then test the result of *that*.

David Schwartz

unread,
Apr 25, 2008, 6:55:38 PM4/25/08
to

Or you can issue a non-blocking read or you can use
getsockopt(SO_ERROR). But you are quite correct that a zero-byte
operation is undefined and should definitely not be used.

DS

0 new messages