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