--- /dev/null
+#include "syshdrs.h"
+
+#ifndef NO_SIGNALS
+extern volatile Sjmp_buf gNetTimeoutJmp;
+extern volatile Sjmp_buf gPipeJmp;
+#endif
+
+#ifndef NO_SIGNALS
+
+int
+SRecv(int sfd, char *const buf0, size_t size, int fl, int tlen, int retry)
+{
+ int nread;
+ volatile int nleft;
+ char *volatile buf = buf0;
+ int tleft;
+ vsio_sigproc_t sigalrm, sigpipe;
+ time_t done, now;
+
+ if (SSetjmp(gNetTimeoutJmp) != 0) {
+ alarm(0);
+ (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
+ (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe);
+ nread = size - nleft;
+ if ((nread > 0) && (retry == kFullBufferNotRequired))
+ return (nread);
+ errno = ETIMEDOUT;
+ return (kTimeoutErr);
+ }
+
+ if (SSetjmp(gPipeJmp) != 0) {
+ alarm(0);
+ (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
+ (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe);
+ nread = size - nleft;
+ if ((nread > 0) && (retry == kFullBufferNotRequired))
+ return (nread);
+ errno = EPIPE;
+ return (kBrokenPipeErr);
+ }
+
+ sigalrm = (vsio_sigproc_t) SSignal(SIGALRM, SIOHandler);
+ sigpipe = (vsio_sigproc_t) SSignal(SIGPIPE, SIOHandler);
+ errno = 0;
+
+ nleft = (int) size;
+ time(&now);
+ done = now + tlen;
+ forever {
+ tleft = (int) (done - now);
+ if (tleft < 1) {
+ nread = size - nleft;
+ if ((nread == 0) || (retry == kFullBufferRequired)) {
+ nread = kTimeoutErr;
+ errno = ETIMEDOUT;
+ }
+ goto done;
+ }
+ (void) alarm((unsigned int) tleft);
+ nread = recv(sfd, (char *) buf, nleft, fl);
+ (void) alarm(0);
+ if (nread <= 0) {
+ if (nread == 0) {
+ /* EOF */
+ if (retry == kFullBufferRequiredExceptLast)
+ nread = size - nleft;
+ goto done;
+ } else if (errno != EINTR) {
+ nread = size - nleft;
+ if (nread == 0)
+ nread = -1;
+ goto done;
+ } else {
+ errno = 0;
+ nread = 0;
+ /* Try again. */
+ }
+ }
+ nleft -= nread;
+ if ((nleft <= 0) || ((retry == 0) && (nleft != (int) size)))
+ break;
+ buf += nread;
+ time(&now);
+ }
+ nread = size - nleft;
+
+done:
+ (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
+ (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe);
+
+ return (nread);
+} /* SRecv */
+
+#else
+
+int
+SRecv(int sfd, char *const buf0, size_t size, int fl, int tlen, int retry)
+{
+ int nread;
+ int nleft;
+ char *buf = buf0;
+ int tleft;
+ time_t done, now;
+ fd_set ss;
+ struct timeval tv;
+ int result;
+
+ errno = 0;
+
+ nleft = (int) size;
+ time(&now);
+ done = now + tlen;
+ forever {
+ tleft = (int) (done - now);
+ if (tleft < 1) {
+ nread = size - nleft;
+ if ((nread == 0) || (retry == kFullBufferRequired)) {
+ nread = kTimeoutErr;
+ errno = ETIMEDOUT;
+ SETWSATIMEOUTERR
+ }
+ goto done;
+ }
+
+ forever {
+ errno = 0;
+ FD_ZERO(&ss);
+ FD_SET(sfd, &ss);
+ tv.tv_sec = tlen;
+ tv.tv_usec = 0;
+ result = select(sfd + 1, SELECT_TYPE_ARG234 &ss, NULL, NULL, SELECT_TYPE_ARG5 &tv);
+ if (result == 1) {
+ /* ready */
+ break;
+ } else if (result == 0) {
+ /* timeout */
+ nread = size - nleft;
+ if ((nread > 0) && (retry == kFullBufferNotRequired))
+ return (nread);
+ errno = ETIMEDOUT;
+ SETWSATIMEOUTERR
+ return (kTimeoutErr);
+ } else if (errno != EINTR) {
+ return (-1);
+ }
+ }
+
+#if defined(WIN32) || defined(_WINDOWS)
+ nread = recv(sfd, (char *) buf, nleft, fl);
+#else
+ nread = recv(sfd, (char *) buf, nleft, fl);
+#endif
+
+ if (nread <= 0) {
+ if (nread == 0) {
+ /* EOF */
+ if (retry == kFullBufferRequiredExceptLast)
+ nread = size - nleft;
+ goto done;
+ } else if (errno != EINTR) {
+ nread = size - nleft;
+ if (nread == 0)
+ nread = -1;
+ goto done;
+ } else {
+ errno = 0;
+ nread = 0;
+ /* Try again. */
+ }
+ }
+ nleft -= nread;
+ if ((nleft <= 0) || ((retry == 0) && (nleft != (int) size)))
+ break;
+ buf += nread;
+ time(&now);
+ }
+ nread = size - nleft;
+
+done:
+ return (nread);
+} /* SRecv */
+
+#endif
+