1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #include "sfhdr.h" 23 #if !_PACKAGE_ast 24 #ifndef FIONREAD 25 #if _sys_ioctl 26 #include <sys/ioctl.h> 27 #endif 28 #endif 29 #endif 30 31 /* Read/Peek a record from an unseekable device 32 ** 33 ** Written by Kiem-Phong Vo. 34 */ 35 36 #define STREAM_PEEK 001 37 #define SOCKET_PEEK 002 38 39 #if __STD_C 40 ssize_t sfpkrd(int fd, Void_t* argbuf, size_t n, int rc, long tm, int action) 41 #else 42 ssize_t sfpkrd(fd, argbuf, n, rc, tm, action) 43 int fd; /* file descriptor */ 44 Void_t* argbuf; /* buffer to read data */ 45 size_t n; /* buffer size */ 46 int rc; /* record character */ 47 long tm; /* time-out */ 48 int action; /* >0: peeking, if rc>=0, get action records, 49 <0: no peeking, if rc>=0, get -action records, 50 =0: no peeking, if rc>=0, must get a single record 51 */ 52 #endif 53 { 54 reg ssize_t r; 55 reg int ntry, t; 56 reg char *buf = (char*)argbuf, *endbuf; 57 58 if(rc < 0 && tm < 0 && action <= 0) 59 return sysreadf(fd,buf,n); 60 61 t = (action > 0 || rc >= 0) ? (STREAM_PEEK|SOCKET_PEEK) : 0; 62 #if !_stream_peek 63 t &= ~STREAM_PEEK; 64 #endif 65 #if !_socket_peek 66 t &= ~SOCKET_PEEK; 67 #endif 68 69 for(ntry = 0; ntry < 2; ++ntry) 70 { 71 r = -1; 72 #if _stream_peek 73 if((t&STREAM_PEEK) && (ntry == 1 || tm < 0) ) 74 { 75 struct strpeek pbuf; 76 pbuf.flags = 0; 77 pbuf.ctlbuf.maxlen = -1; 78 pbuf.ctlbuf.len = 0; 79 pbuf.ctlbuf.buf = NIL(char*); 80 pbuf.databuf.maxlen = n; 81 pbuf.databuf.buf = buf; 82 pbuf.databuf.len = 0; 83 84 if((r = ioctl(fd,I_PEEK,&pbuf)) < 0) 85 { if(errno == EINTR) 86 return -1; 87 t &= ~STREAM_PEEK; 88 } 89 else 90 { t &= ~SOCKET_PEEK; 91 if(r > 0 && (r = pbuf.databuf.len) <= 0) 92 { if(action <= 0) /* read past eof */ 93 r = sysreadf(fd,buf,1); 94 return r; 95 } 96 if(r == 0) 97 r = -1; 98 else if(r > 0) 99 break; 100 } 101 } 102 #endif /* stream_peek */ 103 104 if(ntry == 1) 105 break; 106 107 /* poll or select to see if data is present. */ 108 while(tm >= 0 || action > 0 || 109 /* block until there is data before peeking again */ 110 ((t&STREAM_PEEK) && rc >= 0) || 111 /* let select be interrupted instead of recv which autoresumes */ 112 (t&SOCKET_PEEK) ) 113 { r = -2; 114 #if _lib_poll 115 if(r == -2) 116 { 117 struct pollfd po; 118 po.fd = fd; 119 po.events = POLLIN; 120 po.revents = 0; 121 122 if((r = SFPOLL(&po,1,tm)) < 0) 123 { if(errno == EINTR) 124 return -1; 125 else if(errno == EAGAIN) 126 { errno = 0; 127 continue; 128 } 129 else r = -2; 130 } 131 else r = (po.revents&POLLIN) ? 1 : -1; 132 } 133 #endif /*_lib_poll*/ 134 #if _lib_select 135 if(r == -2) 136 { 137 #if _hpux_threads && vt_threaded 138 #define fd_set int 139 #endif 140 fd_set rd; 141 struct timeval tmb, *tmp; 142 FD_ZERO(&rd); 143 FD_SET(fd,&rd); 144 if(tm < 0) 145 tmp = NIL(struct timeval*); 146 else 147 { tmp = &tmb; 148 tmb.tv_sec = tm/SECOND; 149 tmb.tv_usec = (tm%SECOND)*SECOND; 150 } 151 r = select(fd+1,&rd,NIL(fd_set*),NIL(fd_set*),tmp); 152 if(r < 0) 153 { if(errno == EINTR) 154 return -1; 155 else if(errno == EAGAIN) 156 { errno = 0; 157 continue; 158 } 159 else r = -2; 160 } 161 else r = FD_ISSET(fd,&rd) ? 1 : -1; 162 } 163 #endif /*_lib_select*/ 164 if(r == -2) 165 { 166 #if !_lib_poll && !_lib_select /* both poll and select cann't be used */ 167 #ifdef FIONREAD /* quick and dirty check for availability */ 168 long nsec = tm < 0 ? 0 : (tm+999)/1000; 169 while(nsec > 0 && r < 0) 170 { long avail = -1; 171 if((r = ioctl(fd,FIONREAD,&avail)) < 0) 172 { if(errno == EINTR) 173 return -1; 174 else if(errno == EAGAIN) 175 { errno = 0; 176 continue; 177 } 178 else /* ioctl failed completely */ 179 { r = -2; 180 break; 181 } 182 } 183 else r = avail <= 0 ? -1 : (ssize_t)avail; 184 185 if(r < 0 && nsec-- > 0) 186 sleep(1); 187 } 188 #endif 189 #endif 190 } 191 192 if(r > 0) /* there is data now */ 193 { if(action <= 0 && rc < 0) 194 return sysreadf(fd,buf,n); 195 else r = -1; 196 } 197 else if(tm >= 0) /* timeout exceeded */ 198 return -1; 199 else r = -1; 200 break; 201 } 202 203 #if _socket_peek 204 if(t&SOCKET_PEEK) 205 { 206 #if __MACH__ && __APPLE__ 207 /* 208 * work around macos 10.4 recv(MSG_PEEK) bug that consumes pipe() data 209 */ 210 211 static int recv_peek_ok; 212 if (!recv_peek_ok) 213 { 214 int fds[2]; 215 char tst[2]; 216 tst[0] = 'a'; 217 tst[1] = 'z'; 218 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; 219 close(fds[0]); 220 close(fds[1]); 221 } 222 if (recv_peek_ok < 0) 223 { 224 r = -1; 225 t &= ~SOCKET_PEEK; 226 } 227 else 228 #endif 229 while((r = recv(fd,(char*)buf,n,MSG_PEEK)) < 0) 230 { if(errno == EINTR) 231 return -1; 232 else if(errno == EAGAIN) 233 { errno = 0; 234 continue; 235 } 236 t &= ~SOCKET_PEEK; 237 break; 238 } 239 if(r >= 0) 240 { t &= ~STREAM_PEEK; 241 if(r > 0) 242 break; 243 else /* read past eof */ 244 { if(action <= 0) 245 r = sysreadf(fd,buf,1); 246 return r; 247 } 248 } 249 } 250 #endif 251 } 252 253 if(r < 0) 254 { if(tm >= 0 || action > 0) 255 return -1; 256 else /* get here means: tm < 0 && action <= 0 && rc >= 0 */ 257 { /* number of records read at a time */ 258 if((action = action ? -action : 1) > (int)n) 259 action = n; 260 r = 0; 261 while((t = sysreadf(fd,buf,action)) > 0) 262 { r += t; 263 for(endbuf = buf+t; buf < endbuf;) 264 if(*buf++ == rc) 265 action -= 1; 266 if(action == 0 || (int)(n-r) < action) 267 break; 268 } 269 return r == 0 ? t : r; 270 } 271 } 272 273 /* successful peek, find the record end */ 274 if(rc >= 0) 275 { reg char* sp; 276 277 t = action == 0 ? 1 : action < 0 ? -action : action; 278 for(endbuf = (sp = buf)+r; sp < endbuf; ) 279 if(*sp++ == rc) 280 if((t -= 1) == 0) 281 break; 282 r = sp - buf; 283 } 284 285 /* advance */ 286 if(action <= 0) 287 r = sysreadf(fd,buf,r); 288 289 return r; 290 } 291