C++ Language Socket Class

/**

* @file UtilSocket.h

* Definitions for UtilSocket class (Windows)

*/


#ifndef UTILSOCKET_H_


#define UTILSOCKET_H_


#include <winsock2.h>

#include <ws2tcpip.h>


#pragma comment(lib,  "ws2_32.lib"


class UtilSocket

{

public:


    UtilSocket(int domain);

    UtilSocket(int socknum, sockaddr_in addrinet);

    virtual ~UtilSocket();


    void BindToPort(int port);

    void Listen(int queueLen);

    UtilSocket * Accept();

    void Connect(char * address, int port);

    void SetSocketOption(int optname, const void * optval, int optlen);

    void GetSocketOption(int optname, void * optval, int * optlen);

    int Receive(char * buffer, int bufferSize);

    void Send(char * buff, int len);

    bool getDestroying() {return m_Destroying;}

    void Send(const char * message) {Send((char * ) message);}

    void Send(char * message) {Send(message, strlen(message));}

    void Send(char thechar) {Send( & thechar, 1);}


private:


    SOCKET m_Sock;

    bool m_Destroying;

    int m_Domain;

    sockaddr_in m_SockAddrInet;

};


#endif /* UTILSOCKET_H_ */


/**

* @file UtilSocket.cpp

* UtilSocket class (Windows)

*/


#include <stdio.h>

#include "UtilSocket.h"



void print_wsa_error(char *prefix, int num )

{

       wchar_t *s = NULL;


       FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 

               NULL, WSAGetLastError(),

               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

               (LPWSTR)&s, 0, NULL);

       printf( "%s%S\n", prefix, s);

       LocalFree(s);

}


static bool wsa_initialized=false;


UtilSocket::UtilSocket(int domain):

    m_Sock(-1),

    m_Destroying(false),

    m_Domain(domain)

{

    int protocol = 0;


       if(wsa_initialized==false)

       {

               wsa_initialized=true;

               WSADATA wsaData = {0};


               int status = WSAStartup(MAKEWORD(2, 2),&wsaData);

               if( status !=0 )

               {

                       printf("WSAStartup failed: %d\n", status );

                       throw "[WSA_Init_Failed]";

               }

       }


    if (m_Domain == AF_INET)

        protocol = IPPROTO_TCP;


    m_Sock = socket(domain, SOCK_STREAM, protocol);

    if (m_Sock == INVALID_SOCKET )

       {

        throw "[Socket_Open_Error]";

       }

}


/**

* Constructor for UtilSocket class

*

* @details

* Construct UtilSocket object by initializing private variables.

* Use this constructor if you already have an opened socket, say

* from the result of an Accept operation.

*

* @param socknum Socket number (returned from accept)

* @param addrinet Socket address indicating AF_INET domain

*/


UtilSocket::UtilSocket(int socknum, sockaddr_in addrinet):

    m_Sock(socknum),

    m_Destroying(false),

    m_Domain(AF_INET)

{

       if(wsa_initialized==false)

       {

               printf("Initializing WSAStartup\n");


               wsa_initialized=true;

               WSADATA wsaData = {0};

               int status = WSAStartup(MAKEWORD(2, 2),&wsaData);

               if( status !=0 )

               {

                       printf("WSAStartup failed: %d\n", status );

                       throw "[WSA_Init_Failed]";

               }

       }


    m_SockAddrInet = addrinet;

}


/**

* Destructor for UtilSocket class

*

* @details

* Destruct socket object by closing socket if necessary. Set

* private m_Destroying flag in case subsequent call to Close()

* wants to know if destructor has been entered.

*/


UtilSocket::~UtilSocket()

{

    m_Destroying = true;


    if (m_Sock != -1)

    {

        shutdown(m_Sock, SD_BOTH);

        closesocket(m_Sock);

        m_Sock = -1;

    }

}


/**

* Bind socket to "Any" address for specified port

*

* @details

* Previously-created socket is bound to a specific port, but for any

* IP address. This is typically used by server function to be able to

* accept connections on a specific port from multiple clients.

*

* @param port Which port to bind to

*/


void UtilSocket::BindToPort(int port)

{

    if (m_Domain != AF_INET)

        throw "[Socket_Bind_Domain_Error]";


    m_SockAddrInet.sin_family = AF_INET;

    m_SockAddrInet.sin_port = htons(port);

    m_SockAddrInet.sin_addr.s_addr = INADDR_ANY;


    if (bind(m_Sock, (struct sockaddr * ) & m_SockAddrInet, sizeof(m_SockAddrInet)) == SOCKET_ERROR )

        throw "[Socket_Bind_Error]";

}


/**

* Listen for any connection

*

* @details

* Listens for any connection on the specified socket.

*

* @param queueLen species connection queue length

*/


void UtilSocket::Listen(int queueLen)

{

    if (listen(m_Sock, queueLen) == SOCKET_ERROR )

        throw "[Socket_Listening_Error]";

}


/**

* Accept connection to client

*

* @details

* Accepts a connection to a client represented by the inbound

* parameter. Typically, listen is called on a particular socket,

* and if it returns okay, then Accept is called to accept the connection.

*

* @return Socket that has made connection with

*/


UtilSocket * UtilSocket::Accept()

