CSocket

Name

CSocket -- Encapsulation of a socket file descriptor.

Synopsis


class CSocket
{
    enum State {
      Disconnected,
      Bound,
      Listening,
      Connected
    };
    
  
            CSocket      
        ();
      
            CSocket
        ( int fd,  CSocket::State  state );
    
   const int  
            getSocketFd
        ();
       const CSocket::State 
             getState
        ();
       void  
            Connect
        (const  std::string& host, const  std::string&   service);
       void  Connect( unsigned long int  IpAddress,  unsigned short  service);
  
    
       void  
            Bind
        (const  std::string&  service);
       void  
            Listen 
        ( unsigned int  nBacklog = );
         CSocket*   
            Accept
        ( std::string&  client);
  
       void  
            Shutdown
        ();
       int  
            Read 
        ( void*  pBuffer,  size_t  nBytes);
       int  
            Write
        (const  void*  pBuffer,  size_t  nBytes);
  
       void  
            getPeer
        ( unsigned short& port,  std::string&  peer);
 
       void  
            OOBInline
        ( bool  State = TRUE);
       bool  
            isOOBInline
        ();
  
       void  
            setRcvLowWaterMark
        ( size_t  nBytes);
       void  
            setSndLowWaterMark
        ( size_t  nBytes);
       size_t  
            getSndLowWaterMark
        ();
       void  
            setRcvTimeout 
        ( unsigned int  nMs);
 
       unsigned int  
            getRcvTimeout
        ();
  

     void  
        setSndTimeout
    ( unsigned int  nMs);
     unsigned int  
        getSndTimeout 
    ();
     void  
        Debug
    ( bool  fState = TRUE);
     bool  
        isDebug
    ();
     void  
        SetNotRoutable
    ( bool  fRoutable = TRUE);
 
     bool  
        isNotRoutable
    ();
     void  
        setSndBufSize
    ( size_t  nBufferSize);
     size_t  
        getSndBufSize 
    ();
 
     void  setRcvBufSize( size_t  nBytes);
     size_t  getRcvBufSize();
     void  setLinger( bool  lOn,  int  nLingerSeconds);
     void  getLinger( bool& isLingering,  int& nLingerSeconds);
  
     static std::string  StateName( CSocket::State  state);
  
     void  Flush();
    

};
        

DESCRIPTION

This class encapsulates file descriptors that are open on BSD sockets. The package supports client sockets, servers sockets and encapsulating sockets that were opened via the socket(2) system call.

Client sockets normally construct, then connect and transfer data. Server sockets construct, bind to a server port, listen for connections and the accept connections creating a new data transfer socket. File descriptors that are opened on sockets can be wrapped in a CSocket object. Once wrapped the object can be treated as if it was constructed "normally".

CSocket objects are stateful. The state of an object is one of the values defined by the CSocket::State enum (See DATA TYPES below). The set of methods that can be legally invoked depends on the socket state. For each method described in METHODS below, we will indicate the state restrictions. If a method is invoked in a forbidden state, CTCPBadSocketState is thrown.

METHODS

CSocket ();

Constructs a new object. The object starts out life in the CSocket::Disconnected state.

CSocket ( int fd, CSocket::State state );

This constructor wraps the socket file descriptor; fd in a CSocket object. The state parameter describes the state.

It is important that you supply the correct state value to the constructor so that the object knows which methods are legal when.

const int getSocketFd ();

Returns the value of the file descriptor for the underlying socket.

const CSocket::State getState ();

Returns the current state of the socket.

void Connect (const std::string& host, const std::string& service);

Connects the socket as a client to a service port. The host parameter can be either a DNS host name string (e.g. "spdaq20.nscl.msu.edu") or a dotted IP address (e.g. "35.9.56.50"). The swervice is either a named service (from e.g. /etc/services in the peer) or a service number (e.g. "30000").

You can only call this method if the socket is in the CSocket::Disconnected state. If successful the socket is then in the CSocket::Connected state.

void Connect( unsigned long int IpAddress, unsigned short service);

Connects the socket to a server. IpAddress is the IP address of the server system in host byte order. service is the service port number in host byte order.

You can only call this method if the socket is in the CSocket::Disconnected state. If successful the socket is then in the CSocket::Connected state.

void Bind (const std::string& service);

