netselect.h #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2017-1/
  • net/
  • netselect.h
  • View
  • Commits
  • Open Download .zip Download (4 KB)
/*
 * Copyright 2009 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 */

/*
 * NetTcpSelector -- isolation of select() call for TCP
 *
 * Public methods:
 *
 *	NetTcpSelector( int t ) - create a selector for file descriptor t
 *
 *	NetTcpSelector::Select( int &read, int &write, int usec, Error *e )
 *
 *	    Blocks waiting for read (if read set) and/or write 
 *	    (if write set).  Sets read if data ready to read, write
 *	    if data ready to write.
 *
 *	    Waits at most usec microseconds, or forever if usec < 0.
 *
 *	    Returns 0 if timeout.
 *	    Returns -1 on error (with Error set).
 *	    Returns >0 on data ready.
 *
 *	NetTcpSelector::Peek()
 *
 *	    Returns 1 if data is available to read, 0 if not (EOF).
 *	    Call Select() first.
 */


# if defined( AF_UNIX ) || defined( OS_NT )
# if !defined( OS_UNIXWARE7 ) && !defined( OS_SINIX ) && !defined( OS_OS2 )

// Add HPUX11 to standard select using fd_set,  anything greater than 256
// causes select() to sleep. 

# if defined( OS_HPUX11 ) || defined( OS_NT )
# define USE_SELECT_FDSET
# else
# define USE_SELECT_BITARRAY
# endif

# define USE_SELECTOR

# endif
# endif

class NetTcpSelector
{

    public:

# ifdef USE_SELECT_BITARRAY

	// Choose the max of ( fd + 1 ) and FD_SETSIZE in case the
	// select call always expects at least FD_SETSIZE large...
	// This is a safety measure mostly, but I have observed that
	// the FreeBSD select man page says it always looks at 256
	// descriptors so I'm erring on the conservative side..

	NetTcpSelector( int t )
	{
	    fd = t;
	    if( ++t < FD_SETSIZE )
		t = FD_SETSIZE;
	    rfd = new BitArray( t );
	    wfd = new BitArray( t );
	}

	~NetTcpSelector()
	{
	    delete rfd;
	    delete wfd;
	}

	void SetRead() { rfd->tas( fd ); }
	void ClearRead() { rfd->clear( fd ); }
	int CheckRead() { return (*rfd)[ fd ]; }
	fd_set *Rfds() { return (fd_set*)rfd->fdset(); }

	void SetWrite() { wfd->tas( fd ); }
	void ClearWrite() { wfd->clear( fd ); }
	int CheckWrite() { return (*wfd)[ fd ]; }
	fd_set *Wfds() { return (fd_set*)wfd->fdset(); }

	BitArray	*rfd;
	BitArray	*wfd;

# endif

# ifdef USE_SELECT_FDSET

	NetTcpSelector( int t ) 
	{
	    fd = t;
	    FD_ZERO( &rfd );
	    FD_ZERO( &wfd );
	}

	void SetRead() { FD_SET( fd, &rfd ); }
	void ClearRead() { FD_CLR( fd, &rfd ); }
	int CheckRead() { return FD_ISSET( fd, &rfd ); }
	fd_set *Rfds() { return &rfd; }

	void SetWrite() { FD_SET( fd, &wfd ); }
	void ClearWrite() { FD_CLR( fd, &wfd ); }
	int CheckWrite() { return FD_ISSET( fd, &wfd ); }
	fd_set *Wfds() { return &wfd; }

	fd_set		rfd;
	fd_set		wfd;

# endif

# ifdef USE_SELECTOR

	/* Select() that works with BitArray or fd_set */

	int Select( int &read, int &write, int msec )
	{
	    for( ;; )
	    {
	        struct timeval tv;

	        if( read ) SetRead(); else ClearRead();
	        if( write ) SetWrite(); else ClearWrite();

		if( msec < 1000 )
		{
		    tv.tv_sec = 0;
		    tv.tv_usec = msec * 1000;
		}
		else
		{
		    tv.tv_sec = msec / 1000;
		    tv.tv_usec = ( msec % 1000 ) * 1000;
		}

	        switch( select( fd+1, Rfds(), Wfds(), 0, msec >= 0 ? &tv : 0 ) )
	        {
	        case -1:	
	            if( errno == EINTR )
	                continue;
		    return -1;

	        case 0:	
		    // duh linux leaves fd_sets set on timeout
		    read = write = 0;
		    return 0;

	        default: 
		    read = CheckRead();
		    write = CheckWrite();
		    return 1;
	        }
	    }
	}

# if defined(OS_NT) || defined(OS_SOLARIS)

	int Peek()
	{
	    char buf[2];
	    return recv( fd, buf, 1, MSG_PEEK ) > 0;
	}

# else

	int Peek()
	{
	    int nread;
	    return ioctl( fd, FIONREAD, &nread ) >= 0 && nread > 0;
	}

# endif

	int fd;

# else

	/* Braindead version: ignorance is bliss */

	NetTcpSelector( int ) {}

	int Select( int &read, int &write, int time )
	{
	    read = write = 1;
	    return 1;
	}

	int Peek()
	{
	    return 1;
	}

# endif

} ;

# Change User Description Committed
#1 22288 mark_mears import 2017.1 code drop