{

    socklen_t size;

    sockaddr * ptr = NULL;

    sockaddr_in addrinet;


    if (m_Domain == AF_INET)

    {

        size = sizeof(sockaddr_in);

        ptr = (sockaddr * ) & addrinet;

    }

    else

        throw "[Socket_Bad_Domain]";


    int newSock = accept(m_Sock, ptr, & size);

    if (newSock == INVALID_SOCKET )

        throw "[Socket_Accept_Failed]";


    UtilSocket * retn = NULL;

    retn = new UtilSocket(newSock, addrinet);

    return retn;

}


/**

* Connect to a particular ip address and port

*

* @details

* Used by "client" application to connect to a specific IP Address and port.

*

* @param address Server address, which is run through gethostbyname(),

* @param port Server address port to connect to

*/


void UtilSocket::Connect(char * address, int port)

{

    struct in_addr * addr_ptr;

    struct hostent * hostPtr;

    char *add;

    try

    {

        hostPtr = gethostbyname(address);

        if (hostPtr == NULL)

            throw "[Socket_No_Hostname]";


        // the first address in the list of host addresses


        addr_ptr = (struct in_addr * ) * hostPtr -> h_addr_list;


        // changed the address format to the

        // Internet address in standard dot notation


        add = inet_ntoa( * addr_ptr);

        if ( add==NULL || *add == 0)

            throw "[Socket_Address_Format_Error]";

    }

       catch(...)

    //catch (int e)

    {

        throw "[Socket_Address_Error]";

    }


    struct sockaddr_in sockAddr;

    sockAddr.sin_family = AF_INET;

    sockAddr.sin_port = htons(port);

    sockAddr.sin_addr.s_addr = inet_addr(add);


//        unsigned long ul=1;

//        int ret=ioctlsocket(m_Sock, FIONBIO, (unsigned long *)&ul);//Set into non blocking mode.


    try

    {

        int res = connect(m_Sock, (struct sockaddr * ) & sockAddr, sizeof(struct sockaddr));


        if ( res == SOCKET_ERROR )

        {

               int errnumber = WSAGetLastError();

               print_wsa_error("connect error:", errnumber );


            fd_set fdset;

            FD_ZERO( & fdset);

            FD_SET(m_Sock, & fdset);


            struct timeval connectionTimeout;

            connectionTimeout.tv_sec = 10;

            connectionTimeout.tv_usec = 0;


            res = select(m_Sock + 1, NULL, & fdset, NULL, & connectionTimeout);

            if (res == 0)

                throw "[Socket_Connect_Timeout]";


            if (res == SOCKET_ERROR )

                throw "[Socket_Select_Error]";

        }

               

       unsigned long ul=0;

       int ret=ioctlsocket(m_Sock, FIONBIO, (unsigned long *)&ul);//Set into non blocking mode.

    }

    catch (...)

    {

       unsigned long ul=0;

       int ret=ioctlsocket(m_Sock, FIONBIO, (unsigned long *)&ul);//Set into non blocking mode.

      throw;

    }

}


/**

* Send data to socket

*

* @details

* Sends specified number of bytes to socket

*

* @param buff Source location of buffer to transmit

* @param len Number of bytes to transmit

*/


void UtilSocket::Send(char * buffer, int len)


{

    int retn = send(m_Sock, buffer, len, 0);

    if (retn == SOCKET_ERROR )

        throw "[Socket_Send_Error]";


    if (retn != len)

        throw "[Socket_Send_Not_Complete]";

}


/**

* Receive data

*

* @details

* Receive data from a port. Since no timeouts are set, this is

* a blocking call that will block forever. Use of signal() is

* required to halt invocation if thread wants to terminate.

*

* @param buffer Destination buffer (bytes)

* @param bufferLen Number of bytes in the destination buffer

* @return Actual number of bytes received (.le. bufferLen)

*/


int UtilSocket::Receive(char * buffer, int bufferLen)

{

    buffer[0] = 0;


    int retn = recv(m_Sock, buffer, bufferLen, 0);


    if (retn == SOCKET_ERROR )

        throw "[Socket_Receive_Error]";


    if (retn == 0)

        throw "[Socket_Receive_Zero_Bytes]";


    if (retn < bufferLen)

        buffer[retn] = 0;


    return retn;

}


/**

* Set socket option

*

* @details

* Sets low-level socket options on previously-created socket

*

* @param optname Option name

* @param optval Pointer to option value

* @param optlen Number of bytes in option value

*/


void UtilSocket::SetSocketOption(int optname, const void * optval, int optlen)


{

    if (setsockopt(m_Sock, SOL_SOCKET, optname, (const char*) optval, (socklen_t) optlen) == SOCKET_ERROR )

        throw "[Socket_Set_Option_Error]";

}


/**

* Get socket option

*

* @details

* Gets low-level socket options on previously-created socket

*

* @param optname Option name

* @param optval Pointer to option value

* @param optlen Number of bytes in option value

*/


void UtilSocket::GetSocketOption(int optname, void * optval, int * optlen)

{

    * optlen = 0;

    socklen_t x;


    if (getsockopt(m_Sock, SOL_SOCKET, optname, (char*) optval, & x) == SOCKET_ERROR )

        throw "[Socket_Get_Option_Error]";


    * optlen = (int) x;

}


// EOF