First Attempt at merging socket code into cross platform classes

This commit is contained in:
Mark Vejvoda 2010-04-13 06:59:30 +00:00
parent 2c9b6ea3ee
commit 561dd69107
2 changed files with 383 additions and 109 deletions

View File

@ -28,11 +28,22 @@
using std::string;
#ifdef WIN32
#include <winsock2.h>
typedef SOCKET PLATFORM_SOCKET;
const char* WSAGetLastErrorMessage(const char* pcMessagePrefix,int nErrorID = 0);
#else
typedef int PLATFORM_SOCKET;
#endif
namespace Shared{ namespace Platform{
//
// This interface describes the methods a callback object must implement
// when signalled with detected servers
// when signaled with detected servers
//
class DiscoveredServersInterface {
public:
@ -42,8 +53,7 @@ public:
// =====================================================
// class IP
// =====================================================
class Ip{
class Ip {
private:
unsigned char bytes[4];
@ -61,27 +71,42 @@ public:
// =====================================================
class Socket {
#ifdef WIN32
private:
class SocketManager{
public:
SocketManager();
~SocketManager();
};
protected:
int sock;
static SocketManager socketManager;
#endif
protected:
PLATFORM_SOCKET sock;
long lastDebugEvent;
static int broadcast_portno;
public:
Socket(int sock);
Socket(PLATFORM_SOCKET sock);
Socket();
virtual ~Socket();
static int getBroadCastPort() { return broadcast_portno; }
static int getBroadCastPort() { return broadcast_portno; }
static void setBroadCastPort(int value) { broadcast_portno = value; }
static std::vector<std::string> getLocalIPAddressList();
// Int lookup is socket fd while bool result is whether or not that socket was signalled for reading
static bool hasDataToRead(std::map<int,bool> &socketTriggeredList);
static bool hasDataToRead(int socket);
static bool hasDataToRead(std::map<PLATFORM_SOCKET,bool> &socketTriggeredList);
static bool hasDataToRead(PLATFORM_SOCKET socket);
bool hasDataToRead();
void disconnectSocket();
int getSocketId() const { return sock; }
PLATFORM_SOCKET getSocketId() const { return sock; }
int getDataToRead();
int send(const void *data, int dataSize);
@ -89,7 +114,7 @@ public:
int peek(void *data, int dataSize);
void setBlock(bool block);
static void setBlock(bool block, int socket);
static void setBlock(bool block, PLATFORM_SOCKET socket);
bool isReadable();
bool isWritable(bool waitOnDelayedResponse);
@ -97,9 +122,10 @@ public:
static string getHostName();
static string getIp();
bool isSocketValid(PLATFORM_SOCKET *validateSocket=NULL) const;
protected:
static void throwException(const string &str);
static void throwException(string str);
};
class BroadCastClientSocketThread : public Thread
@ -127,8 +153,7 @@ public:
// =====================================================
// class ClientSocket
// =====================================================
class ClientSocket: public Socket{
class ClientSocket: public Socket {
public:
ClientSocket();
virtual ~ClientSocket();
@ -167,7 +192,6 @@ public:
// =====================================================
// class ServerSocket
// =====================================================
class ServerSocket: public Socket{
public:
ServerSocket();

View File

@ -12,13 +12,14 @@
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
#include <sstream>
//#include <sstream>
#if defined(HAVE_SYS_IOCTL_H)
#define BSD_COMP /* needed for FIONREAD on Solaris2 */
#include <sys/ioctl.h>
#define BSD_COMP /* needed for FIONREAD on Solaris2 */
#include <sys/ioctl.h>
#endif
#if defined(HAVE_SYS_FILIO_H) /* needed for FIONREAD on Solaris 2.5 */
#include <sys/filio.h>
#if defined(HAVE_SYS_FILIO_H) /* needed for FIONREAD on Solaris 2.5 */
#include <sys/filio.h>
#endif
#include <net/if.h>
@ -29,30 +30,223 @@
#include <algorithm>
#ifdef WIN32
# include <windows.h>
# include <winsock.h>
# include <iphlpapi.h>
#include <windows.h>
#include <winsock.h>
#include <iphlpapi.h>
//#include <strstream>
#else
# include <unistd.h>
# include <stdlib.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <net/if.h>
# include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
//#include <net/if.h>
//#include <sys/ioctl.h>
#endif
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Util;
namespace Shared{ namespace Platform{
#ifdef WIN32
#define socklen_t int
#define MAXHOSTNAME 254
#define PLATFORM_SOCKET_TRY_AGAIN WSAEWOULDBLOCK
#define PLATFORM_SOCKET_INPROGRESS WSAEINPROGRESS
#define PLATFORM_SOCKET_INTERRUPTED WSAEWOULDBLOCK
typedef SSIZE_T ssize_t;
//// Constants /////////////////////////////////////////////////////////
const int kBufferSize = 1024;
//// Statics ///////////////////////////////////////////////////////////
// List of Winsock error constants mapped to an interpretation string.
// Note that this list must remain sorted by the error constants'
// values, because we do a binary search on the list when looking up
// items.
static class ErrorEntry
{
public:
int nID;
const char* pcMessage;
ErrorEntry(int id, const char* pc = 0) : nID(id), pcMessage(pc)
{
}
bool operator<(const ErrorEntry& rhs)
{
return nID < rhs.nID;
}
} gaErrorList[] =
{
ErrorEntry(0, "No error"),
ErrorEntry(WSAEINTR, "Interrupted system call"),
ErrorEntry(WSAEBADF, "Bad file number"),
ErrorEntry(WSAEACCES, "Permission denied"),
ErrorEntry(WSAEFAULT, "Bad address"),
ErrorEntry(WSAEINVAL, "Invalid argument"),
ErrorEntry(WSAEMFILE, "Too many open sockets"),
ErrorEntry(WSAEWOULDBLOCK, "Operation would block"),
ErrorEntry(WSAEINPROGRESS, "Operation now in progress"),
ErrorEntry(WSAEALREADY, "Operation already in progress"),
ErrorEntry(WSAENOTSOCK, "Socket operation on non-socket"),
ErrorEntry(WSAEDESTADDRREQ, "Destination address required"),
ErrorEntry(WSAEMSGSIZE, "Message too long"),
ErrorEntry(WSAEPROTOTYPE, "Protocol wrong type for socket"),
ErrorEntry(WSAENOPROTOOPT, "Bad protocol option"),
ErrorEntry(WSAEPROTONOSUPPORT, "Protocol not supported"),
ErrorEntry(WSAESOCKTNOSUPPORT, "Socket type not supported"),
ErrorEntry(WSAEOPNOTSUPP, "Operation not supported on socket"),
ErrorEntry(WSAEPFNOSUPPORT, "Protocol family not supported"),
ErrorEntry(WSAEAFNOSUPPORT, "Address family not supported"),
ErrorEntry(WSAEADDRINUSE, "Address already in use"),
ErrorEntry(WSAEADDRNOTAVAIL, "Can't assign requested address"),
ErrorEntry(WSAENETDOWN, "Network is down"),
ErrorEntry(WSAENETUNREACH, "Network is unreachable"),
ErrorEntry(WSAENETRESET, "Net connection reset"),
ErrorEntry(WSAECONNABORTED, "Software caused connection abort"),
ErrorEntry(WSAECONNRESET, "Connection reset by peer"),
ErrorEntry(WSAENOBUFS, "No buffer space available"),
ErrorEntry(WSAEISCONN, "Socket is already connected"),
ErrorEntry(WSAENOTCONN, "Socket is not connected"),
ErrorEntry(WSAESHUTDOWN, "Can't send after socket shutdown"),
ErrorEntry(WSAETOOMANYREFS, "Too many references, can't splice"),
ErrorEntry(WSAETIMEDOUT, "Connection timed out"),
ErrorEntry(WSAECONNREFUSED, "Connection refused"),
ErrorEntry(WSAELOOP, "Too many levels of symbolic links"),
ErrorEntry(WSAENAMETOOLONG, "File name too long"),
ErrorEntry(WSAEHOSTDOWN, "Host is down"),
ErrorEntry(WSAEHOSTUNREACH, "No route to host"),
ErrorEntry(WSAENOTEMPTY, "Directory not empty"),
ErrorEntry(WSAEPROCLIM, "Too many processes"),
ErrorEntry(WSAEUSERS, "Too many users"),
ErrorEntry(WSAEDQUOT, "Disc quota exceeded"),
ErrorEntry(WSAESTALE, "Stale NFS file handle"),
ErrorEntry(WSAEREMOTE, "Too many levels of remote in path"),
ErrorEntry(WSASYSNOTREADY, "Network system is unavailable"),
ErrorEntry(WSAVERNOTSUPPORTED, "Winsock version out of range"),
ErrorEntry(WSANOTINITIALISED, "WSAStartup not yet called"),
ErrorEntry(WSAEDISCON, "Graceful shutdown in progress"),
ErrorEntry(WSAHOST_NOT_FOUND, "Host not found"),
ErrorEntry(WSANO_DATA, "No host data of that type was found")
};
bool operator<(const ErrorEntry& rhs1,const ErrorEntry& rhs2)
{
return rhs1.nID < rhs2.nID;
}
const int kNumMessages = sizeof(gaErrorList) / sizeof(ErrorEntry);
//// WSAGetLastErrorMessage ////////////////////////////////////////////
// A function similar in spirit to Unix's perror() that tacks a canned
// interpretation of the value of WSAGetLastError() onto the end of a
// passed string, separated by a ": ". Generally, you should implement
// smarter error handling than this, but for default cases and simple
// programs, this function is sufficient.
//
// This function returns a pointer to an internal static buffer, so you
// must copy the data from this function before you call it again. It
// follows that this function is also not thread-safe.
const char* WSAGetLastErrorMessage(const char* pcMessagePrefix,
int nErrorID /* = 0 */)
{
// Build basic error string
static char acErrorBuffer[256];
std::ostrstream outs(acErrorBuffer, sizeof(acErrorBuffer));
outs << pcMessagePrefix << ": ";
// Tack appropriate canned message onto end of supplied message
// prefix. Note that we do a binary search here: gaErrorList must be
// sorted by the error constant's value.
ErrorEntry* pEnd = gaErrorList + kNumMessages;
ErrorEntry Target(nErrorID ? nErrorID : WSAGetLastError());
ErrorEntry* it = std::lower_bound(gaErrorList, pEnd, Target);
if ((it != pEnd) && (it->nID == Target.nID))
{
outs << it->pcMessage;
}
else
{
// Didn't find error in list, so make up a generic one
outs << "unknown error";
}
outs << " (" << Target.nID << ")";
// Finish error message off and return it.
outs << std::ends;
acErrorBuffer[sizeof(acErrorBuffer) - 1] = '\0';
return acErrorBuffer;
}
Socket::SocketManager Socket::socketManager;
Socket::SocketManager::SocketManager(){
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
WSAStartup(wVersionRequested, &wsaData);
//dont throw exceptions here, this is a static initializacion
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Winsock initialized.\n");
}
Socket::SocketManager::~SocketManager(){
WSACleanup();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Winsock cleanup complete.\n");
}
#else
typedef unsigned int UINT_PTR, *PUINT_PTR;
typedef UINT_PTR SOCKET;
#define INVALID_SOCKET (SOCKET)(~0)
#define PLATFORM_SOCKET_TRY_AGAIN EAGAIN
#define PLATFORM_SOCKET_INPROGRESS EINPROGRESS
#define PLATFORM_SOCKET_INTERRUPTED EINTR
#endif
int Socket::broadcast_portno = 61357;
BroadCastClientSocketThread *ClientSocket::broadCastClientThread = NULL;
int getLastSocketError() {
#ifndef WIN32
return errno;
#else
return WSAGetLastError();
#endif
}
char * getLastSocketErrorText(int *errNumber=NULL) {
int errId = (errNumber != NULL ? *errNumber : getLastSocketError());
#ifndef WIN32
return strerror(errId);
#else
return WSAGetLastErrorMessage(errId);
#endif
}
string getLastSocketErrorFormattedText(int *errNumber=NULL) {
int errId = (errNumber != NULL ? *errNumber : getLastSocketError());
string msg = "(Error: " + intToStr(errId) + " - [" + string(getLastSocketErrorText(&errId)) +"])";
return msg;
}
// =====================================================
// class Ip
// =====================================================
@ -425,9 +619,11 @@ std::vector<std::string> Socket::getLocalIPAddressList() {
ipIdx++;
}
#ifndef WIN32
// Now check all linux network devices
for(int idx = 0; idx < 5; ++idx) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
PLATFORM_SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0);
/* I want to get an IPv4 IP address */
struct ifreq ifr;
@ -450,17 +646,37 @@ std::vector<std::string> Socket::getLocalIPAddressList() {
}
}
#endif
return ipList;
}
Socket::Socket(int sock){
bool Socket::isSocketValid(PLATFORM_SOCKET *validateSocket) const {
#ifdef WIN32
if(validateSocket == NULL) {
return (sock != INVALID_SOCKET);
}
else {
return (*validateSocket != INVALID_SOCKET);
}
#else
if(validateSocket == NULL) {
return (sock > 0);
}
else {
return (*validateSocket > 0);
}
#endif
}
Socket::Socket(PLATFORM_SOCKET sock){
this->sock= sock;
}
Socket::Socket()
{
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock < 0)
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(isSocketValid() == false)
{
throwException("Error creating socket");
}
@ -479,19 +695,24 @@ void Socket::disconnectSocket()
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
if(sock > 0)
if(isSocketValid() == true)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] calling shutdown and close for socket = %d...\n",__FILE__,__FUNCTION__,sock);
::shutdown(sock,2);
#ifndef WIN32
::close(sock);
sock = INVALID_SOCKET;
#else
::closesocket(sock);
sock = -1;
#endif
}
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END closing socket = %d...\n",__FILE__,__FUNCTION__,sock);
}
// Int lookup is socket fd while bool result is whether or not that socket was signalled for reading
bool Socket::hasDataToRead(std::map<int,bool> &socketTriggeredList)
bool Socket::hasDataToRead(std::map<PLATFORM_SOCKET,bool> &socketTriggeredList)
{
bool bResult = false;
@ -501,11 +722,11 @@ bool Socket::hasDataToRead(std::map<int,bool> &socketTriggeredList)
fd_set rfds;
FD_ZERO(&rfds);
int imaxsocket = 0;
for(std::map<int,bool>::iterator itermap = socketTriggeredList.begin();
PLATFORM_SOCKET imaxsocket = 0;
for(std::map<PLATFORM_SOCKET,bool>::iterator itermap = socketTriggeredList.begin();
itermap != socketTriggeredList.end(); itermap++)
{
int socket = itermap->first;
PLATFORM_SOCKET socket = itermap->first;
if(socket > 0)
{
FD_SET(socket, &rfds);
@ -523,7 +744,7 @@ bool Socket::hasDataToRead(std::map<int,bool> &socketTriggeredList)
int retval = select(imaxsocket + 1, &rfds, NULL, NULL, &tv);
if(retval < 0)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR SELECTING SOCKET DATA retval = %d errno = %d [%s]\n",__FILE__,__FUNCTION__,retval,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR SELECTING SOCKET DATA retval = %d error = %s\n",__FILE__,__FUNCTION__,retval,getLastSocketErrorFormattedText().c_str());
}
else if(retval)
{
@ -531,10 +752,10 @@ bool Socket::hasDataToRead(std::map<int,bool> &socketTriggeredList)
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] select detected data imaxsocket = %d...\n",__FILE__,__FUNCTION__,imaxsocket);
for(std::map<int,bool>::iterator itermap = socketTriggeredList.begin();
for(std::map<PLATFORM_SOCKET,bool>::iterator itermap = socketTriggeredList.begin();
itermap != socketTriggeredList.end(); itermap++)
{
int socket = itermap->first;
PLATFORM_SOCKET socket = itermap->first;
if (FD_ISSET(socket, &rfds))
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] FD_ISSET true for socket %d...\n",__FUNCTION__,socket);
@ -560,7 +781,7 @@ bool Socket::hasDataToRead()
return Socket::hasDataToRead(sock) ;
}
bool Socket::hasDataToRead(int socket)
bool Socket::hasDataToRead(PLATFORM_SOCKET socket)
{
bool bResult = false;
@ -607,15 +828,18 @@ int Socket::getDataToRead(){
//retval = select(sock + 1, &rfds, NULL, NULL, &tv);
//if(retval)
if(sock > 0)
if(isSocketValid() == true)
{
/* ioctl isn't posix, but the following seems to work on all modern
* unixes */
int err= ioctl(sock, FIONREAD, &size);
if(err < 0 && errno != EAGAIN)
#ifndef WIN32
int err = ioctl(sock, FIONREAD, &size);
#else
int err= ioctlsocket(sock, FIONREAD, &size);
#endif
if(err < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR PEEKING SOCKET DATA, err = %d errno = %d [%s]\n",__FILE__,__FUNCTION__,err,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR PEEKING SOCKET DATA, err = %d %s\n",__FILE__,__FUNCTION__,err,getLastSocketErrorFormattedText().c_str());
//throwException(szBuf);
}
else if(err == 0)
@ -629,21 +853,21 @@ int Socket::getDataToRead(){
int Socket::send(const void *data, int dataSize) {
ssize_t bytesSent= 0;
if(sock > 0)
if(isSocketValid() == true)
{
bytesSent = ::send(sock, reinterpret_cast<const char*>(data), dataSize, 0);
}
if(bytesSent < 0 && errno != EAGAIN)
if(bytesSent < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR WRITING SOCKET DATA, err = %d errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesSent,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR WRITING SOCKET DATA, err = %d error = %s\n",__FILE__,__FUNCTION__,bytesSent,getLastSocketErrorFormattedText().c_str());
//throwException(szBuf);
}
else if(bytesSent < 0 && errno == EAGAIN)
else if(bytesSent < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #1 EAGAIN during send, trying again...\n",__FILE__,__FUNCTION__);
time_t tStartTimer = time(NULL);
while((bytesSent < 0 && errno == EAGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
while((bytesSent < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
{
if(Socket::isWritable(true) == true)
{
@ -655,10 +879,10 @@ int Socket::send(const void *data, int dataSize) {
}
if(bytesSent <= 0)
{
int iErr = errno;
int iErr = getLastSocketError();
disconnectSocket();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] DISCONNECTED SOCKET error while sending socket data, bytesSent = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesSent,iErr,strerror(iErr));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] DISCONNECTED SOCKET error while sending socket data, bytesSent = %d, error = %s\n",__FILE__,__FUNCTION__,bytesSent,getLastSocketErrorFormattedText(&iErr).c_str());
//throwException(szBuf);
}
@ -671,21 +895,21 @@ int Socket::receive(void *data, int dataSize)
{
ssize_t bytesReceived = 0;
if(sock > 0)
if(isSocketValid() == true)
{
bytesReceived = recv(sock, reinterpret_cast<char*>(data), dataSize, 0);
}
if(bytesReceived < 0 && errno != EAGAIN)
if(bytesReceived < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] ERROR READING SOCKET DATA error while sending socket data, bytesSent = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesReceived,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] ERROR READING SOCKET DATA error while sending socket data, bytesSent = %d, error = %s\n",__FILE__,__FUNCTION__,bytesReceived,getLastSocketErrorFormattedText().c_str());
//throwException(szBuf);
}
else if(bytesReceived < 0 && errno == EAGAIN)
else if(bytesReceived < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #1 EAGAIN during receive, trying again...\n",__FILE__,__FUNCTION__);
time_t tStartTimer = time(NULL);
while((bytesReceived < 0 && errno == EAGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
while((bytesReceived < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
{
if(Socket::isReadable() == true)
{
@ -698,10 +922,10 @@ int Socket::receive(void *data, int dataSize)
if(bytesReceived <= 0)
{
int iErr = errno;
int iErr = getLastSocketError();
disconnectSocket();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] DISCONNECTED SOCKET error while receiving socket data, bytesReceived = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,bytesReceived,iErr,strerror(iErr));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] DISCONNECTED SOCKET error while receiving socket data, bytesReceived = %d, error = %s\n",__FILE__,__FUNCTION__,bytesReceived,getLastSocketErrorFormattedText(&iErr).c_str());
//throwException(szBuf);
}
return static_cast<int>(bytesReceived);
@ -709,23 +933,23 @@ int Socket::receive(void *data, int dataSize)
int Socket::peek(void *data, int dataSize){
ssize_t err = 0;
if(sock > 0)
if(isSocketValid() == true)
{
err = recv(sock, reinterpret_cast<char*>(data), dataSize, MSG_PEEK);
}
if(err < 0 && errno != EAGAIN)
if(err < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] ERROR PEEKING SOCKET DATA error while sending socket data, bytesSent = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,err,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] ERROR PEEKING SOCKET DATA error while sending socket data, bytesSent = %d, error = %s\n",__FILE__,__FUNCTION__,err,getLastSocketErrorFormattedText().c_str());
//throwException(szBuf);
disconnectSocket();
}
else if(err < 0 && errno == EAGAIN)
else if(err < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #1 EAGAIN during peek, trying again...\n",__FILE__,__FUNCTION__);
time_t tStartTimer = time(NULL);
while((err < 0 && errno == EAGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
while((err < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN) && (difftime(time(NULL),tStartTimer) <= 5))
{
if(Socket::isReadable() == true)
{
@ -738,10 +962,10 @@ int Socket::peek(void *data, int dataSize){
if(err <= 0)
{
int iErr = errno;
int iErr = getLastSocketError();
disconnectSocket();
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] DISCONNECTED SOCKET error while peeking socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,err,iErr,strerror(iErr));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] DISCONNECTED SOCKET error while peeking socket data, err = %d, error = %s\n",__FILE__,__FUNCTION__,err,getLastSocketErrorFormattedText(&iErr).c_str());
//throwException(szBuf);
}
@ -752,18 +976,26 @@ void Socket::setBlock(bool block){
setBlock(block,this->sock);
}
void Socket::setBlock(bool block, int socket){
void Socket::setBlock(bool block, PLATFORM_SOCKET socket){
#ifndef WIN32
int err= fcntl(socket, F_SETFL, block ? 0 : O_NONBLOCK);
if(err<0){
#else
u_long iMode= !block;
int err= ioctlsocket(socket, FIONBIO, &iMode);
#endif
if(err < 0){
throwException("Error setting I/O mode for socket");
}
}
bool Socket::isReadable()
{
if(sock <= 0) return false;
if(isSocketValid() == false) return false;
#ifndef WIN32
struct timeval tv;
#else
TIMEVAL tv;
#endif
tv.tv_sec= 0;
tv.tv_usec= 1;
@ -779,7 +1011,7 @@ bool Socket::isReadable()
lastDebugEvent = time(NULL);
//throwException("Error selecting socket");
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] error while selecting socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,i,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] error while selecting socket data, err = %d, error = %s\n",__FILE__,__FUNCTION__,i,getLastSocketErrorFormattedText().c_str());
}
}
//return (i == 1 && FD_ISSET(sock, &set));
@ -788,9 +1020,13 @@ bool Socket::isReadable()
bool Socket::isWritable(bool waitOnDelayedResponse)
{
if(sock <= 0) return false;
if(isSocketValid() == false) return false;
#ifndef WIN32
struct timeval tv;
#else
TIMEVAL tv;
#endif
tv.tv_sec= 0;
tv.tv_usec= 1;
@ -808,7 +1044,7 @@ bool Socket::isWritable(bool waitOnDelayedResponse)
{
lastDebugEvent = time(NULL);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] error while selecting socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,i,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] error while selecting socket data, err = %d, error = %s\n",__FILE__,__FUNCTION__,i,getLastSocketErrorFormattedText().c_str());
}
waitOnDelayedResponse = false;
@ -819,7 +1055,7 @@ bool Socket::isWritable(bool waitOnDelayedResponse)
if(difftime(time(NULL),lastDebugEvent) >= 1)
{
lastDebugEvent = time(NULL);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] TIMEOUT while selecting socket data, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,i,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"[%s::%s] TIMEOUT while selecting socket data, err = %d, error = %s\n",__FILE__,__FUNCTION__,i,getLastSocketErrorFormattedText().c_str());
}
if(waitOnDelayedResponse == false)
@ -885,10 +1121,9 @@ string Socket::getIp() {
intToStr(address[3]);
}
void Socket::throwException(const string &str){
std::stringstream msg;
msg << str << " (Error: " << strerror(errno) << ")";
throw runtime_error(msg.str());
void Socket::throwException(string str){
string msg = str + " " + getLastSocketErrorFormattedText();
throw runtime_error(msg);
}
// ===============================================
@ -962,19 +1197,22 @@ void ClientSocket::connect(const Ip &ip, int port)
addr.sin_addr.s_addr= inet_addr(ip.getString().c_str());
addr.sin_port= htons(port);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Connecting to host [%s] on port = %d\n", ip.getString().c_str(),port);
int err= ::connect(sock, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr));
if(err < 0)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 Error connecting socket for IP: %s for Port: %d err = %d errno = %d [%s]\n",__FILE__,__FUNCTION__,ip.getString().c_str(),port,err,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 Error connecting socket for IP: %s for Port: %d err = %d error = %s\n",__FILE__,__FUNCTION__,ip.getString().c_str(),port,err,getLastSocketErrorFormattedText().c_str());
if (errno == EINPROGRESS)
if (getLastSocketError() == PLATFORM_SOCKET_INPROGRESS ||
getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN)
{
fd_set myset;
struct timeval tv;
int valopt;
socklen_t lon;
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] EINPROGRESS in connect() - selecting\n",__FILE__,__FUNCTION__);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] PLATFORM_SOCKET_INPROGRESS in connect() - selecting\n",__FILE__,__FUNCTION__);
do
{
@ -986,9 +1224,9 @@ void ClientSocket::connect(const Ip &ip, int port)
err = select(sock+1, NULL, &myset, NULL, &tv);
if (err < 0 && errno != EINTR)
if (err < 0 && getLastSocketError() != PLATFORM_SOCKET_INTERRUPTED)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Error connecting %d - [%s]\n",__FILE__,__FUNCTION__,errno, strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Error connecting %s\n",__FILE__,__FUNCTION__,getLastSocketErrorFormattedText().c_str());
//throwException(szBuf);
break;
}
@ -996,9 +1234,13 @@ void ClientSocket::connect(const Ip &ip, int port)
{
// Socket selected for write
lon = sizeof(int);
#ifndef WIN32
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0)
#else
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)(&valopt), &lon) < 0)
#endif
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Error in getsockopt() %d - [%s]\n",__FILE__,__FUNCTION__,errno, strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Error in getsockopt() %s\n",__FILE__,__FUNCTION__,getLastSocketErrorFormattedText().c_str());
//throwException(szBuf);
break;
}
@ -1011,7 +1253,7 @@ void ClientSocket::connect(const Ip &ip, int port)
}
errno = 0;
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Apparent recovery for connection sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Apparent recovery for connection sock = %d, err = %d\n",__FILE__,__FUNCTION__,sock,err);
break;
}
@ -1028,15 +1270,19 @@ void ClientSocket::connect(const Ip &ip, int port)
if(err < 0)
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Before END sock = %d, err = %d, errno = %d [%s]\n",__FILE__,__FUNCTION__,sock,err,errno,strerror(errno));
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Before END sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,err,getLastSocketErrorFormattedText().c_str());
//throwException(szBuf);
disconnectSocket();
}
else
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Valid recovery for connection sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Valid recovery for connection sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,err,getLastSocketErrorFormattedText().c_str());
}
}
else
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Connected to host [%s] on port = %d sock = %d err = %d", ip.getString().c_str(),port,err);
}
}
//=======================================================================
@ -1122,7 +1368,7 @@ void BroadCastClientSocketThread::execute() {
short port; // The port for the broadcast.
struct sockaddr_in bcSender; // local socket address for the broadcast.
struct sockaddr_in bcaddr; // The broadcast address for the receiver.
int bcfd; // The file descriptor used for the broadcast.
PLATFORM_SOCKET bcfd; // The file descriptor used for the broadcast.
bool one = true; // Parameter for "setscokopt".
char buff[10024]; // Buffers the data to be broadcasted.
socklen_t alen;
@ -1133,7 +1379,7 @@ void BroadCastClientSocketThread::execute() {
// Prepare to receive the broadcast.
bcfd = socket(AF_INET, SOCK_DGRAM, 0);
if( bcfd <= 0 ) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"socket failed: %d\n", errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"socket failed: %s\n", getLastSocketErrorFormattedText().c_str());
//exit(-1);
}
else {
@ -1144,10 +1390,13 @@ void BroadCastClientSocketThread::execute() {
bcaddr.sin_port = port;
int val = 1;
#ifndef WIN32
setsockopt(bcfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
#else
setsockopt(bcfd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
#endif
if(bind( bcfd, (struct sockaddr *)&bcaddr, sizeof(bcaddr) ) < 0 ) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"bind failed: %d\n", errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"bind failed: %s\n", getLastSocketErrorFormattedText().c_str());
}
else {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@ -1165,7 +1414,7 @@ void BroadCastClientSocketThread::execute() {
alen = sizeof(struct sockaddr);
if( (nb = recvfrom(bcfd, buff, 10024, 0, (struct sockaddr *) &bcSender, &alen)) <= 0 )
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"recvfrom failed: %d\n", errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"recvfrom failed: %s\n", getLastSocketErrorFormattedText().c_str());
//exit(-1);
}
else {
@ -1291,13 +1540,18 @@ void ServerSocket::bind(int port)
addr.sin_port= htons(port);
int val = 1;
#ifndef WIN32
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
#else
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
#endif
int err= ::bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
if(err < 0)
{
char szBuf[1024]="";
sprintf(szBuf, "In [%s::%s] Error binding socket sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
sprintf(szBuf, "In [%s::%s] Error binding socket sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,err,getLastSocketErrorFormattedText().c_str());
throwException(szBuf);
}
}
@ -1308,7 +1562,7 @@ void ServerSocket::listen(int connectionQueueSize)
if(err < 0)
{
char szBuf[1024]="";
sprintf(szBuf, "In [%s::%s] Error listening socket sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,err,errno);
sprintf(szBuf, "In [%s::%s] Error listening socket sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,err,getLastSocketErrorFormattedText().c_str());
throwException(szBuf);
}
@ -1325,13 +1579,13 @@ void ServerSocket::listen(int connectionQueueSize)
Socket *ServerSocket::accept()
{
int newSock= ::accept(sock, NULL, NULL);
if(newSock < 0)
PLATFORM_SOCKET newSock= ::accept(sock, NULL, NULL);
if(isSocketValid(&newSock) == false)
{
char szBuf[1024]="";
sprintf(szBuf, "In [%s::%s] Error accepting socket connection sock = %d, err = %d, errno = %d\n",__FILE__,__FUNCTION__,sock,newSock,errno);
sprintf(szBuf, "In [%s::%s] Error accepting socket connection sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,newSock,getLastSocketErrorFormattedText().c_str());
if(errno == EAGAIN)
if(getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN)
{
return NULL;
}
@ -1341,7 +1595,6 @@ Socket *ServerSocket::accept()
return new Socket(newSock);
}
BroadCastSocketThread::BroadCastSocketThread() {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@ -1418,17 +1671,14 @@ void BroadCastSocketThread::execute() {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
const int MAX_NIC_COUNT = 10;
//unsigned int tbcaddr; // The broadcast address.
short port; // The port for the broadcast.
struct sockaddr_in bcLocal[MAX_NIC_COUNT]; // local socket address for the broadcast.
//struct sockaddr_in bcaddr; // The broadcast address for the receiver.
int bcfd[MAX_NIC_COUNT]; // The socket used for the broadcast.
PLATFORM_SOCKET bcfd[MAX_NIC_COUNT]; // The socket used for the broadcast.
bool one = true; // Parameter for "setscokopt".
int pn; // The number of the packet broadcasted.
char buff[1024]; // Buffers the data to be broadcasted.
char myhostname[100]; // hostname of local machine
char subnetmask[MAX_NIC_COUNT][100]; // Subnet mask to broadcast to
//struct in_addr myaddr; // My host address in net format
struct hostent* myhostent;
char * ptr; // some transient vars
int len,i;
@ -1455,12 +1705,12 @@ void BroadCastSocketThread::execute() {
bcLocal[idx].sin_port = port; // We are letting the OS fill in the port number for the local machine.
bcfd[idx] = socket( AF_INET, SOCK_DGRAM, 0 );
if( bcfd[idx] <= 0 ) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Unable to allocate broadcast socket [%s]: %d\n", subnetmask[idx], errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Unable to allocate broadcast socket [%s]: %s\n", subnetmask[idx], getLastSocketErrorFormattedText().c_str());
//exit(-1);
}
// Mark the socket for broadcast.
else if( setsockopt( bcfd[idx], SOL_SOCKET, SO_BROADCAST, (const char *) &one, sizeof( int ) ) < 0 ) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Could not set socket to broadcast [%s]: %d\n", subnetmask[idx], errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Could not set socket to broadcast [%s]: %s\n", subnetmask[idx], getLastSocketErrorFormattedText().c_str());
//exit(-1);
}
@ -1490,7 +1740,7 @@ void BroadCastSocketThread::execute() {
//if( sendto( bcfd, buff, sizeof(buff) + 1, 0 , (struct sockaddr *)&bcaddr, sizeof(struct sockaddr_in) ) != sizeof(buff) + 1 )
if( sendto( bcfd[idx], buff, sizeof(buff) + 1, 0 , (struct sockaddr *)&bcLocal[idx], sizeof(struct sockaddr_in) ) != sizeof(buff) + 1 )
{
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Sendto error: %d\n", errno);
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"Sendto error: %s\n", getLastSocketErrorFormattedText().c_str());
//exit(-1);
}
else {
@ -1507,7 +1757,7 @@ void BroadCastSocketThread::execute() {
}
sleep( 100 ); // send out broadcast every 1 seconds
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
}
catch(const exception &ex) {
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());