/***************************************************************************** ************************* AIRBORNE SYSTEMS ************************* ************************* COMPUTING DEVICES CANADA ************************* ****************************************************************************** Filename: CSocket.cpp Project: LOCATOR Purpose: C++ implementation for the LOCATOR CSocket class. Base class for the LOCATOR socket objects. This class provides the lowest-level management of the sockets. Release: V1.0 Author: Denis Dumas Date: 30-Jul-1999 Modified: *****************************************************************************/ #include "vxWorks.h" #include "sockLib.h" #include "unistd.h" #include "errno.h" #include "string.h" #include "LOCATORconstants.h" #include "CMsgLog.h" #include "CSocket.h" /*--------------------------------------------------------------------------- Method Name: CSocket::CSocket() Purpose: Default constructor. Parameters In: None. Parameters Out: None. Return Values: None. Notes: None. ---------------------------------------------------------------------------*/ CSocket::CSocket() { // Initialize variables. cIsInitialized = false; cSocketDescriptor = -1; } /*--------------------------------------------------------------------------- Method Name: CSocket::~CSocket() Purpose: Default destructor. Parameters In: None. Parameters Out: None. Return Values: None. Notes: None. ---------------------------------------------------------------------------*/ CSocket::~CSocket() { // Always close the socket. close ( cSocketDescriptor ); } /*--------------------------------------------------------------------------- Method Name: CSocket::Init() Purpose: Creates/initializes the socket. Parameters In: None. Parameters Out: None. Return Values: SUCCESS on successful completion, ERROR_GENERAL otherwise. Notes: None. ---------------------------------------------------------------------------*/ int CSocket::Init() { const char * const lMethod = "CSocket::Init()"; // Create a connection-oriented socket. cSocketDescriptor = socket ( AF_INET, SOCK_STREAM, 0 ); if ( cSocketDescriptor < 0 ) { gMsg.Log ( lMethod, "failed to create socket" ); gMsg.Log ( "errno error", strerror ( errno ) ); return ERROR_GENERAL; } // Everything is OK at this point. cIsInitialized = true; return SUCCESS; } /*--------------------------------------------------------------------------- Method Name: CSocket::Init() Purpose: Initializes the socket. Parameters In: Valid socket file descriptor. Parameters Out: None. Return Values: SUCCESS on successful completion, ERROR_GENERAL otherwise. Notes: None. ---------------------------------------------------------------------------*/ int CSocket::Init ( const int pSocketDescriptor ) { const char * const lMethod = "CSocket::Init ( int )"; bool lHasData; // At the very minimum the file descriptor should be positive. if ( pSocketDescriptor < 0 ) { gMsg.Log ( lMethod, "invalid file descriptor on input" ); gMsg.Log ( "file descriptor", pSocketDescriptor ); return ERROR_GENERAL; } // Assume that the file descriptor is valid. cSocketDescriptor = pSocketDescriptor; cIsInitialized = true; // CheckSocket will detect if this is a valid file descriptor. if ( CheckSocket ( &lHasData ) != SUCCESS ) { cIsInitialized = false; gMsg.Log ( lMethod, "something wrong with file descriptor" ); return ERROR_GENERAL; } // At this point all is ok. return SUCCESS; } /*--------------------------------------------------------------------------- Method Name: CSocket::CheckSocket() Purpose: Checks the socket for activity or errors. Parameters In: pHasData - pointer to boolean. Parameters Out: pHasData - Set to true if there is data in the socket, otherwise set to false. Return Values: SUCCESS on successful completion, ERROR_GENERAL otherwise. Notes: None. ---------------------------------------------------------------------------*/ int CSocket::CheckSocket ( bool * const pHasData ) { const char * const lMethod = "CSocket::CheckSocket"; const int lNcallsMax = 10; int lActivity, lNcalls; bool lInterrupted; fd_set lReadSet, lErrorSet; struct timeval lTimeout; // The socket must be initialized at this point. *pHasData = false; if ( !cIsInitialized ) { gMsg.Log ( lMethod, "attempt to use socket before initialization" ); return ERROR_GENERAL; } // Initialize the read and error descriptor sets to the null set, and add // this socket's file descriptor to these descriptor sets. FD_ZERO ( &lReadSet ); FD_SET ( cSocketDescriptor, &lReadSet ); FD_ZERO ( &lErrorSet ); FD_SET ( cSocketDescriptor, &lErrorSet ); // This is a poll to see if this socket is ready to read from, so // the timeout period has to be set to 0 (can't just use a NULL pointer). lTimeout.tv_sec = 0; lTimeout.tv_usec = 0; // Ok. Now check to see if this socket has activity on it... // Specify a timeout of 0 to return immediately. // Repeat until call not interrupted, or limit reached. lNcalls = 0; do { lNcalls++; lInterrupted = false; lActivity = select ( cSocketDescriptor+1, &lReadSet, NULL, &lErrorSet, &lTimeout ); // Check to see if an error in the call to select() occured. // The error EINTR means that the select call was interrupted. if ( lActivity < 0 ) { gMsg.Log ( lMethod, "error during call to select" ); gMsg.Log ( "errno error", strerror ( errno ) ); if ( errno != EINTR ) return ERROR_GENERAL; else lInterrupted = true; } } while ( lInterrupted && ( lNcalls <= lNcallsMax ) ); // If the limit was reached something bizarre is going on... if ( lNcalls > lNcallsMax ) { gMsg.Log ( lMethod, "select() interrupted maximum number of times" ); return ERROR_GENERAL; } // Error condition on this socket? if ( FD_ISSET ( cSocketDescriptor, &lErrorSet ) != 0 ) { gMsg.Log ( lMethod, "error condition detected on socket" ); return ERROR_GENERAL; } // The final check is for input data. // If this test is non-zero there is some data waiting... if ( FD_ISSET ( cSocketDescriptor, &lReadSet ) != 0) *pHasData = true; // All done. return SUCCESS; } /*--------------------------------------------------------------------------- Method Name: CSocket::Setfds() Purpose: Sets the fds mask with this socket's descriptor. Parameters In: pReadSet - pointer to read file descriptor set. Parameters Out: pReadSet - bit for this socket fds is set. pMaxfd - updated with this file descriptor if it is larger Return Values: SUCCESS on successful completion, ERROR_GENERAL otherwise. Notes: None. ---------------------------------------------------------------------------*/ int CSocket::Setfds ( fd_set * const pReadSet, int * pMaxfd ) { const char * const lMethod = "CSocket::Setfds"; // The socket must be initialized at this point. if ( !cIsInitialized ) { gMsg.Log ( lMethod, "attempt to use socket before initialization" ); return ERROR_GENERAL; } // Set the bit for this socket and update pMaxfd, if necessary. FD_SET ( cSocketDescriptor, pReadSet ); if ( ( cSocketDescriptor + 1 ) > *pMaxfd ) *pMaxfd = cSocketDescriptor + 1; return SUCCESS; }