diff --git a/source/shared_lib/include/platform/posix/socket.h b/source/shared_lib/include/platform/posix/socket.h index 3dab6f68..dd554b60 100644 --- a/source/shared_lib/include/platform/posix/socket.h +++ b/source/shared_lib/include/platform/posix/socket.h @@ -28,11 +28,22 @@ using std::string; +#ifdef WIN32 + #include + 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 getLocalIPAddressList(); // Int lookup is socket fd while bool result is whether or not that socket was signalled for reading - static bool hasDataToRead(std::map &socketTriggeredList); - static bool hasDataToRead(int socket); + static bool hasDataToRead(std::map &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(); diff --git a/source/shared_lib/sources/platform/posix/socket.cpp b/source/shared_lib/sources/platform/posix/socket.cpp index b7dfaaf7..842b784d 100644 --- a/source/shared_lib/sources/platform/posix/socket.cpp +++ b/source/shared_lib/sources/platform/posix/socket.cpp @@ -12,13 +12,14 @@ #include #include #include -#include +//#include + #if defined(HAVE_SYS_IOCTL_H) -#define BSD_COMP /* needed for FIONREAD on Solaris2 */ -#include + #define BSD_COMP /* needed for FIONREAD on Solaris2 */ + #include #endif -#if defined(HAVE_SYS_FILIO_H) /* needed for FIONREAD on Solaris 2.5 */ -#include + #if defined(HAVE_SYS_FILIO_H) /* needed for FIONREAD on Solaris 2.5 */ + #include #endif #include @@ -29,30 +30,223 @@ #include #ifdef WIN32 -# include -# include -# include + + #include + #include + #include + //#include + #else -# include -# include -# include -# include -# include -# include -# include + + #include + #include + #include + #include + #include + //#include + //#include + #endif #include #include +#include + +#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 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 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 &socketTriggeredList) +bool Socket::hasDataToRead(std::map &socketTriggeredList) { bool bResult = false; @@ -501,11 +722,11 @@ bool Socket::hasDataToRead(std::map &socketTriggeredList) fd_set rfds; FD_ZERO(&rfds); - int imaxsocket = 0; - for(std::map::iterator itermap = socketTriggeredList.begin(); + PLATFORM_SOCKET imaxsocket = 0; + for(std::map::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 &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 &socketTriggeredList) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] select detected data imaxsocket = %d...\n",__FILE__,__FUNCTION__,imaxsocket); - for(std::map::iterator itermap = socketTriggeredList.begin(); + for(std::map::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(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(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(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(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(&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(&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());