FreeBSD/contrib/netcat/netcat.c
/*
 * readwrite()
 * Loop that polls on the network file descriptor and stdin.
 */
readwrite()
Loop that polls on the network file descriptor and stdin.
readwrite () Loop that polls on the network file descriptor and stdin .
void
readwrite(int net_fd)
{
	struct pollfd pfd[4];
	int stdin_fd = STDIN_FILENO;
	int stdout_fd = STDOUT_FILENO;
	unsigned char netinbuf[BUFSIZE];
	size_t netinbufpos = 0;
	unsigned char stdinbuf[BUFSIZE];
	size_t stdinbufpos = 0;
	int n, num_fds;
	ssize_t ret;
	if (dflag)
		stdin_fd = -1;
	pfd[POLL_STDIN].fd = stdin_fd;
	pfd[POLL_STDIN].events = POLLIN;
	pfd[POLL_NETOUT].fd = net_fd;
	pfd[POLL_NETOUT].events = 0;
	pfd[POLL_NETIN].fd = net_fd;
	pfd[POLL_NETIN].events = POLLIN;
	pfd[POLL_STDOUT].fd = stdout_fd;
	pfd[POLL_STDOUT].events = 0;
	while (1) {
		if (pfd[POLL_STDIN].fd == -1 && pfd[POLL_NETIN].fd == -1
		    && stdinbufpos == 0 && netinbufpos == 0) {
			close(net_fd);
			return;
		}
		if (pfd[POLL_NETOUT].fd == -1 && pfd[POLL_STDOUT].fd == -1) {
			close(net_fd);
			return;
		}
		if (lflag && pfd[POLL_NETIN].fd == -1
		    && stdinbufpos == 0 && netinbufpos == 0) {
			close(net_fd);
			return;
		}
		if (iflag)
			sleep(iflag);
		num_fds = poll(pfd, 4, timeout);
		if (num_fds == -1) {
			close(net_fd);
			err(1, "polling error");
		}
		if (num_fds == 0)
			return;
		for (n = 0; n < 4; n++) {
			if (pfd[n].revents & (POLLERR|POLLNVAL)) {
				pfd[n].fd = -1;
			}
		}
		if (pfd[POLL_STDIN].events & POLLIN &&
		    pfd[POLL_STDIN].revents & POLLHUP &&
		    ! (pfd[POLL_STDIN].revents & POLLIN))
				pfd[POLL_STDIN].fd = -1;
		if (pfd[POLL_NETIN].events & POLLIN &&
		    pfd[POLL_NETIN].revents & POLLHUP &&
		    ! (pfd[POLL_NETIN].revents & POLLIN))
				pfd[POLL_NETIN].fd = -1;
		if (pfd[POLL_NETOUT].revents & POLLHUP) {
			if (Nflag)
				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
			pfd[POLL_NETOUT].fd = -1;
		}
		if (pfd[POLL_STDOUT].revents & POLLHUP)
			pfd[POLL_STDOUT].fd = -1;
		if (pfd[POLL_NETOUT].fd == -1)
			pfd[POLL_STDIN].fd = -1;
		if (pfd[POLL_STDOUT].fd == -1) {
			if (pfd[POLL_NETIN].fd != -1)
				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
			pfd[POLL_NETIN].fd = -1;
		}
		if (pfd[POLL_STDIN].revents & POLLIN && stdinbufpos < BUFSIZE) {
			ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
			    &stdinbufpos);
			if (ret == 0 || ret == -1)
				pfd[POLL_STDIN].fd = -1;
			if (stdinbufpos > 0)
				pfd[POLL_NETOUT].events = POLLOUT;
			if (stdinbufpos == BUFSIZE)
				pfd[POLL_STDIN].events = 0;
		}
		if (pfd[POLL_NETOUT].revents & POLLOUT && stdinbufpos > 0) {
			ret = drainbuf(pfd[POLL_NETOUT].fd, stdinbuf,
			    &stdinbufpos);
			if (ret == -1)
				pfd[POLL_NETOUT].fd = -1;
			if (stdinbufpos == 0)
				pfd[POLL_NETOUT].events = 0;
			if (stdinbufpos < BUFSIZE)
				pfd[POLL_STDIN].events = POLLIN;
		}
		if (pfd[POLL_NETIN].revents & POLLIN && netinbufpos < BUFSIZE) {
			ret = fillbuf(pfd[POLL_NETIN].fd, netinbuf,
			    &netinbufpos);
			if (ret == -1)
				pfd[POLL_NETIN].fd = -1;
			if (ret == 0) {
				shutdown(pfd[POLL_NETIN].fd, SHUT_RD);
				pfd[POLL_NETIN].fd = -1;
			}
			if (netinbufpos > 0)
				pfd[POLL_STDOUT].events = POLLOUT;
			if (netinbufpos == BUFSIZE)
				pfd[POLL_NETIN].events = 0;
			if (tflag)
				atelnet(pfd[POLL_NETIN].fd, netinbuf,
				    netinbufpos);
		}
		if (pfd[POLL_STDOUT].revents & POLLOUT && netinbufpos > 0) {
			ret = drainbuf(pfd[POLL_STDOUT].fd, netinbuf,
			    &netinbufpos);
			if (ret == -1)
				pfd[POLL_STDOUT].fd = -1;
			if (netinbufpos == 0)
				pfd[POLL_STDOUT].events = 0;
			if (netinbufpos < BUFSIZE)
				pfd[POLL_NETIN].events = POLLIN;
		}
		if (pfd[POLL_STDIN].fd == -1 && stdinbufpos == 0) {
			if (pfd[POLL_NETOUT].fd != -1 && Nflag)
				shutdown(pfd[POLL_NETOUT].fd, SHUT_WR);
			pfd[POLL_NETOUT].fd = -1;
		}
		if (pfd[POLL_NETIN].fd == -1 && netinbufpos == 0) {
			pfd[POLL_STDOUT].fd = -1;
		}
	}
}
void readwrite ( int net_fd ) { struct pollfd pfd [ 4 ] ; int stdin_fd = STDIN_FILENO ; int stdout_fd = STDOUT_FILENO ; unsigned char netinbuf [ BUFSIZE ] ; size_t netinbufpos = 0 ; unsigned char stdinbuf [ BUFSIZE ] ; size_t stdinbufpos = 0 ; int n , num_fds ; ssize_t ret ; if ( dflag ) stdin_fd = -1 ; pfd [ POLL_STDIN ] . fd = stdin_fd ; pfd [ POLL_STDIN ] . events = POLLIN ; pfd [ POLL_NETOUT ] . fd = net_fd ; pfd [ POLL_NETOUT ] . events = 0 ; pfd [ POLL_NETIN ] . fd = net_fd ; pfd [ POLL_NETIN ] . events = POLLIN ; pfd [ POLL_STDOUT ] . fd = stdout_fd ; pfd [ POLL_STDOUT ] . events = 0 ; while ( 1 ) { if ( pfd [ POLL_STDIN ] . fd == -1 && pfd [ POLL_NETIN ] . fd == -1 && stdinbufpos == 0 && netinbufpos == 0 ) { close ( net_fd ) ; return ; } if ( pfd [ POLL_NETOUT ] . fd == -1 && pfd [ POLL_STDOUT ] . fd == -1 ) { close ( net_fd ) ; return ; } if ( lflag && pfd [ POLL_NETIN ] . fd == -1 && stdinbufpos == 0 && netinbufpos == 0 ) { close ( net_fd ) ; return ; } if ( iflag ) sleep ( iflag ) ; num_fds = poll ( pfd , 4 , timeout ) ; if ( num_fds == -1 ) { close ( net_fd ) ; err ( 1 , " " ) ; } if ( num_fds == 0 ) return ; for ( n = 0 ; n < 4 ; n ++ ) { if ( pfd [ n ] . revents & ( POLLERR | POLLNVAL ) ) { pfd [ n ] . fd = -1 ; } } if ( pfd [ POLL_STDIN ] . events & POLLIN && pfd [ POLL_STDIN ] . revents & POLLHUP && ! ( pfd [ POLL_STDIN ] . revents & POLLIN ) ) pfd [ POLL_STDIN ] . fd = -1 ; if ( pfd [ POLL_NETIN ] . events & POLLIN && pfd [ POLL_NETIN ] . revents & POLLHUP && ! ( pfd [ POLL_NETIN ] . revents & POLLIN ) ) pfd [ POLL_NETIN ] . fd = -1 ; if ( pfd [ POLL_NETOUT ] . revents & POLLHUP ) { if ( Nflag ) shutdown ( pfd [ POLL_NETOUT ] . fd , SHUT_WR ) ; pfd [ POLL_NETOUT ] . fd = -1 ; } if ( pfd [ POLL_STDOUT ] . revents & POLLHUP ) pfd [ POLL_STDOUT ] . fd = -1 ; if ( pfd [ POLL_NETOUT ] . fd == -1 ) pfd [ POLL_STDIN ] . fd = -1 ; if ( pfd [ POLL_STDOUT ] . fd == -1 ) { if ( pfd [ POLL_NETIN ] . fd != -1 ) shutdown ( pfd [ POLL_NETIN ] . fd , SHUT_RD ) ; pfd [ POLL_NETIN ] . fd = -1 ; } if ( pfd [ POLL_STDIN ] . revents & POLLIN && stdinbufpos < BUFSIZE ) { ret = fillbuf ( pfd [ POLL_STDIN ] . fd , stdinbuf , & stdinbufpos ) ; if ( ret == 0 || ret == -1 ) pfd [ POLL_STDIN ] . fd = -1 ; if ( stdinbufpos > 0 ) pfd [ POLL_NETOUT ] . events = POLLOUT ; if ( stdinbufpos == BUFSIZE ) pfd [ POLL_STDIN ] . events = 0 ; } if ( pfd [ POLL_NETOUT ] . revents & POLLOUT && stdinbufpos > 0 ) { ret = drainbuf ( pfd [ POLL_NETOUT ] . fd , stdinbuf , & stdinbufpos ) ; if ( ret == -1 ) pfd [ POLL_NETOUT ] . fd = -1 ; if ( stdinbufpos == 0 ) pfd [ POLL_NETOUT ] . events = 0 ; if ( stdinbufpos < BUFSIZE ) pfd [ POLL_STDIN ] . events = POLLIN ; } if ( pfd [ POLL_NETIN ] . revents & POLLIN && netinbufpos < BUFSIZE ) { ret = fillbuf ( pfd [ POLL_NETIN ] . fd , netinbuf , & netinbufpos ) ; if ( ret == -1 ) pfd [ POLL_NETIN ] . fd = -1 ; if ( ret == 0 ) { shutdown ( pfd [ POLL_NETIN ] . fd , SHUT_RD ) ; pfd [ POLL_NETIN ] . fd = -1 ; } if ( netinbufpos > 0 ) pfd [ POLL_STDOUT ] . events = POLLOUT ; if ( netinbufpos == BUFSIZE ) pfd [ POLL_NETIN ] . events = 0 ; if ( tflag ) atelnet ( pfd [ POLL_NETIN ] . fd , netinbuf , netinbufpos ) ; } if ( pfd [ POLL_STDOUT ] . revents & POLLOUT && netinbufpos > 0 ) { ret = drainbuf ( pfd [ POLL_STDOUT ] . fd , netinbuf , & netinbufpos ) ; if ( ret == -1 ) pfd [ POLL_STDOUT ] . fd = -1 ; if ( netinbufpos == 0 ) pfd [ POLL_STDOUT ] . events = 0 ; if ( netinbufpos < BUFSIZE ) pfd [ POLL_NETIN ] . events = POLLIN ; } if ( pfd [ POLL_STDIN ] . fd == -1 && stdinbufpos == 0 ) { if ( pfd [ POLL_NETOUT ] . fd != -1 && Nflag ) shutdown ( pfd [ POLL_NETOUT ] . fd , SHUT_WR ) ; pfd [ POLL_NETOUT ] . fd = -1 ; } if ( pfd [ POLL_NETIN ] . fd == -1 && netinbufpos == 0 ) { pfd [ POLL_STDOUT ] . fd = -1 ; } } }
readwrite()
 Loop that polls on the network file descriptor and stdin.
