/* netio/fget_netio_timeout.c.  Generated from netio_timeout.c.in by configure. */

/*
**  Copyright 2000-2004 University of Illinois Board of Trustees
**  Copyright 2000-2004 Mark D. Roth
**  All rights reserved.
**
**  fget_netio_timeout.c - NETIO timeout code
**
**  Mark D. Roth <roth@feep.net>
*/

#include <fget_netio_internal.h>

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>

#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#else
# ifdef HAVE_SYS_SELECT_H
#  include <sys/select.h>
# endif
#endif


/*
** wait for an I/O operation to complete.
** arguments:
**	file descriptor
**	write flag (boolean - true for write, false for read)
**	timeout value:
**		-1		infinite wait
**		0		immediate return (0 second wait)
**		(positive)	number of seconds to wait
** Returns:
**	0	success
**	-1	error
**	1	timed out
*/
int
fget_netio_wait(NETIO *nio, int write_mode, time_t timeout)
{
	int i;
#ifdef HAVE_POLL
	struct pollfd pfd[1];
	int ito;
#else /* ! HAVE_POLL */
	fd_set rfds, wfds, efds;
	struct timeval tv;
#endif /* HAVE_POLL */

#ifdef DEBUG
	printf("==> fget_netio_wait(nio=0x%lx { nio->n_fd=%d }, "
	       "write_mode=%d, timeout=%lu)\n",
	       nio, nio->n_fd, write_mode, (unsigned long)timeout);
#endif

#ifdef HAVE_POLL

	/*
	** if the system supports poll(2), use it
	*/

	pfd[0].fd = nio->n_fd;
	pfd[0].events = (write_mode ? POLLOUT : POLLIN);
	pfd[0].revents = 0;

	if (timeout == (time_t)-1)
		ito = -1;
	else
		ito = timeout * 1000;

	i = poll(pfd, 1, ito);
# ifdef DEBUG
	printf("    fget_netio_wait(): poll() returned %d\n", i);
	printf("    fget_netio_wait(): pfd[0].revents = %d\n",
	       pfd[0].revents);
# endif
	if (i == -1)
		return -1;
	if (BIT_ISSET(pfd[0].revents, POLLERR))
	{
		errno = EIO;
		return -1;
	}
	if (BIT_ISSET(pfd[0].revents, POLLHUP))
	{
		errno = ECONNRESET;
		return -1;
	}
	if (i == 0)
		return 1;

#else /* ! HAVE_POLL */

	/*
	** if poll(2) is not available, use select(2) instead
	*/

	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);
	if (write_mode)
		FD_SET(nio->n_fd, &wfds);
	else
		FD_SET(nio->n_fd, &rfds);
	FD_SET(nio->n_fd, &efds);

	tv.tv_sec = timeout;
	tv.tv_usec = 0;

	i = select(FD_SETSIZE, &rfds, &wfds, &efds,
		   (timeout == (time_t)-1 ? NULL : &tv));
# ifdef DEBUG
	printf("   fget_netio_wait(): select() returned %d\n", i);
# endif
	if (i == -1)
		return -1;
	if (FD_ISSET(nio->n_fd, &efds))
	{
		errno = EIO;
		return -1;
	}
	if (i == 0)
		return 1;

#endif /* HAVE_POLL */

#ifdef DEBUG
	puts("<== fget_netio_wait(): success");
#endif
	return 0;
}


int
fget_netio_eof(NETIO *nio)
{
	int i;
	char buf[NETIOBUFSIZE];

	/* if the EOF flag is set, return true immediately */
	if (nio->n_eof)
		return 1;

	/* otherwise, we need to try poll() */
	i = fget_netio_wait(nio, 0, 0);
#ifdef DEBUG
	printf("    fget_netio_eof(): "
	       "fget_netio_wait() returned %d\n", i);
#endif
	if (i == -1)
		/* error means EOF */
		return 1;
	if (i == 1)
		/* timed out means idle, not EOF */
		return 0;

	/*
	** otherwise, _netio_wait() returned 0, which means there's data
	** to be read.  however, this is true even when read() would
	** return 0, indicating an EOF.  so, to distinguish between
	** these two cases, we use recv() with MSG_PEEK to see how
	** much data is available to be read.
	*/
#ifdef DEBUG
	printf("     fget_netio_eof(): calling recv()\n");
#endif
	i = recv(nio->n_fd, buf, sizeof(buf), MSG_PEEK);
	if (i == 0)
		/* no data to be read - must be EOF */
		return 1;

	/*
	** either there's data to be read, or it's an error.
	** either way, not EOF
	*/
	return 0;
}




syntax highlighted by Code2HTML, v. 0.9.1