1 #include "syshdrs.h" 2 3 static char UNUSED(gSioVersion[]) = "@(#) sio 6.0.3 ** Copyright 1992-2001 Mike Gleason. All rights reserved."; 4 5 #ifdef NO_SIGNALS 6 static char UNUSED(gNoSignalsMarker[]) = "@(#) sio - NO_SIGNALS"; 7 #else 8 extern volatile Sjmp_buf gNetTimeoutJmp; 9 extern volatile Sjmp_buf gPipeJmp; 10 #endif 11 12 /* Read up to "size" bytes on sfd before "tlen" seconds. 13 * 14 * If "retry" is on, after a successful read of less than "size" 15 * bytes, it will attempt to read more, upto "size." 16 * 17 * If the timer elapses and one or more bytes were read, it returns 18 * that number, otherwise a timeout error is returned. 19 * 20 * Although "retry" would seem to indicate you may want to always 21 * read "size" bytes or else it is an error, even with that on you 22 * may get back a value < size. Set "retry" to 0 when you want to 23 * return as soon as there is a chunk of data whose size is <= "size". 24 */ 25 26 #ifndef NO_SIGNALS 27 28 int 29 SRead(int sfd, char *const buf0, size_t size, int tlen, int retry) 30 { 31 int nread; 32 volatile int nleft; 33 char *volatile buf = buf0; 34 int tleft; 35 vsio_sigproc_t sigalrm, sigpipe; 36 time_t done, now; 37 38 if (SSetjmp(gNetTimeoutJmp) != 0) { 39 alarm(0); 40 (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm); 41 (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe); 42 nread = size - nleft; 43 if ((nread > 0) && ((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) == 0)) 44 return (nread); 45 errno = ETIMEDOUT; 46 return (kTimeoutErr); 47 } 48 49 if (SSetjmp(gPipeJmp) != 0) { 50 alarm(0); 51 (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm); 52 (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe); 53 nread = size - nleft; 54 if ((nread > 0) && ((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) == 0)) 55 return (nread); 56 errno = EPIPE; 57 return (kBrokenPipeErr); 58 } 59 60 sigalrm = (vsio_sigproc_t) SSignal(SIGALRM, SIOHandler); 61 sigpipe = (vsio_sigproc_t) SSignal(SIGPIPE, SIOHandler); 62 errno = 0; 63 64 nleft = (int) size; 65 time(&now); 66 done = now + tlen; 67 forever { 68 tleft = (int) (done - now); 69 if (tleft < 1) { 70 nread = size - nleft; 71 if ((nread == 0) || ((retry & (kFullBufferRequired)) != 0)) { 72 nread = kTimeoutErr; 73 errno = ETIMEDOUT; 74 } 75 goto done; 76 } 77 (void) alarm((unsigned int) tleft); 78 nread = read(sfd, (char *) buf, nleft); 79 (void) alarm(0); 80 if (nread <= 0) { 81 if (nread == 0) { 82 /* EOF */ 83 if (retry == ((retry & (kFullBufferRequiredExceptLast)) != 0)) 84 nread = size - nleft; 85 goto done; 86 } else if (errno != EINTR) { 87 nread = size - nleft; 88 if (nread == 0) 89 nread = -1; 90 goto done; 91 } else { 92 errno = 0; 93 nread = 0; 94 /* Try again. */ 95 96 /* Ignore this line... */ 97 LIBSIO_USE_VAR(gSioVersion); 98 } 99 } 100 nleft -= nread; 101 if ((nleft <= 0) || (((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) == 0) && (nleft != (int) size))) 102 break; 103 buf += nread; 104 time(&now); 105 } 106 nread = size - nleft; 107 108 done: 109 (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm); 110 (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe); 111 112 return (nread); 113 } /* SRead */ 114 115 #else 116 117 int 118 SRead(int sfd, char *const buf0, size_t size, int tlen, int retry) 119 { 120 int nread; 121 volatile int nleft; 122 char *buf = buf0; 123 int tleft; 124 time_t done, now; 125 fd_set ss; 126 struct timeval tv; 127 int result, firstRead; 128 129 errno = 0; 130 131 nleft = (int) size; 132 time(&now); 133 done = now + tlen; 134 firstRead = 1; 135 136 forever { 137 tleft = (int) (done - now); 138 if (tleft < 1) { 139 nread = size - nleft; 140 if ((nread == 0) || ((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) != 0)) { 141 nread = kTimeoutErr; 142 errno = ETIMEDOUT; 143 SETWSATIMEOUTERR 144 } 145 goto done; 146 } 147 148 if (!firstRead || ((retry & kNoFirstSelect) == 0)) { 149 forever { 150 errno = 0; 151 FD_ZERO(&ss); 152 FD_SET(sfd, &ss); 153 tv.tv_sec = tlen; 154 tv.tv_usec = 0; 155 result = select(sfd + 1, SELECT_TYPE_ARG234 &ss, NULL, NULL, SELECT_TYPE_ARG5 &tv); 156 if (result == 1) { 157 /* ready */ 158 break; 159 } else if (result == 0) { 160 /* timeout */ 161 nread = size - nleft; 162 if ((nread > 0) && ((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) == 0)) 163 return (nread); 164 errno = ETIMEDOUT; 165 SETWSATIMEOUTERR 166 return (kTimeoutErr); 167 } else if (errno != EINTR) { 168 return (-1); 169 } 170 } 171 firstRead = 0; 172 } 173 174 #if defined(WIN32) || defined(_WINDOWS) 175 nread = recv(sfd, (char *) buf, nleft, 0); 176 #else 177 nread = read(sfd, (char *) buf, nleft); 178 #endif 179 180 if (nread <= 0) { 181 if (nread == 0) { 182 /* EOF */ 183 if (retry == ((retry & (kFullBufferRequiredExceptLast)) != 0)) 184 nread = size - nleft; 185 goto done; 186 } else if (errno != EINTR) { 187 nread = size - nleft; 188 if (nread == 0) 189 nread = -1; 190 goto done; 191 } else { 192 errno = 0; 193 nread = 0; 194 /* Try again. */ 195 196 /* Ignore these two lines */ 197 LIBSIO_USE_VAR(gSioVersion); 198 LIBSIO_USE_VAR(gNoSignalsMarker); 199 } 200 } 201 nleft -= nread; 202 if ((nleft <= 0) || (((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) == 0) && (nleft != (int) size))) 203 break; 204 buf += nread; 205 time(&now); 206 } 207 nread = size - nleft; 208 209 done: 210 return (nread); 211 } /* SRead */ 212 213 #endif 214