Can you partially shutdown() a UNIX domain socket?

Andrew Vignaux Andrew.Vignaux at comp.vuw.ac.nz
Tue Apr 2 20:13:30 AEST 1991


Can I shutdown(,1) an AF_UNIX socket so that it propagates the
"end-of-file" indication to the other end?  I seem to be able to do this
with AF_INET sockets.  Am I asking too much from shutdown()?

I have tried the following program under MORE/bsd on our hp300s, HPUX
7.0 on 9000/{8,3}00, SunOS 4.1, and AIX 3.1.  The program compiled with
-DINET gets a 0 read in the child after shutdown() is called in the
parent, the -UINET program doesn't.  BTW: my original 4-fd select() loop
in the parent has been simplified (too much?) into a synchronised
for(;;) loop.

Should I just use pipe()s?  My real program talks to a remote server
using INET sockets but occasionally I want to fire up a local program
and talk to that.  If I can get the shutdown() to work I can use the
same processing loop because everyone's a socket.  Actually, my real
program is in perl and I've already rewritten it using pipes ;-)

Andrew
-- 
Domain address: Andrew.Vignaux at comp.vuw.ac.nz

-------------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#ifndef INET
# include <sys/un.h>
# define NAME "socket"
#else
# include <netinet/in.h>
#endif

#define DATA1 "In Xanadu, did Kublai Khan . . ."
#define DATA2 "A stately pleasure dome decree . . ."
#define DATA3 "And now for something completely different . . ."

int main()
{
    int family;
    int s, child;
    int sockets[2];
    char buf[1024];

#ifndef INET
    struct sockaddr_un addr;
#else
    int l;
    struct sockaddr_in addr;
#endif

#ifndef INET
    addr.sun_family = family = AF_UNIX;
    strcpy (addr.sun_path, NAME);
#else
    addr.sin_family = family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = 0;
#endif

    if ((s = socket(family, SOCK_STREAM, 0)) < 0) {
	perror("master: socket");
	exit(1);
    }
    if (bind(s, &addr, sizeof(addr)) < 0) {
	perror("master: bind");
	exit(1);
    }

#ifdef INET
    l = sizeof(addr);
    if (getsockname(s, &addr, &l)) {
	perror("master: getsockname");
	exit(1);
    }
#endif
    listen (s, 5);

    setbuf (stdout, (char *)NULL);
    if ((child = fork()) == -1)
	perror("fork");

    else if (child == 0) {	/* This is the child. */
	int r;

	if ((sockets[1] = accept(s, (struct sockaddr *)0, (int *)0)) < 0) {
	    perror("child: accept");
	    exit(1);
	}
#ifndef INET
	if (unlink (addr.sun_path) < 0)
	    perror ("child: unlink");
#endif
	while (1) {
	    r = read(sockets[1], buf, 1024);
	    if (r < 0) {
		perror("child: read");
		exit (1);
	    }
	    else if (r == 0) {
		(void) fprintf (stderr, "<eof>\n");
		break;
	    }
	    (void) printf("%d==>%.*s\n", r, r, buf);
	    if (write(sockets[1], DATA2, sizeof(DATA2)) < 0)
		perror("child: write");
	}
	if (write(sockets[1], DATA3, sizeof(DATA3)) < 0)
	    perror("child: end write");
	if (close(sockets[1]) < 0)
	    perror("child: close");

    } else {			/* This is the parent. */
	int i, r;

	if ((sockets[0] = socket(family, SOCK_STREAM, 0)) < 0) {
	    perror("parent: socket"); exit(1);
	}
	if (connect (sockets[0], &addr, sizeof(addr)) < 0) {
	    perror("parent: connect"); exit(1);
	}
	for (i = 0; i < 5; i++) {
	    if (write(sockets[0], DATA1, sizeof(DATA1)) < 0)
		perror("parent: write");
	    if ((r = read(sockets[0], buf, 1024)) < 0)
		perror("parent: read");
	    (void) printf("%d-->%.*s\n", r, r, buf);
	}
	if (shutdown(sockets[0], 1) < 0)
	    perror("parent: shutdown");
	if ((r = read(sockets[0], buf, 1024)) < 0)
	    perror("parent: end read");
	(void) printf("%d**>%.*s\n", r, r, buf);
	if (close(sockets[0]) < 0)
	    perror("parent: close");
    }

    return 0;
}



More information about the Comp.unix.programmer mailing list