Attempt to invoke connect(2) on already connected unix domain datagram socket fails with ECONNRESET

Maxim Sobolev sobomax at portaone.com
Mon Jan 10 08:46:24 PST 2005


Maxim Sobolev wrote:
> Further investigation revealed that the said problem only happens when 
> the program is trying to re-connect() socket object which previously has 
> been connected to the unix domain socket closed on the server side at 
> the time when the second connect() is called. Attached please find more 
> simple testcase.

It seems that I've found source of the problem. It is caused by the fact 
that when server closes its side of unix domain socket it causes 
unp_drop(ref, ECONNRESET) to be called on client side of the connection, 
which in turn results in so_error member of client's struct socket to be 
set to ECONNRESET. Since we don't do any more reads on the client side 
of the connection, this error is never cleared up and then being picked 
up as a connection error by kern_connect() routine, which is obviously 
incorrect. The funny thing is that despite that error (ECONNRESET) one 
can still use resulting socket like if no error has happened.

Attached please find which I believe should fix the problem in question. 
I would appreciate if somebody can review it.

Thanks in advance!

Regards,

Maxim

-------------- next part --------------
Index: uipc_socket.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.208.2.6
diff -d -u -r1.208.2.6 uipc_socket.c
--- uipc_socket.c	16 Nov 2004 08:15:07 -0000	1.208.2.6
+++ uipc_socket.c	10 Jan 2005 16:23:07 -0000
@@ -530,10 +530,19 @@
 	 */
 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
-	    (error = sodisconnect(so))))
+	    (error = sodisconnect(so)))) {
 		error = EISCONN;
-	else
+	} else {
+		SOCK_LOCK(so);
+		/*
+		 * Prevent accumulated error from previous connection
+		 * from biting us.
+		 */
+		so->so_error = 0;
+		SOCK_UNLOCK(so);
 		error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td);
+	}
+
 	return (error);
 }
 


More information about the freebsd-current mailing list