/usr/src/lib/libast/common/sfio/sfpkrd.c
C | 291 lines | 236 code | 19 blank | 36 comment | 105 complexity | cd61b98ec2ba262bc402b778b8b8de7a MD5 | raw file
- /***********************************************************************
- * *
- * This software is part of the ast package *
- * Copyright (c) 1985-2010 AT&T Intellectual Property *
- * and is licensed under the *
- * Common Public License, Version 1.0 *
- * by AT&T Intellectual Property *
- * *
- * A copy of the License is available at *
- * http://www.opensource.org/licenses/cpl1.0.txt *
- * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
- * *
- * Information and Software Systems Research *
- * AT&T Research *
- * Florham Park NJ *
- * *
- * Glenn Fowler <gsf@research.att.com> *
- * David Korn <dgk@research.att.com> *
- * Phong Vo <kpv@research.att.com> *
- * *
- ***********************************************************************/
- #include "sfhdr.h"
- #if !_PACKAGE_ast
- #ifndef FIONREAD
- #if _sys_ioctl
- #include <sys/ioctl.h>
- #endif
- #endif
- #endif
- /* Read/Peek a record from an unseekable device
- **
- ** Written by Kiem-Phong Vo.
- */
- #define STREAM_PEEK 001
- #define SOCKET_PEEK 002
- #if __STD_C
- ssize_t sfpkrd(int fd, Void_t* argbuf, size_t n, int rc, long tm, int action)
- #else
- ssize_t sfpkrd(fd, argbuf, n, rc, tm, action)
- int fd; /* file descriptor */
- Void_t* argbuf; /* buffer to read data */
- size_t n; /* buffer size */
- int rc; /* record character */
- long tm; /* time-out */
- int action; /* >0: peeking, if rc>=0, get action records,
- <0: no peeking, if rc>=0, get -action records,
- =0: no peeking, if rc>=0, must get a single record
- */
- #endif
- {
- reg ssize_t r;
- reg int ntry, t;
- reg char *buf = (char*)argbuf, *endbuf;
- if(rc < 0 && tm < 0 && action <= 0)
- return sysreadf(fd,buf,n);
- t = (action > 0 || rc >= 0) ? (STREAM_PEEK|SOCKET_PEEK) : 0;
- #if !_stream_peek
- t &= ~STREAM_PEEK;
- #endif
- #if !_socket_peek
- t &= ~SOCKET_PEEK;
- #endif
- for(ntry = 0; ntry < 2; ++ntry)
- {
- r = -1;
- #if _stream_peek
- if((t&STREAM_PEEK) && (ntry == 1 || tm < 0) )
- {
- struct strpeek pbuf;
- pbuf.flags = 0;
- pbuf.ctlbuf.maxlen = -1;
- pbuf.ctlbuf.len = 0;
- pbuf.ctlbuf.buf = NIL(char*);
- pbuf.databuf.maxlen = n;
- pbuf.databuf.buf = buf;
- pbuf.databuf.len = 0;
- if((r = ioctl(fd,I_PEEK,&pbuf)) < 0)
- { if(errno == EINTR)
- return -1;
- t &= ~STREAM_PEEK;
- }
- else
- { t &= ~SOCKET_PEEK;
- if(r > 0 && (r = pbuf.databuf.len) <= 0)
- { if(action <= 0) /* read past eof */
- r = sysreadf(fd,buf,1);
- return r;
- }
- if(r == 0)
- r = -1;
- else if(r > 0)
- break;
- }
- }
- #endif /* stream_peek */
- if(ntry == 1)
- break;
- /* poll or select to see if data is present. */
- while(tm >= 0 || action > 0 ||
- /* block until there is data before peeking again */
- ((t&STREAM_PEEK) && rc >= 0) ||
- /* let select be interrupted instead of recv which autoresumes */
- (t&SOCKET_PEEK) )
- { r = -2;
- #if _lib_poll
- if(r == -2)
- {
- struct pollfd po;
- po.fd = fd;
- po.events = POLLIN;
- po.revents = 0;
- if((r = SFPOLL(&po,1,tm)) < 0)
- { if(errno == EINTR)
- return -1;
- else if(errno == EAGAIN)
- { errno = 0;
- continue;
- }
- else r = -2;
- }
- else r = (po.revents&POLLIN) ? 1 : -1;
- }
- #endif /*_lib_poll*/
- #if _lib_select
- if(r == -2)
- {
- #if _hpux_threads && vt_threaded
- #define fd_set int
- #endif
- fd_set rd;
- struct timeval tmb, *tmp;
- FD_ZERO(&rd);
- FD_SET(fd,&rd);
- if(tm < 0)
- tmp = NIL(struct timeval*);
- else
- { tmp = &tmb;
- tmb.tv_sec = tm/SECOND;
- tmb.tv_usec = (tm%SECOND)*SECOND;
- }
- r = select(fd+1,&rd,NIL(fd_set*),NIL(fd_set*),tmp);
- if(r < 0)
- { if(errno == EINTR)
- return -1;
- else if(errno == EAGAIN)
- { errno = 0;
- continue;
- }
- else r = -2;
- }
- else r = FD_ISSET(fd,&rd) ? 1 : -1;
- }
- #endif /*_lib_select*/
- if(r == -2)
- {
- #if !_lib_poll && !_lib_select /* both poll and select can't be used */
- #ifdef FIONREAD /* quick and dirty check for availability */
- long nsec = tm < 0 ? 0 : (tm+999)/1000;
- while(nsec > 0 && r < 0)
- { long avail = -1;
- if((r = ioctl(fd,FIONREAD,&avail)) < 0)
- { if(errno == EINTR)
- return -1;
- else if(errno == EAGAIN)
- { errno = 0;
- continue;
- }
- else /* ioctl failed completely */
- { r = -2;
- break;
- }
- }
- else r = avail <= 0 ? -1 : (ssize_t)avail;
- if(r < 0 && nsec-- > 0)
- sleep(1);
- }
- #endif
- #endif
- }
- if(r > 0) /* there is data now */
- { if(action <= 0 && rc < 0)
- return sysreadf(fd,buf,n);
- else r = -1;
- }
- else if(tm >= 0) /* timeout exceeded */
- return -1;
- else r = -1;
- break;
- }
- #if _socket_peek
- if(t&SOCKET_PEEK)
- {
- #if __MACH__ && __APPLE__
- /*
- * work around macos 10.4 recv(MSG_PEEK) bug that consumes pipe() data
- */
- struct stat st;
- static int recv_peek_ok;
- if (!recv_peek_ok)
- {
- int fds[2];
- char tst[2];
- tst[0] = 'a';
- tst[1] = 'z';
- recv_peek_ok = (!pipe(fds) && write(fds[1], tst, 2) && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a' && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a') ? 1 : -1;
- close(fds[0]);
- close(fds[1]);
- }
- if (recv_peek_ok < 0 && !fstat(fd, &st) && !S_ISSOCK(st.st_mode))
- {
- r = -1;
- t &= ~SOCKET_PEEK;
- }
- else
- #endif
- while((r = recv(fd,(char*)buf,n,MSG_PEEK)) < 0)
- { if(errno == EINTR)
- return -1;
- else if(errno == EAGAIN)
- { errno = 0;
- continue;
- }
- t &= ~SOCKET_PEEK;
- break;
- }
- if(r >= 0)
- { t &= ~STREAM_PEEK;
- if(r > 0)
- break;
- else /* read past eof */
- { if(action <= 0)
- r = sysreadf(fd,buf,1);
- return r;
- }
- }
- }
- #endif
- }
- if(r < 0)
- { if(tm >= 0 || action > 0)
- return -1;
- else /* get here means: tm < 0 && action <= 0 && rc >= 0 */
- { /* number of records read at a time */
- if((action = action ? -action : 1) > (int)n)
- action = n;
- r = 0;
- while((t = sysreadf(fd,buf,action)) > 0)
- { r += t;
- for(endbuf = buf+t; buf < endbuf;)
- if(*buf++ == rc)
- action -= 1;
- if(action == 0 || (int)(n-r) < action)
- break;
- }
- return r == 0 ? t : r;
- }
- }
- /* successful peek, find the record end */
- if(rc >= 0)
- { reg char* sp;
- t = action == 0 ? 1 : action < 0 ? -action : action;
- for(endbuf = (sp = buf)+r; sp < endbuf; )
- if(*sp++ == rc)
- if((t -= 1) == 0)
- break;
- r = sp - buf;
- }
- /* advance */
- if(action <= 0)
- r = sysreadf(fd,buf,r);
- return r;
- }