Files
2019-01-31 02:40:31 +01:00

406 lines
10 KiB
C++

// This file is part of Glest <https://github.com/Glest>
//
// Copyright (C) 2018 The Glest team
//
// Glest is a fork of MegaGlest <https://megaglest.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
#ifndef _SHARED_PLATFORM_SOCKET_H_
#define _SHARED_PLATFORM_SOCKET_H_
#ifdef WIN32
#ifdef __MINGW32__
#include <winsock2.h>
#else
#include <winsock2.h>
#include <winsock.h>
#endif
typedef SOCKET PLATFORM_SOCKET;
#if defined(_WIN64)
#define PLATFORM_SOCKET_FORMAT_TYPE I64U_SPECIFIER
#else
#define PLATFORM_SOCKET_FORMAT_TYPE "%d"
#endif
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
typedef int PLATFORM_SOCKET;
#define PLATFORM_SOCKET_FORMAT_TYPE "%d"
#endif
#include <string>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <map>
#include <vector>
#include "base_thread.h"
#include "simple_threads.h"
#include "data_types.h"
using std::string;
#include "leak_dumper.h"
using namespace Shared::PlatformCommon;
namespace Shared {
namespace Platform {
#ifdef WIN32
#define PLATFORM_SOCKET_TRY_AGAIN WSAEWOULDBLOCK
#define PLATFORM_SOCKET_INPROGRESS WSAEINPROGRESS
#define PLATFORM_SOCKET_INTERRUPTED WSAEWOULDBLOCK
#else
#define PLATFORM_SOCKET_TRY_AGAIN EAGAIN
#define PLATFORM_SOCKET_INPROGRESS EINPROGRESS
#define PLATFORM_SOCKET_INTERRUPTED EINTR
#endif
// The callback Interface used by the UPNP discovery process
class FTPClientValidationInterface {
public:
virtual int isValidClientType(uint32 clientIp) = 0;
virtual int isClientAllowedToGetFile(uint32 clientIp, const char *username, const char *filename) = 0;
virtual ~FTPClientValidationInterface() {
}
};
// The callback Interface used by the UPNP discovery process
class UPNPInitInterface {
public:
virtual void UPNPInitStatus(bool result) = 0;
virtual ~UPNPInitInterface() {
}
};
//
// This interface describes the methods a callback object must implement
// when signaled with detected servers
//
class DiscoveredServersInterface {
public:
virtual void DiscoveredServers(std::vector<string> serverList) = 0;
virtual ~DiscoveredServersInterface() {
}
};
// =====================================================
// class IP
// =====================================================
class Ip {
private:
unsigned char bytes[4];
public:
Ip();
Ip(unsigned char byte0, unsigned char byte1, unsigned char byte2, unsigned char byte3);
Ip(const string& ipString);
static void Inet_NtoA(uint32 addr, char * ipbuf);
unsigned char getByte(int byteIndex) {
return bytes[byteIndex];
}
string getString() const;
};
// =====================================================
// class Socket
// =====================================================
#ifdef WIN32
class SocketManager {
public:
SocketManager();
~SocketManager();
};
#endif
class Socket {
protected:
//#ifdef WIN32
//static SocketManager wsaManager;
//#endif
PLATFORM_SOCKET sock;
time_t lastDebugEvent;
static int broadcast_portno;
std::string ipAddress;
std::string connectedIpAddress;
//SimpleTaskThread *pingThread;
std::map<string, double> pingCache;
time_t lastThreadedPing;
//Mutex pingThreadAccessor;
Mutex *dataSynchAccessorRead;
Mutex *dataSynchAccessorWrite;
Mutex *inSocketDestructorSynchAccessor;
bool inSocketDestructor;
bool isSocketBlocking;
time_t lastSocketError;
static string host_name;
static std::vector<string> intfTypes;
public:
Socket(PLATFORM_SOCKET sock);
Socket();
virtual ~Socket();
static int getLastSocketError();
static const char * getLastSocketErrorText(int *errNumber = NULL);
static string getLastSocketErrorFormattedText(int *errNumber = NULL);
static void setIntfTypes(std::vector<string> intfTypes) {
Socket::intfTypes = intfTypes;
}
static bool disableNagle;
static int DEFAULT_SOCKET_SENDBUF_SIZE;
static int DEFAULT_SOCKET_RECVBUF_SIZE;
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<PLATFORM_SOCKET, bool> &socketTriggeredList);
static bool hasDataToRead(PLATFORM_SOCKET socket);
bool hasDataToRead();
static bool hasDataToReadWithWait(PLATFORM_SOCKET socket, int waitMicroseconds);
bool hasDataToReadWithWait(int waitMicroseconds);
virtual void disconnectSocket();
PLATFORM_SOCKET getSocketId() const {
return sock;
}
int getDataToRead(bool wantImmediateReply = false);
int send(const void *data, int dataSize);
int receive(void *data, int dataSize, bool tryReceiveUntilDataSizeMet);
int peek(void *data, int dataSize, bool mustGetData = true, int *pLastSocketError = NULL);
void setBlock(bool block);
static void setBlock(bool block, PLATFORM_SOCKET socket);
bool getBlock();
bool isReadable(bool lockMutex = false);
bool isWritable(struct timeval *timeVal = NULL, bool lockMutex = false);
bool isConnected();
static string getHostName();
static string getIp();
bool isSocketValid() const;
static bool isSocketValid(const PLATFORM_SOCKET *validateSocket);
static double getAveragePingMS(std::string host, int pingCount = 5);
float getThreadedPingMS(std::string host);
virtual std::string getIpAddress();
virtual void setIpAddress(std::string value) {
ipAddress = value;
}
uint32 getConnectedIPAddress(string IP = "");
protected:
static void throwException(string str);
static void getLocalIPAddressListForPlatform(std::vector<std::string> &ipList);
};
class SafeSocketBlockToggleWrapper {
protected:
Socket *socket;
bool originallyBlocked;
bool newBlocked;
public:
SafeSocketBlockToggleWrapper(Socket *socket, bool toggle);
~SafeSocketBlockToggleWrapper();
void Restore();
};
class BroadCastClientSocketThread : public BaseThread {
private:
DiscoveredServersInterface *discoveredServersCB;
public:
BroadCastClientSocketThread(DiscoveredServersInterface *cb);
virtual void execute();
};
// =====================================================
// class ClientSocket
// =====================================================
class ClientSocket : public Socket {
public:
ClientSocket();
virtual ~ClientSocket();
void connect(const Ip &ip, int port);
static void discoverServers(DiscoveredServersInterface *cb);
static void stopBroadCastClientThread();
protected:
static BroadCastClientSocketThread *broadCastClientThread;
static void startBroadCastClientThread(DiscoveredServersInterface *cb);
};
class BroadCastSocketThread : public BaseThread {
private:
Mutex *mutexPauseBroadcast;
bool pauseBroadcast;
int boundPort;
public:
BroadCastSocketThread(int boundPort);
virtual ~BroadCastSocketThread();
virtual void execute();
virtual bool canShutdown(bool deleteSelfIfShutdownDelayed = false);
bool getPauseBroadcast();
void setPauseBroadcast(bool value);
};
// =====================================================
// class ServerSocket
// =====================================================
class ServerSocket : public Socket, public UPNPInitInterface {
protected:
bool portBound;
int boundPort;
string bindSpecificAddress;
static int externalPort;
static int ftpServerPort;
static int maxPlayerCount;
virtual void UPNPInitStatus(bool result);
BroadCastSocketThread *broadCastThread;
void startBroadCastThread();
void resumeBroadcast();
bool isBroadCastThreadRunning();
vector<string> blockIPList;
bool basicMode;
public:
ServerSocket(bool basicMode = false);
virtual ~ServerSocket();
void bind(int port);
void listen(int connectionQueueSize = SOMAXCONN);
Socket *accept(bool errorOnFail = true);
void stopBroadCastThread();
void pauseBroadcast();
void addIPAddressToBlockedList(string value);
bool isIPAddressBlocked(string value) const;
void removeBlockedIPAddress(string value);
void clearBlockedIPAddress();
bool hasBlockedIPAddresses() const;
void setBindPort(int port) {
boundPort = port;
}
int getBindPort() const {
return boundPort;
}
bool isPortBound() const {
return portBound;
}
void setBindSpecificAddress(string value) {
bindSpecificAddress = value;
}
static void setExternalPort(int port) {
externalPort = port;
}
static int getExternalPort() {
return externalPort;
}
static void setFTPServerPort(int port) {
ftpServerPort = port;
}
static int getFTPServerPort() {
return ftpServerPort;
}
virtual void disconnectSocket();
void NETdiscoverUPnPDevices();
static void setMaxPlayerCount(int value) {
maxPlayerCount = value;
}
static Mutex mutexUpnpdiscoverThread;
static SDL_Thread *upnpdiscoverThread;
static bool cancelUpnpdiscoverThread;
};
// =====================================================
// class UPNP_Tools
// =====================================================
class UPNP_Tools {
public:
static bool isUPNP;
static bool enabledUPNP;
static Mutex mutexUPNP;
static int upnp_init(void *param);
static bool upnp_add_redirect(int ports[2], bool mutexLock = true);
static void upnp_rem_redirect(int ext_port);
static void NETaddRedirects(std::vector<int> UPNPPortForwardList, bool mutexLock = true);
static void NETremRedirects(int ext_port);
static void AddUPNPPortForward(int internalPort, int externalPort);
static void RemoveUPNPPortForward(int internalPort, int externalPort);
};
}
} //end namespace
#endif