Path: utzoo!attcan!uunet!cme!libes From: libes@cme.nbs.gov (Don Libes) Newsgroups: comp.unix.wizards Subject: Re: preserving message boundaries on named pipes - System V Message-ID: <1165@muffin.cme.nbs.gov> Date: 19 May 89 17:42:15 GMT References: <571@lehi3b15.csee.Lehigh.EDU> <8486@chinet.chi.il.us> Reply-To: libes@cme.nbs.gov (Don Libes) Organization: National Institute of Standards and Technology Lines: 175 In article <8486@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes: >In article <571@lehi3b15.csee.Lehigh.EDU> murrey@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@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@cme.nist.gov ...!uunet!cme-durer!libes */ #include #include extern int errno; #include #include 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); }