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