[268] in linux-net channel archive

home help back first fref pref prev next nref lref last post

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;
 	}

home help back first fref pref prev next nref lref last post