1#include "syshdrs.h"
2#ifdef PRAGMA_HDRSTOP
3#	pragma hdrstop
4#endif
5
6static const char UNUSED(gSioVersion[]) = kSioVersion;
7static const char UNUSED(gCopyright[]) = "@(#) libsio Copyright 1992-2011, by Mike Gleason.  All rights reserved.";
8
9
10/* Read up to "size" bytes on sfd before "tlen" seconds.
11 *
12 * If "retry" is on, after a successful read of less than "size"
13 * bytes, it will attempt to read more, upto "size."
14 *
15 * If the timer elapses and one or more bytes were read, it returns
16 * that number, otherwise a timeout error is returned.
17 *
18 * Although "retry" would seem to indicate you may want to always
19 * read "size" bytes or else it is an error, even with that on you
20 * may get back a value < size.  Set "retry" to 0 when you want to
21 * return as soon as there is a chunk of data whose size is <= "size".
22 */
23
24int
25SRead(int sfd, char *const buf0, size_t size, int tlen, int retry)
26{
27	read_return_t nread;
28	read_size_t nleft;
29	char *buf = buf0;
30	int tleft;
31	time_t done, now;
32	fd_set ss;
33	struct timeval tv;
34	int result, firstRead;
35	DECL_SIGPIPE_VARS
36
37	if ((buf == NULL) || (size == 0) || (tlen <= 0)) {
38		errno = EINVAL;
39		return (-1);
40	}
41
42	IGNORE_SIGPIPE
43	errno = 0;
44
45	nleft = (read_size_t) size;
46	time(&now);
47	done = now + tlen;
48	firstRead = 1;
49
50	forever {
51		tleft = (done > now) ? ((int) (done - now)) : 0;
52		if (tleft < 1) {
53			nread = (read_return_t) size - (read_return_t) nleft;
54			if ((nread == 0) || ((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) != 0)) {
55				nread = kTimeoutErr;
56				errno = ETIMEDOUT;
57				SETWSATIMEOUTERR
58			}
59			goto done;
60		}
61
62		if (!firstRead || ((retry & kNoFirstSelect) == 0)) {
63			forever {
64				errno = 0;
65				MY_FD_ZERO(&ss);
66#if defined(__DECC) || defined(__DECCXX)
67#pragma message save
68#pragma message disable trunclongint
69#endif
70				MY_FD_SET(sfd, &ss);
71#if defined(__DECC) || defined(__DECCXX)
72#pragma message restore
73#endif
74				tv.tv_sec = (tv_sec_t) tleft;
75				tv.tv_usec = 0;
76				result = select(sfd + 1, SELECT_TYPE_ARG234 &ss, NULL, NULL, SELECT_TYPE_ARG5 &tv);
77				if (result >= 1) {
78					/* ready */
79					break;
80				} else if (result == 0) {
81					/* timeout */
82					nread = (read_return_t) size - (read_return_t) nleft;
83					if ((nread > 0) && ((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast))  == 0)) {
84						RESTORE_SIGPIPE
85						return ((int) nread);
86					}
87					errno = ETIMEDOUT;
88					SETWSATIMEOUTERR
89					RESTORE_SIGPIPE
90					return (kTimeoutErr);
91				} else if (errno != EINTR) {
92					RESTORE_SIGPIPE
93					return (-1);
94				}
95			}
96			firstRead = 0;
97		}
98
99#if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
100		nread = recv(sfd, (char *) buf, (recv_size_t) nleft, 0);
101#else
102		nread = read(sfd, (char *) buf, nleft);
103#endif
104
105		if (nread <= 0) {
106			if (nread == 0) {
107				/* EOF */
108				if (retry == ((retry & (kFullBufferRequiredExceptLast)) != 0))
109					nread = (read_return_t) size - (read_return_t) nleft;
110				goto done;
111			} else if (errno != EINTR) {
112				nread = (read_return_t) size - (read_return_t) nleft;
113				if (nread == 0)
114					nread = (read_return_t) -1;
115				goto done;
116			} else {
117				errno = 0;
118				nread = 0;
119				/* Try again. */
120
121				/* Ignore these two lines */
122				LIBSIO_USE_VAR(gSioVersion);
123				LIBSIO_USE_VAR(gCopyright);
124			}
125		}
126		nleft -= (read_size_t) nread;
127		if ((nleft == 0) || (((retry & (kFullBufferRequired|kFullBufferRequiredExceptLast)) == 0) && (nleft != (read_size_t) size)))
128			break;
129		buf += nread;
130		time(&now);
131	}
132	nread = (read_return_t) size - (read_return_t) nleft;
133
134done:
135	RESTORE_SIGPIPE
136	return ((int) nread);
137}	/* SRead */
138