/*
 * Copyright (c) 1993 W. Richard Stevens.  All rights reserved.
 * Permission to use or modify this software and its documentation only for
 * educational purposes and without fee is hereby granted, provided that
 * the above copyright notice appear in all copies.  The author makes no
 * representations about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 */

#include	"sock.h"

/* Copy everything from stdin to "sockfd",
 * and everything from "sockfd" to stdout. */

void
loop_tcp(int sockfd)
{
	int		maxfdp1, nread, ntowrite, stdineof, flags;
	fd_set	rset;

	if (pauseinit)
		sleep_us(pauseinit*1000);	/* intended for server */

	flags = 0;
	stdineof = 0;
	FD_ZERO(&rset);
	maxfdp1 = sockfd + 1;	/* check descriptors [0..sockfd] */

	for ( ; ; ) {
		if (stdineof == 0)
			FD_SET(STDIN_FILENO, &rset);
		FD_SET(sockfd, &rset);

		if (select(maxfdp1, &rset, NULL, NULL, NULL) < 0)
			err_sys("select error");

		if (FD_ISSET(STDIN_FILENO, &rset)) {	/* data to read on stdin */
			if ( (nread = read(STDIN_FILENO, rbuf, readlen)) < 0)
				err_sys("read error from stdin");
			else if (nread == 0) {	/* EOF on stdin */
				if (halfclose) {
					if (shutdown(sockfd, SHUT_WR) < 0)
						err_sys("shutdown() error");

					FD_CLR(STDIN_FILENO, &rset);
					stdineof = 1;	/* don't read stdin anymore */
					continue;		/* back to select() */
				}
				break;		/* default: stdin EOF -> done */
			}

			if (crlf) {
				ntowrite = crlf_add(wbuf, writelen, rbuf, nread);
				if (dowrite(sockfd, wbuf, ntowrite) != ntowrite)
					err_sys("write error");
			} else {
				if (dowrite(sockfd, rbuf, nread) != nread)
					err_sys("write error");
			}
		}

		if (FD_ISSET(sockfd, &rset)) {	/* data to read from socket */
				/* msgpeek = 0 or MSG_PEEK */
			flags = msgpeek;
		oncemore:
			if ( (nread = recv(sockfd, rbuf, readlen, flags)) < 0)
				err_sys("recv error");
			else if (nread == 0) {
				if (verbose)
					fprintf(stderr, "connection closed by peer\n");
				break;		/* EOF, terminate */
			}

			if (crlf) {
				ntowrite = crlf_strip(wbuf, writelen, rbuf, nread);
				if (writen(STDOUT_FILENO, wbuf, ntowrite) != ntowrite)
					err_sys("writen error to stdout");
			} else {
				if (writen(STDOUT_FILENO, rbuf, nread) != nread)
					err_sys("writen error to stdout");
			}

			if (flags != 0) {
				flags = 0;		/* no infinite loop */
				goto oncemore;	/* read the message again */
			}
		}
	}

	if (pauseclose) {
		if (verbose)
				fprintf(stderr, "pausing before close\n");
		sleep_us(pauseclose*1000);
	}

	if (close(sockfd) < 0)
		err_sys("close error");		/* since SO_LINGER may be set */
}
