[comp.unix.programmer] Can you partially shutdown

Andrew.Vignaux@comp.vuw.ac.nz (Andrew Vignaux) (04/02/91)

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

Andrew.Vignaux@comp.vuw.ac.nz (Andrew Vignaux) (04/07/91)

In <1991Apr02.101330.22133@comp.vuw.ac.nz>, I wrote:
> 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()?
> [excessively long example program deleted]

The 4.3 "Devil" book has a justification for this on page 320,
Socket-to-Protocol Interface:

: * PRU_SHUTDOWN: Shut down socket data transmission.  This call is
:   used to indicate that no more data will be sent.  The protocol
:   may, at its discretion, deallocate any data structures related to
:   the shutdown% and/or notify a connected peer of the shutdown.

So, it seems that it's up to the protocol handling code.  Why is the
"may, at its discretion" qualification there though?  To handle
protocols that you can't partially shutdown()?  Are there any (stream)
domains where it is hard to notify a peer of the partial shutdown?  Is
AF_UNIX really such a domain?

Without being able to shutdown() one side of a socket is there much
useful work you can do with socketpair()@ that you can't do (more
portably) with pipe()s#?  Actually I can partially answer that myself
(again): datagrams and passing access rights.

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

% Should that be some other word than shutdown, e.g. socket to be
  shutdown?

@ I could find only one program that used socketpair() (in the portion
  of our source archive that happened to be uncompressed) and it
  seemed to be in a routine which usually used ptys.

# When another domains/types/protocol combination acknowledges the
  PRU_CONNECT2 request this question shall be considered null and
  void.