Binds the socket to a service port. This makes the object a server socket. service is either the name of a service (e.g. in /etc/services) or a service number (e.g. "30000").

This method must be called with the socket in the CSocket::Disconnected state and, if successful, will put the socket in the CSocket::Bound state.

void Listen ( unsigned int nBacklog = );

Establishes a queue to accept connections on a server socket. nBacklog is the number of un-accepted connection requests that can be pending at any given time. If a a connection is requested when the listen queue is full, it is refused or allowed to retry depending on the protocol (according to linux man connect(2)).

The socket must be in the CSocket::Bound state. On successful completion, the socket is put in the CSocket::Listening state.

CSocket* Accept ( std::string& client);

Used by a server socket in the CSocket::Listening state to accept the next connection on the connection backlog queue. If there is no pending connection, this method will block until one is available.

The return value is a pointer to a CSocket in the CSocket::Connected state with which the server can exchange data with the client. Additionally the client parameter is filled in with information about the host. If the hostname can be determined via reverse DNS lookup, the fully qualified host name is stored. If not, the dotted IP address string is stored.

This method does not change the state of the object.

If you want to avoid blocking when there are no connections present in the backlog queue you can use getSocketFd to get the underlying socket's file descriptor and use it in either a poll(2) or select(2) system service testing for readability. The file descriptor will be considered readable when a connection is present on the backlog.

void Shutdown ();

Shuts down a socket that is in the CSocket::Connected state. The socket is still usable but:

  • The socket is in the CSocket::Disconnected state

  • Any attempts by the peer to transfer data to the socket will fail.

  • Any attempts by the peer to transfer data from the socket will only work as long as there is unconsumed data in the internal TCP/IP buffers for the file descriptor.

Note that this method invalidates any file descriptor the application may have cached via a call to getSocketFd. Such file descriptors must be re-fetched.

int Read ( void* pBuffer, size_t nBytes);

Reads data from the socket. The socket must be in the CSocket::Connected state. pBuffer points to a buffer into which the read data will be received. nBytes is the desired number of bytes to read. Normally if there are no bytes to read, this method will block until the read can be satisfied.

The method returns the number of bytes actually read. Note that this may be less than the number of bytes requested with nBytes.

Several exceptions can be thrown besides CTCPBadSocketState::

  • CErrnoException - if the underlying read(2) completed with an error. The socket is placed in the CSocket::Disconnected state.

  • CTCPConnectionLost - if the peer shutdown the socket or is no longer communicating for some other reason (program exit or system failure). The socket is shutdown and placed in the CSocket::Disconnected state.

int Write (const void* pBuffer, size_t nBytes);

Writes data to the peer over the socket. pBuffer points to the data to write and nBytes is the number of bytes of data to write. The return value is the number of bytes of data actually written which, on success, is always nBytes. If there are non-fatal errors like EAGAIN, EINTR or EWOULDBLOCK, method will attempt to write the unwritten parts of the buffer.

Exceptions can be thrown as follows:

  • CTCPBadSocketState - The socket is not in the CSocket::Connected state.

  • CTCPConnectionLost - the connection with the peer was lost and therefore future writes would also fail. The socket is placed in the CSocket::Disconnected state.

  • CErrnoException - some error was reported via errno. The socket is placed in the CSocket::Disconnected state.

void getPeer ( unsigned short& port, std::string& peer);

Fetches information about the peer of a CSocket::Connected socket. port is filled in with the port to which this port is connected. peer is filled in with either the fully qualfied domain name fo the hsot the peer runs on (if a reverse DNS lookup can be performed) or the dotted IP adress in string form if not.

void OOBInline ( bool State = TRUE);

Can be called when the socket is in any state except CState::Open Sets the SO_OOBINLINE parameter of the socket. If State is true, out of band data is included inline with the socket data. If false out of band data is not inline.

bool isOOBInline ();

Returns true if out of band data are inline else false.

void setRcvLowWaterMark ( size_t nBytes);

Sets the receive low water mark to nBytes. This value is the number of bytes that must have been buffered at the protocol level before data are returned to the caller.

Some operating systems don't actually allow this to be modified but silently do nothing. To detect if this state you can use getRcvLowWaterMark can be invoked to see what the current low water mark is.

