Subject: Missing EOF for socketpair() with SOCK_DGRAM
To: None <tech-net@NetBSD.org>
From: Christian Biere <christianbiere@gmx.de>
List: tech-net
Date: 11/01/2006 06:22:54
Hi,

the following program does not terminate i.e., recv() never returns although
the child exits thus closing the other side of the socket pair.

#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>

int
main(void)
{
	int fd_pair[2] = { -1, -1 };
	pid_t pid;

	if (-1 == socketpair(AF_LOCAL, SOCK_DGRAM, 0, fd_pair))
		err(EXIT_FAILURE, "socketpair");

	pid = fork();
	if ((pid_t) -1 == pid)
		err(EXIT_FAILURE, "fork");

	if (0 == pid) {
		close(fd_pair[0]);
		_exit(EXIT_SUCCESS);
	} else {
		char c;

		close(fd_pair[1]);
		recv(fd_pair[0], &c, sizeof c, 0);
	}

	return EXIT_SUCCESS;
}

For what it's worth, on FreeBSD the program terminates, on Linux recv() doesn't
return either. What's also interesting is that with some minor variations both
processes actually terminate on NetBSD as well as Linux. For example, if I
replace '0 == pid' with '0 != pid', or if I insert "poll(NULL, 0, 1000);"
before recv().

The following fixes the problem here so that recv() returns with ECONNRESET. Are
there any objections or may I commit this?

Index: uipc_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.93
diff -u -p -r1.93 uipc_usrreq.c
--- uipc_usrreq.c	3 Sep 2006 21:15:29 -0000	1.93
+++ uipc_usrreq.c	1 Nov 2006 04:14:26 -0000
@@ -799,7 +800,7 @@ unp_disconnect(struct unpcb *unp)
 			unp2->unp_nextref = unp->unp_nextref;
 		}
 		unp->unp_nextref = 0;
-		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
+		soisdisconnected(unp->unp_socket);
 		break;
 
 	case SOCK_STREAM:

-- 
Christian