Logo Search packages:      
Sourcecode: nc6 version File versions  Download package

readwrite.c

/*
 *  readwrite.c - stream i/o reading/writing loop - implementation 
 * 
 *  nc6 - an advanced netcat clone
 *  Copyright (C) 2001-2006 Mauro Tortonesi <mauro _at_ deepspace6.net>
 *  Copyright (C) 2002-2006 Chris Leishman <chris _at_ leishman.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */  
#include "system.h"
#include "readwrite.h"
#include "misc.h"
#include "circ_buf.h"
#include "parser.h"

#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>

RCSID("@(#) $Header: /ds6/cvs/nc6/src/readwrite.c,v 1.44 2006/01/19 22:46:23 chris Exp $");



/* ios1 is the remote stream, ios2 the local one */
int readwrite(io_stream_t *ios1, io_stream_t *ios2)
{
      int rr, max_fd = -1;
      int ios1_read_fd, ios1_write_fd;
      int ios2_read_fd, ios2_write_fd;
      fd_set read_fdset, write_fdset;
      struct timeval tv1, tv2;
      struct timeval *tvp1, *tvp2, *tvp;
      bool timedout1 = false, timedout2 = false;
      int retval = 0;
      
      /* check function arguments */
      assert(ios1 != NULL);
      assert(ios2 != NULL);

      /* setup all the stuff for the select loop */

      /* here's the select loop. 
       *
       * the loop continues until one of the following occurs:
       *
       * neither side needs to read or write
       * OR
       * either side times out
       * OR
       * a write error occurs
       *
       * note: by default, when the remote read side (ios1) is closed, it
       * triggers a hold timeout immediately - which closes the local read
       * side as well.
       */
      for (;;) {
            /* setup fdsets */
            FD_ZERO(&read_fdset);
            FD_ZERO(&write_fdset);

            ios1_read_fd  = ios_schedule_read(ios1);
            ios1_write_fd = ios_schedule_write(ios1);
            ios2_read_fd  = ios_schedule_read(ios2);
            ios2_write_fd = ios_schedule_write(ios2);

            max_fd = -1;
            if (ios1_read_fd >= 0) {
                  FD_SET(ios1_read_fd, &read_fdset);
                  max_fd = ios1_read_fd;
            }
            if (ios1_write_fd >= 0) {
                  FD_SET(ios1_write_fd, &write_fdset);
                  max_fd = MAX(ios1_write_fd, max_fd);
            }
            if (ios2_read_fd >= 0) {
                  FD_SET(ios2_read_fd, &read_fdset);
                  max_fd = MAX(ios2_read_fd, max_fd);
            }
            if (ios2_write_fd >= 0) {
                  FD_SET(ios2_write_fd, &write_fdset);
                  max_fd = MAX(ios2_write_fd, max_fd);
            }

            /* stop loop if nothing is to be read or written */
            if (max_fd == -1)
                  break;

            /* check timeouts */
            tvp1 = tvp2 = NULL;
            if (!timedout1) {
                  tvp1 = ios_next_timeout(ios1, &tv1);

                  /* handle timeouts */
                  if (ios_idle_timedout(ios1)) {
                        /* stop the readwrite loop */
                        retval = -1;
                        break;
                  }
                  if (ios_hold_timedout(ios1)) {
                        /* stop reading from the other endpoint */
                        ios_shutdown(ios2, SHUT_RD);
                        /* stop sending to this endpoint */
                        ios_shutdown(ios1, SHUT_WR);
                        timedout1 = true;
                        continue;
                  }
            }
            if (!timedout2) {
                  tvp2 = ios_next_timeout(ios2, &tv2);

                  /* handle timeouts */
                  if (ios_idle_timedout(ios2)) {
                        /* stop the readwrite loop */
                        retval = -1;
                        break;
                  }
                  if (ios_hold_timedout(ios2)) {
                        /* stop reading from the other endpoint */
                        ios_shutdown(ios1, SHUT_RD);
                        /* stop sending to this endpoint */
                        ios_shutdown(ios2, SHUT_WR);
                        timedout2 = true;
                        continue;
                  }
            }

            /* select smallest timeout for select */
            if (tvp1 != NULL) {
                  if (tvp2 != NULL)
                        tvp = timercmp(tvp1, tvp2, <) ? tvp1 : tvp2;
                  else
                        tvp = tvp1;
            } else {
                  tvp = tvp2;  /* tvp2 may be NULL */
            }

            /* blocking select with timeout */        
            rr = select(max_fd + 1, &read_fdset, &write_fdset, NULL, tvp);

            /* handle select errors.
             * if errno == EINTR we just retry select */
            if (rr < 0) {
                  if (errno == EINTR) 
                        continue;
                  fatal("select error: %s", strerror(errno));
            }
            
            if (ios1_read_fd >= 0 && FD_ISSET(ios1_read_fd, &read_fdset)) {
                  /* ios1 is ready to read */
                  rr = ios_read(ios1);

                  if (rr < 0) {
                        if (rr == IOS_EOF) {
                              ios_write_eof(ios2);
                        } else {
                              /* something bad happened -
                               * exit the main loop */
                              retval = -1;
                              break;
                        }
                  }
            }

            if (ios2_read_fd >= 0 && FD_ISSET(ios2_read_fd, &read_fdset)) {
                  /* ios2 is ready to read */
                  rr = ios_read(ios2);

                  if (rr < 0) {
                        if (rr == IOS_EOF) {
                              ios_write_eof(ios1);
                        } else {
                              /* something bad happened -
                               * exit the main loop */
                              retval = -1;
                              break;
                        }
                  }
            }

            if (ios1_write_fd >= 0 && FD_ISSET(ios1_write_fd, &write_fdset))
            {
                  /* ios1 is ready to write */
                  rr = ios_write(ios1);

                  if (rr < 0) {
                        /* write failed -
                         * exit the main loop */
                        retval = -1;
                        break;
                  }
            }

            if (ios2_write_fd >= 0 && FD_ISSET(ios2_write_fd, &write_fdset))
            {
                  /* ios2 is ready to write */
                  rr = ios_write(ios2);

                  if (rr < 0) {
                        /* write failed -
                         * exit the main loop */
                        retval = -1;
                        break;
                  }
            }
      }
      
      return retval;
}

Generated by  Doxygen 1.6.0   Back to index