preserving message boundaries on named pipes - System V

Don Libes libes at cme.nbs.gov
Sat May 20 03:42:15 AEST 1989


In article <8486 at chinet.chi.il.us> les at chinet.chi.il.us (Leslie Mikesell) writes:
>In article <571 at lehi3b15.csee.Lehigh.EDU> murrey at lehi3b15.csee.Lehigh.EDU (Erik Murrey) writes:
>>Is it possible to preserve message boundaries on named pipes ...
>
>The easy way is to use fixed length write()'s and matching read()'s.
>If the input is sufficiently varied that this approach would impose
>a lot of overhead you might precede the data with a length value.

I wrote two functions that preserve message boundaries on any stream
using just this idea.

	sized_write(fd,buffer,nbytes) - just like write()
	sized_read(fd,buffer,nbytes) - just like read() except that
					it returns what was written
					by one call to sized_write()

They work on any stream, not just named pipes.  I originally used them
on top of TCP.

>This
>should be done as a single write() if multiple processes are writing
>to the same FIFO to avoid the possibility of interleaving between the
>length and data.

I didn't go this far, mainly because I can't see a simple way to do
this without copying and reserving or mallocing a potentially enormous
auxiliary space.

Don Libes          libes at cme.nbs.gov      ...!uunet!cme-durer!libes


----------------------------cut here---------------------------------
/* sized_io.c - Preserve message boundaries in stream io.

These two routines enable us to use stream io, but still detect end of
record marks.  Each call to sized_read() returns a complete buffer, that is,
what was written by one call to sized_write().

Notes:

The IPC system seems to be a confusing mess.  I.e. unusual conditions are
handled in all different ways.  Specifically,

While we are reading, if the writer goes away, we sometimes get a read()
== -1 && errno == ECONNRESET.  Sometimes we get a read() == 0.  Why the
difference?

While we are writing, if the reader goes away, we get a signal (SIGPIPE).


Don Libes
National Institute of Standards and Technology
(301) 975-3535
libes at cme.nist.gov
...!uunet!cme-durer!libes

*/

#include <stdio.h>
#include <errno.h>
extern int errno;
#include <sys/types.h>
#include <netinet/in.h>

int	/* returns number of bytes read or -1 if error (i.e. EOF) */
sized_read(fd,buffer,maxbytes)
int fd;
char *buffer;
int maxbytes;	/* unlike read(), this parameter is the maximum size of */
		/* the buffer */
{
	int size;	/* size of incoming packet */
	int cc;
	int rembytes;	/* remaining bytes */
	u_long netlong;	/* network byte ordered length */

	/* read header */
	if (sizeof(size) != (cc = read(fd,(char *)&netlong,sizeof(netlong)))){
		/* if the connection is broken, we end up here */
#ifdef DEBUG
		fprintf(stderr,"sized_read: expecting buffer size but only read %d chars\n",cc);
#endif
		if (cc == -1)
			if (errno != ECONNRESET) perror("read");
		return(-1);
	}

	size = ntohl(netlong);

	/* read data */
	if (size == 0) return(0);
	else if (size > maxbytes) {
		fprintf(stderr,"sized_read: buffer too small.  ");
		fprintf(stderr,"buffer size was %d  actual size was %d\n",
			maxbytes,size);
		return(-1);
	}

	/* handle buffers to large to fit in one transfer */
	rembytes = size;
	while (rembytes) {
		if (-1 == (cc = read(fd,buffer,rembytes))) {
			fprintf(stderr,"sized_read(,,%d) = read(,,%d) = %d\n",
							size,rembytes,cc);
			if (errno != ECONNRESET) perror("read");
			return(-1);
		}

		/* new! */
		if (0 == cc) {	/* EOF - process died */
			return(-1);
		}

#ifdef DEBUG
		if (rembytes != cc)
			fprintf(stderr,"sized_read(,,%d) = read(,,%d) = %d\n",
							size,rembytes,cc);
#endif
		/* read() returned more bytes than requested!?!?!?! */
		/* this can't happen, but appears to be anyway */
		if (cc > rembytes) {
			fprintf(stderr,"sized_read(,,%d) = read(,,%d) = %d!?!?!\n",
							size,rembytes,cc);
			fprintf(stderr,"read() returned more chars than requested!  Aborting program.\n");
			abort();
		}
		buffer += cc;
		rembytes -= cc;
	}
	return(size);
}

int	/* returns number of data bytes written or -1 if error */
sized_write(fd,buffer,nbytes)
int fd;
char *buffer;
int nbytes;
{
	int cc;
	int rembytes;
	u_long netlong;	/* network byte ordered length */

	/* write header */
	netlong = htonl(nbytes);
	if (sizeof(nbytes) != (cc = write(fd,(char *)&netlong,
							sizeof(netlong)))) {
#ifdef DEBUG
		/* this can never happen (SIGPIPE will always occur first) */
		fprintf(stderr,"sized_write: tried to write buffer size but only wrote %d chars\n",cc);
#endif
		if (cc == -1) perror("write");
		return(-1);
	}

	/* write data */
	if (nbytes == 0) return(0);

	rembytes = nbytes;
	while (rembytes) {
		if (-1 == (cc = write(fd,buffer,rembytes))) {
		      fprintf(stderr,"sized_write(,,%d) = write(,,%d) = %d\n",
							nbytes,rembytes,cc);
			perror("write");
			return(-1);
		}
#ifdef DEBUG
		if (rembytes != cc) 
		      fprintf(stderr,"sized_write(,,%d) = write(,,%d) = %d\n",
							nbytes,rembytes,cc);
#endif
		buffer += cc;
		rembytes -= cc;
	}
	return(nbytes);
}



More information about the Comp.unix.wizards mailing list