keithp@azure.UUCP (Keith Packard) (07/24/85)
I have been trying to use INET domain sockets in an application that previously used UNIX domain sockets. I wanted to use INET sockets so I could use my application from multiple machines and, although that portion works correctly, I have discovered an undocumented "feature" of INET sockets: when a process writes on a socket without a reader the familiar SIGPIPE signal is not sent and, in fact, *no* error indication at all! Have I done something wrong? Below is a shell-archive that contains two sets of programs, they are effectively identical except that one uses unix domain sockets and the other uses inet sockets. Type "make test" to see if SIGPIPE is sent for inet sockets, the expected output for each set is: hello world SIGPIPE caught Keith Packard ...!tektronix!azure!keithp ------------------------a clasic shell archive------------------ : files: : : Makefile : binet.c : bunix.c : cinet.c : cunix.c : sed 's/^X//' << \%%%%%%EOF%%%%%%% >Makefile X# X# makefile for SIGPIPE test X# XPROGS=bunix cunix binet cinet X Xtest: all X bunix X cunix X binet X cinet X Xall: $(PROGS) X Xbunix: bunix.o X cc -o bunix bunix.o Xcunix: cunix.o X cc -o cunix cunix.o Xbinet: binet.o X cc -o binet binet.o Xcinet: cinet.o X cc -o cinet cinet.o %%%%%%EOF%%%%%%% sed 's/^X//' << \%%%%%%EOF%%%%%%% >binet.c X/* X * server process, AF_INET version X */ X# include <sys/types.h> X# include <sys/socket.h> X# include <netinet/in.h> X Xstruct sockaddr_in addr = { AF_INET, 29997 }; X Xmain () X{ X int s, t, cnt; X char buf[1024]; X X if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1) X perror ("server socket"); X setsockopt (s, SOL_SOCKET, SO_REUSEADDR, 0, 0); X if (bind (s, &addr, sizeof (addr)) == -1) X perror ("server bind"); X if (listen (s, 5) == -1) X perror ("server listen"); X if (fork () > 0) X _exit (0); X cnt = sizeof (addr); X if ((t = accept (s, &addr, &cnt)) == -1) X perror ("server accept"); X if (shutdown (t, 1) == -1) X perror ("server shutdown"); X /* X * read just one message and X * carefully close the sockets X */ X if ((cnt = read (t, buf, 1024)) == -1) X perror ("server read"); X if (write (1, buf, cnt) != cnt) X perror ("server write"); X close (t); X close (s); X _exit (0); X} %%%%%%EOF%%%%%%% sed 's/^X//' << \%%%%%%EOF%%%%%%% >bunix.c X/* X * server process, AF_UNIX version X */ X# include <sys/types.h> X# include <sys/socket.h> X# include <sys/un.h> X Xstruct sockaddr_un addr = { AF_UNIX, "socket" }; X Xmain () X{ X int s, t, cnt; X char buf[1024]; X X if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) X perror ("server socket"); X setsockopt (s, SOL_SOCKET, SO_REUSEADDR, 0, 0); X if (bind (s, &addr, sizeof (addr)-2) == -1) X perror ("server bind"); X if (listen (s, 5) == -1) X perror ("server listen"); X if (fork () > 0) X _exit (0); X cnt = sizeof (addr); X if ((t = accept (s, &addr, &cnt)) == -1) X perror ("server accept"); X if (shutdown (t, 1) == -1) X perror ("server shutdown"); X /* X * read just one message and X * carefully close the sockets X */ X if ((cnt = read (t, buf, 1024)) == -1) X perror ("server read"); X if (write (1, buf, cnt) != cnt) X perror ("server write"); X close (t); X close (s); X unlink ("socket"); X _exit (0); X} %%%%%%EOF%%%%%%% sed 's/^X//' << \%%%%%%EOF%%%%%%% >cinet.c X/* X * client process, AF_INET version X */ X X# include <sys/types.h> X# include <sys/socket.h> X# include <netinet/in.h> X# include <signal.h> X# include <netdb.h> X Xstruct sockaddr_in addr = { AF_INET, 29997 }; X Xmain () X{ X int s, t, cnt; X char buf[1024]; X int pipedead (); X X struct hostent *gethostbyname (), *hostent; X /* X * local host address X */ X hostent = gethostbyname ("localhost"); X addr.sin_addr.s_addr = *(int *)hostent->h_addr; X s = socket (AF_INET, SOCK_STREAM, 0); X if (connect (s, &addr, sizeof (addr)) == -1) X perror ("socket connect"); X shutdown (s, 0); X /* X * write one message and wait a bit, X * this way the server will read from X * the socket and exit before the X * second write X */ X if (write (s, "hello world\n", 12) != 12) X perror ("first write in client"); X sleep (2); X signal (SIGPIPE, pipedead); X /* X * this *should* cause a SIGPIPE X * to be sent to this process as X * the server has exited at this time X */ X if (write (s, "sigpipe?\n", 9) != 9) X perror ("second write in client"); X exit (0); X} X Xpipedead () X{ X write (2, "SIGPIPE caught\n", 15); X _exit (0); X} %%%%%%EOF%%%%%%% sed 's/^X//' << \%%%%%%EOF%%%%%%% >cunix.c X/* X * client process, AF_UNIX version X */ X X# include <sys/types.h> X# include <sys/socket.h> X# include <sys/un.h> X# include <signal.h> X Xstruct sockaddr_un addr = { AF_UNIX, "socket" }; X Xmain () X{ X int s, t, cnt; X char buf[1024]; X int pipedead (); X X s = socket (AF_UNIX, SOCK_STREAM, 0); X if (connect (s, &addr, sizeof (addr)-2) == -1) X perror ("socket connect"); X shutdown (s, 0); X /* X * write one message and wait a bit, X * this way the server will read from X * the socket and exit before the X * second write X */ X if (write (s, "hello world\n", 12) != 12) X perror ("first write in client"); X sleep (2); X signal (SIGPIPE, pipedead); X /* X * this *should* cause a SIGPIPE X * to be sent to this process as X * the server has exited at this time X */ X if (write (s, "sigpipe?\n", 9) != 9) X perror ("second write in client"); X exit (0); X} X Xpipedead () X{ X write (2, "SIGPIPE caught\n", 15); X _exit (0); X} %%%%%%EOF%%%%%%%