From 41b602c90ff8fc4c571578bd3a5d9b21a41b131d Mon Sep 17 00:00:00 2001 From: Colby Klein Date: Wed, 24 May 2017 01:23:22 -0700 Subject: [PATCH] EzSockets: Don't leak WinAPI everywhere this gets included. Fixes #1455 --- src/NetworkSyncManager.cpp | 12 +-- src/ezsockets.cpp | 208 +++++++++++++++++++++++++++---------- src/ezsockets.h | 43 +++----- 3 files changed, 176 insertions(+), 87 deletions(-) diff --git a/src/NetworkSyncManager.cpp b/src/NetworkSyncManager.cpp index 40232aca3d..e9442eca26 100644 --- a/src/NetworkSyncManager.cpp +++ b/src/NetworkSyncManager.cpp @@ -212,7 +212,7 @@ void NetworkSyncManager::StartUp() PostStartUp( ServerIP ); BroadcastReception = new EzSockets; - BroadcastReception->create( IPPROTO_UDP ); + BroadcastReception->create( EZS_UDP ); BroadcastReception->bind( 8765 ); BroadcastReception->blocking = false; } @@ -537,7 +537,7 @@ void NetworkSyncManager::Update(float fDeltaTime) ThisServer.Name = BroadIn.ReadNT(); int port = BroadIn.Read2(); BroadIn.Read2(); //Num players connected. - uint32_t addy = EzSockets::LongFromAddrIn(BroadcastReception->fromAddr); + uint32_t addy = BroadcastReception->getAddress(); ThisServer.Address = ssprintf( "%u.%u.%u.%u:%d", (addy<<0)>>24, (addy<<8)>>24, (addy<<16)>>24, (addy<<24)>>24, port ); @@ -867,7 +867,7 @@ uint16_t PacketFunctions::Read2() uint16_t Temp; memcpy( &Temp, Data + Position,2 ); Position+=2; - return ntohs(Temp); + return EzSockets::ntohs(Temp); } uint32_t PacketFunctions::Read4() @@ -878,7 +878,7 @@ uint32_t PacketFunctions::Read4() uint32_t Temp; memcpy( &Temp, Data + Position,4 ); Position+=4; - return ntohl(Temp); + return EzSockets::ntohl(Temp); } RString PacketFunctions::ReadNT() @@ -905,7 +905,7 @@ void PacketFunctions::Write2(uint16_t data) { if (Position>=NETMAXBUFFERSIZE-1) return; - data = htons(data); + data = EzSockets::htons(data); memcpy( &Data[Position], &data, 2 ); Position+=2; } @@ -915,7 +915,7 @@ void PacketFunctions::Write4(uint32_t data) if (Position>=NETMAXBUFFERSIZE-3) return ; - data = htonl(data); + data = EzSockets::htonl(data); memcpy( &Data[Position], &data, 4 ); Position+=4; } diff --git a/src/ezsockets.cpp b/src/ezsockets.cpp index 88125b9b26..689da60c7e 100644 --- a/src/ezsockets.cpp +++ b/src/ezsockets.cpp @@ -22,6 +22,12 @@ #include #endif +#if defined(_WINDOWS) +#include +#else +#include +#endif + #if !defined(SOCKET_ERROR) #define SOCKET_ERROR -1 #endif @@ -44,62 +50,131 @@ inline timeval timevalFromMs(unsigned int ms) return tv; } +namespace +{ + struct ezs_internal + { + // Only necessary for Windows +#if defined(_WINDOWS) + WSADATA wsda; +#endif + + int MAXCON; + int sock; + struct sockaddr_in addr; + + struct sockaddr_in fromAddr; + unsigned long fromAddr_len; + + // Used for Select() command + fd_set *scks; + timeval *times; + + ezs_internal() + { + MAXCON = 5; + memset (&addr,0,sizeof(addr)); //Clear the sockaddr_in structure + +#if defined(_WINDOWS) // Windows REQUIRES WinSock Startup + WSAStartup( MAKEWORD(1,1), &wsda ); +#endif + + scks = new fd_set; + times = new timeval; + } + ~ezs_internal() + { + delete scks; + delete times; + } + }; +} + +uint32_t EzSockets::ntohl(uint32_t in) +{ + return ::ntohl(in); +} + +uint16_t EzSockets::ntohs(uint16_t in) +{ + return ::ntohs(in); +} + +uint32_t EzSockets::htonl(uint32_t in) +{ + return ::htonl(in); +} + +uint16_t EzSockets::htons(uint16_t in) { + return ::htons(in); +} EzSockets::EzSockets() { - MAXCON = 5; - memset (&addr,0,sizeof(addr)); //Clear the sockaddr_in structure + ezs_internal *data = new ezs_internal(); + this->opaque = (void*)data; -#if defined(_WINDOWS) // Windows REQUIRES WinSock Startup - WSAStartup( MAKEWORD(1,1), &wsda ); -#endif - - sock = INVALID_SOCKET; blocking = true; - scks = new fd_set; - times = new timeval; - times->tv_sec = 0; - times->tv_usec = 0; + data->sock = INVALID_SOCKET; + data->times->tv_sec = 0; + data->times->tv_usec = 0; state = skDISCONNECTED; } EzSockets::~EzSockets() { close(); - delete scks; - delete times; + + ezs_internal *data = (ezs_internal*)(this->opaque); + delete data; } //Check to see if the socket has been created bool EzSockets::check() { - return sock > SOCKET_NONE; + ezs_internal *data = (ezs_internal*)(this->opaque); + return data->sock > SOCKET_NONE; } bool EzSockets::create() { - return create(IPPROTO_TCP, SOCK_STREAM); + return create(EZS_TCP, SOCK_STREAM); } -bool EzSockets::create(int Protocol) +bool EzSockets::create(EzSockets_Proto Protocol) { switch(Protocol) { - case IPPROTO_TCP: - return create(IPPROTO_TCP, SOCK_STREAM); - case IPPROTO_UDP: - return create(IPPROTO_UDP, SOCK_DGRAM); + case EZS_TCP: + return create(EZS_TCP, SOCK_STREAM); + case EZS_UDP: + return create(EZS_UDP, SOCK_DGRAM); default: return create(Protocol, SOCK_RAW); } } -bool EzSockets::create(int Protocol, int Type) +bool EzSockets::create(EzSockets_Proto Protocol, int Type) { + ezs_internal *data = (ezs_internal*)(this->opaque); state = skDISCONNECTED; - sock = socket(AF_INET, Type, Protocol); - lastCode = sock; - return sock > SOCKET_NONE; // Socket must be Greater than 0 + + int realproto = 0; + switch (Protocol) { + case EZS_TCP: + realproto = IPPROTO_TCP; + break; + case EZS_UDP: + realproto = IPPROTO_UDP; + break; + case EZS_NONE: + realproto = IPPROTO_IP; + break; + } + + data->sock = socket(AF_INET, Type, realproto); + lastCode = data->sock; + return data->sock > SOCKET_NONE; // Socket must be Greater than 0 } bool EzSockets::bind(unsigned short port) @@ -107,16 +182,18 @@ bool EzSockets::bind(unsigned short port) if(!check()) return false; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(port); - lastCode = ::bind(sock,(struct sockaddr*)&addr, sizeof(addr)); + ezs_internal *data = (ezs_internal*)(this->opaque); + data->addr.sin_family = AF_INET; + data->addr.sin_addr.s_addr = htonl(INADDR_ANY); + data->addr.sin_port = htons(port); + lastCode = ::bind(data->sock,(struct sockaddr*)&data->addr, sizeof(data->addr)); return !lastCode; } bool EzSockets::listen() { - lastCode = ::listen(sock, MAXCON); + ezs_internal *data = (ezs_internal*)(this->opaque); + lastCode = ::listen(data->sock, data->MAXCON); if (lastCode == SOCKET_ERROR) return false; @@ -145,12 +222,14 @@ bool EzSockets::accept(EzSockets& socket) int length = sizeof(socket); - socket.sock = ::accept(sock,(struct sockaddr*) &socket.addr, + ezs_internal *data = (ezs_internal*)(this->opaque); + ezs_internal *sdata = (ezs_internal*)(socket.opaque); + sdata->sock = ::accept(data->sock,(struct sockaddr*) &sdata->addr, (socklen_t*) &length); - lastCode = socket.sock; + lastCode = sdata->sock; - if ( socket.sock == SOCKET_ERROR ) + if ( sdata->sock == SOCKET_ERROR ) return false; socket.state = skCONNECTED; @@ -163,35 +242,44 @@ void EzSockets::close() inBuffer = ""; outBuffer = ""; + ezs_internal *data = (ezs_internal*)(this->opaque); #if defined(WIN32) // The close socket command is different in Windows - ::closesocket(sock); + ::closesocket(data->sock); #else - ::close(sock); + ::close(data->sock); #endif } long EzSockets::uAddr() { - return addr.sin_addr.s_addr; + ezs_internal *data = (ezs_internal*)(this->opaque); + return data->addr.sin_addr.s_addr; } - bool EzSockets::connect(const std::string& host, unsigned short port) { - if(!check()) + if (!check()) + { return false; + } struct hostent* phe; phe = gethostbyname(host.c_str()); if (phe == NULL) + { return false; - memcpy(&addr.sin_addr, phe->h_addr, sizeof(struct in_addr)); + } - addr.sin_family = AF_INET; - addr.sin_port = htons(port); + ezs_internal *data = (ezs_internal*)(this->opaque); + memcpy(&data->addr.sin_addr, phe->h_addr, sizeof(struct in_addr)); - if(::connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) + data->addr.sin_family = AF_INET; + data->addr.sin_port = htons(port); + + if(::connect(data->sock, (struct sockaddr*)&data->addr, sizeof(data->addr)) == SOCKET_ERROR) + { return false; + } state = skCONNECTED; return true; @@ -208,13 +296,15 @@ inline bool checkCanRead(int sock, timeval& timeout) bool EzSockets::CanRead() { - return checkCanRead(sock, *times); + ezs_internal *data = (ezs_internal*)(this->opaque); + return checkCanRead(data->sock, *data->times); } bool EzSockets::CanRead(unsigned int msTimeout) { + ezs_internal *data = (ezs_internal*)(this->opaque); timeval tv = timevalFromMs(msTimeout); - return checkCanRead(sock, tv); + return checkCanRead(data->sock, tv); } bool EzSockets::IsError() @@ -222,10 +312,11 @@ bool EzSockets::IsError() if (state == skERROR) return true; - FD_ZERO(scks); - FD_SET((unsigned)sock, scks); + ezs_internal *data = (ezs_internal*)(this->opaque); + FD_ZERO(data->scks); + FD_SET((unsigned)data->sock, data->scks); - if (select(sock+1, NULL, NULL, scks, times) >=0 ) + if (select(data->sock+1, NULL, NULL, data->scks, data->times) >=0 ) return false; state = skERROR; @@ -243,13 +334,15 @@ inline bool checkCanWrite(int sock, timeval& timeout) bool EzSockets::CanWrite() { - return checkCanWrite(sock, *times); + ezs_internal *data = (ezs_internal*)(this->opaque); + return checkCanWrite(data->sock, *data->times); } bool EzSockets::CanWrite(unsigned int msTimeout) { + ezs_internal *data = (ezs_internal*)(this->opaque); timeval tv = timevalFromMs(msTimeout); - return checkCanWrite(sock, tv); + return checkCanWrite(data->sock, tv); } void EzSockets::update() @@ -265,8 +358,11 @@ void EzSockets::update() pUpdateWrite(); } -unsigned long EzSockets::LongFromAddrIn( const sockaddr_in & s ) +uint32_t EzSockets::getAddress() { + ezs_internal *data = (ezs_internal*)(this->opaque); + sockaddr_in &s = data->fromAddr; + #if defined(_WINDOWS) return ntohl(s.sin_addr.S_un.S_addr); #else @@ -475,17 +571,19 @@ int EzSockets::pUpdateWrite() int EzSockets::pReadData(char* data) { - if(state == skCONNECTED || state == skLISTENING) - return recv(sock, data, 1024, 0); + ezs_internal *sdata = (ezs_internal*)(this->opaque); + if (state == skCONNECTED || state == skLISTENING) + return recv(sdata->sock, data, 1024, 0); - fromAddr_len = sizeof(sockaddr_in); - return recvfrom(sock, data, 1024, 0, (sockaddr*)&fromAddr, - (socklen_t*)&fromAddr_len); + sdata->fromAddr_len = sizeof(sockaddr_in); + return recvfrom(sdata->sock, data, 1024, 0, (sockaddr*)&sdata->fromAddr, + (socklen_t*)&sdata->fromAddr_len); } int EzSockets::pWriteData(const char* data, int dataSize) { - return send(sock, data, dataSize, 0); + ezs_internal *sdata = (ezs_internal*)(this->opaque); + return send(sdata->sock, data, dataSize, 0); } /* diff --git a/src/ezsockets.h b/src/ezsockets.h index 4a7c8b6b9c..a2aa1b26db 100644 --- a/src/ezsockets.h +++ b/src/ezsockets.h @@ -21,14 +21,15 @@ #endif #include -#if defined(_WINDOWS) -#include -#else -#include -#endif - using namespace std; +enum EzSockets_Proto +{ + EZS_NONE, + EZS_TCP, + EZS_UDP +}; + class EzSockets { public: @@ -38,8 +39,8 @@ public: //Crate the socket bool create(); - bool create(int Protocol); - bool create(int Protocol, int Type); + bool create(EzSockets_Proto Protocol); + bool create(EzSockets_Proto Protocol, int Type); //Bind Socket to local port bool bind(unsigned short port); @@ -107,9 +108,7 @@ public: skERROR }; - struct sockaddr_in fromAddr; - unsigned long fromAddr_len; - static unsigned long LongFromAddrIn( const sockaddr_in & s ); + uint32_t getAddress(); // The following possibly should be private. string inBuffer; @@ -127,23 +126,15 @@ public: RString address; + // Wrapped here so we don't have to leak winapi everywhere... + static uint32_t ntohl(uint32_t); + static uint16_t ntohs(uint16_t); + static uint32_t htonl(uint32_t); + static uint16_t htons(uint16_t); + private: - // Only necessary for Windows -#if defined(_WINDOWS) - WSADATA wsda; -#endif - - int MAXCON; - int sock; - struct sockaddr_in addr; - - - // Used for Select() command - fd_set *scks; - timeval *times; - - // Buffers + void *opaque; }; istream& operator>>(istream& is, EzSockets& obj);