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