void setSndLowWaterMark ( size_t nBytes);

Sets the low watermark of the send buffer. nBytes is the minimum number of bytes that must be buffered before the protocol starts emitting data.

size_t getSndLowWaterMark ();

Returns the receive low watermark value. This is the actual value which may differ from the value set.

void setRcvTimeout ( unsigned int nMs);

Sets the receive buffering timeout to nMs milliseconds. With a large receive low water mark, there is a chance that for reads lower than the watermark, if data are only being slowly received, reads could block for a long time or even forever waiting for the watermark to be hit. The receive timeout limits how long a read can be blocked when there is buffered data but fewer than the number of bytes in the receive low water mark.

unsigned int getRcvTimeout ();

Returns the value of the receive timeout.

void setSndTimeout ( unsigned int nMs);

Sets the value of the send timeout to nMs milliseconds. When the first bytes are written to the internal protocol buffers, a timer is started. Data are only written on the wire to the peer when either the send low watermark is achieved or the timer expires.

This timeout ensures that data are eventually queued for write to the peer with a maximum host side latencey of nMs milliseconds even if the data are being buffered quite slowly or the send low watermark is never achieved.

unsigned int getSndTimeout ();

Returns the number of milliseconds in the send timeout.

void Debug ( bool fState = TRUE);

Only programs with the effective user id of root can perform this operation (CErrnoException is thrown if otherwise). Setting this causes the system to produce debugging KERN_LOG messages which syslog can be configured to put into some log file for later analysis.

bool isDebug ();

Returns true if socket debugging is enabled. false if not.

void SetNotRoutable ( bool fRoutable = TRUE);

If fRoutable is true routing is turned off for the packets from this protocol. If fRoutable is false, routing is enabled.

Non routed messages will not be sent through gateways/routers. This confines them to the subnet local to the sender. To turn off routing on socket messages:

  • You should probably turn off routing on both sides.

  • You need to have a very good understanding of the network physical topology (what a subnet is and where your peer is relative to you).

bool isNotRoutable ();

Returns the state of the non-routing flag. true means routing is off for this socket while false means it is on.

void setSndBufSize ( size_t nBufferSize);

Sets the total size of the send buffer for the socket to nBufferSize. This is different from the low watermark. This determines the number of bytes of data that are buffered in the local machine while the peer has halted transmission via flow control. This buffering allows the application to continue to queue data for transmission without blocking until the buffer is full.

size_t getSndBufSize ();

Returns the number of bytes in the socket's send buffer.

void setRcvBufSize( size_t nBytes);

Sets the receive buffer size for the socket to nBytes. This is the number of received bytes the local host will buffer prior to exerting flow control on the peer to get it to slow down or stop transmitting. This buffer allows the local host to continue to receive data between reads of data at the application level.

size_t getRcvBufSize();

Returns the number of bytes of data in the receive buffer.

void setLinger( bool lOn, int nLingerSeconds);

The termination of a TCP/IP connection is a dance that requires cooperation from both parties to proceed properly. Best practices require the client to close the connection and the server, on detecting this to be the case, to close its side of the connection. When this is not done, connections can sit in the TIME_WAIT state for some time (the linger timeout)

This call allows the application to enable or disable lingering (the lOn parameter) and to set the linger timeout (nLingerSeconds).

Note that in general if you have to modify the default parameters your application protocol is probably not following TCP/IP best practices.

One case that may warrant it is when the server detects a misbehaving client and may want to abortively close the connection. In that case the linger timeout can be set to zero or lingering turned off in order to avoid hanging the connection in TIME_WAIT.

void getLinger( bool& isLingering, int& nLingerSeconds);

Sets isLingering to the state of the socket's lingering flat and nLingerSeconds to the linger timeout.

static std::string StateName( CSocket::State state);

Given a socket state value returns a string that represents that state. This is used in generating user readable messages that must include the state.

void Flush();

Reads and discards all data buffered fro iput on the socket.

DATA TYPES

The CSocket::State data type is exported as public. This type is an enum that represents a socket state. It is defined as follows:


enum State {
    Disconnected,
    Bound,
    Listening,
    Connected
};
            

SEE ALSO

CTCPBadSocketState, CTCPConnectionFailed, CTCPConnectionLost, CTCPNoSuchHost, CTCPNoSuchService