readwrite () Loop that polls on the network file descriptor and stdin .
/* don't read from stdin if requested */ /* stdin */ /* network out */ /* network in */ /* stdout */ /* both inputs are gone, buffers are empty, we are done */ /* both outputs are gone, we can't continue */ /* listen and net in gone, queues empty, done */ /* help says -i is for "wait between lines sent". We read and
		 * write arbitrary amounts of data, and we don't want to start
		 * scanning for newlines, so this is as good as it gets */ /* poll */ /* treat poll errors */ /* timeout happened */ /* treat socket error conditions */ /* reading is possible after HUP */ /* if HUP, stop watching stdout */ /* if no net out, stop watching stdin */ /* if no stdout, stop watching net in */ /* try to read from stdin */ /* error or eof on stdin - remove from pfd */ /* read something - poll net out */ /* filled buffer - remove self from polling */ /* try to write to network */ /* buffer empty - remove self from polling */ /* buffer no longer full - poll stdin again */ /* try to read from network */ /* eof on net in - remove from pfd */ /* read something - poll stdout */ /* filled buffer - remove self from polling */ /* handle telnet */ /* try to write to stdout */ /* buffer empty - remove self from polling */ /* buffer no longer full - poll net in again */ /* stdin gone and queue empty? */ /* net in gone and queue empty? */