[268] in linux-net channel archive
Problem on Linux 1.2.8 with returning errors to nonblocking sockets [+FIX]
daemon@ATHENA.MIT.EDU (Matt Day)
Thu May 4 02:32:04 1995
Date: Wed, 3 May 1995 22:22:28 -0700
From: Matt Day <mday@artisoft.com>
To: submit-linux-dev-net@ratatosk.yggdrasil.com
Cc: A.Cox@swansea.ac.uk, Linus.Torvalds@helsinki.fi
Hi,
In Linux 1.2.8 (and many previous versions), there are a couple problems
with returning connection errors back to a nonblocking connect() call.
For example, if I try to connect a nonblocking socket to a system that's
currently unreachable, here's what happens on Linux 1.2.8:
create socket;
enable nonblocking flag on socket;
connect() socket; (returns EINPROGRESS)
select() on socket; (indicates socket is read- and exception-ready)
connect() socket; (returns EALREADY)
The big problem here is the second connect() returning EALREADY instead
of the correct socket error (EHOSTUNREACH, or whatever). The cause of
this problem is a simple oversight in inet_connect(), and a patch for
that is below.
The second problem is select() returning exception-ready and not
write-ready on a socket with a pending error. Unfortunately, there are
no official specs on the proper behavior of select(), but all the BSD
documentation I could find says that when a socket has a pending error
that select() on that socket should indicate read-ready and write-ready
but not exception-ready. (Exception-ready is for indicating OOB pending
status only.) I think we should be compatible with the BSD select(), so
a fix for tcp_select() is in the patch below.
These problems cause Netscape to fail to report an error when it tries
to connect to a screwed up system.
Thanks,
Matt Day <mday@artisoft.com>
--- net/inet/af_inet.c- Mon Mar 27 14:40:59 1995
+++ net/inet/af_inet.c Wed May 3 21:40:49 1995
@@ -939,8 +939,12 @@
return 0; /* Rock and roll */
}
- if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK))
- return -EALREADY; /* Connecting is currently in progress */
+ if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK)) {
+ if (sk->err != 0)
+ return -sk->err; /* Connection must have failed */
+ else
+ return -EALREADY; /* Connecting is currently in progress */
+ }
if (sock->state != SS_CONNECTING)
{
--- net/inet/tcp.c- Wed May 3 20:12:30 1995
+++ net/inet/tcp.c Wed May 3 21:40:49 1995
@@ -934,6 +934,8 @@
break;
case SEL_OUT:
+ if (sk->err)
+ return 1;
if (sk->shutdown & SEND_SHUTDOWN)
return 0;
if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
@@ -948,7 +950,7 @@
return 1;
case SEL_EX:
- if (sk->err || sk->urg_data)
+ if (sk->urg_data)
return 1;
break;
}