1 // ============================================================== 2 // This file is part of Glest Shared Library (www.glest.org) 3 // 4 // Copyright (C) 2005 Matthias Braun <matze@braunis.de> 5 // 6 // You can redistribute this code and/or modify it under 7 // the terms of the GNU General Public License as published 8 // by the Free Software Foundation; either version 2 of the 9 // License, or (at your option) any later version 10 // ============================================================== 11 12 #ifndef _SHARED_PLATFORM_SOCKET_H_ 13 #define _SHARED_PLATFORM_SOCKET_H_ 14 15 #ifdef WIN32 16 #ifdef __MINGW32__ 17 #include <winsock2.h> 18 #else 19 #include <winsock2.h> 20 #include <winsock.h> 21 #endif 22 23 typedef SOCKET PLATFORM_SOCKET; 24 #if defined(_WIN64) 25 #define PLATFORM_SOCKET_FORMAT_TYPE MG_I64U_SPECIFIER 26 #else 27 #define PLATFORM_SOCKET_FORMAT_TYPE "%d" 28 #endif 29 #else 30 #include <unistd.h> 31 #include <sys/socket.h> 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 #include <netdb.h> 35 36 typedef int PLATFORM_SOCKET; 37 #define PLATFORM_SOCKET_FORMAT_TYPE "%d" 38 #endif 39 40 #include <string> 41 #include <errno.h> 42 #include <sys/types.h> 43 #include <fcntl.h> 44 #include <map> 45 #include <vector> 46 #include "base_thread.h" 47 #include "simple_threads.h" 48 #include "data_types.h" 49 50 using std::string; 51 52 #include "leak_dumper.h" 53 54 using namespace Shared::PlatformCommon; 55 56 namespace Shared { namespace Platform { 57 58 #ifdef WIN32 59 60 #define PLATFORM_SOCKET_TRY_AGAIN WSAEWOULDBLOCK 61 #define PLATFORM_SOCKET_INPROGRESS WSAEINPROGRESS 62 #define PLATFORM_SOCKET_INTERRUPTED WSAEWOULDBLOCK 63 64 #else 65 66 #define PLATFORM_SOCKET_TRY_AGAIN EAGAIN 67 #define PLATFORM_SOCKET_INPROGRESS EINPROGRESS 68 #define PLATFORM_SOCKET_INTERRUPTED EINTR 69 70 #endif 71 72 // The callback Interface used by the UPNP discovery process 73 class FTPClientValidationInterface { 74 public: 75 virtual int isValidClientType(uint32 clientIp) = 0; 76 virtual int isClientAllowedToGetFile(uint32 clientIp, const char *username, const char *filename) = 0; 77 ~FTPClientValidationInterface()78 virtual ~FTPClientValidationInterface() {} 79 }; 80 81 82 // The callback Interface used by the UPNP discovery process 83 class UPNPInitInterface { 84 public: 85 virtual void UPNPInitStatus(bool result) = 0; 86 ~UPNPInitInterface()87 virtual ~UPNPInitInterface() {} 88 }; 89 90 // 91 // This interface describes the methods a callback object must implement 92 // when signaled with detected servers 93 // 94 class DiscoveredServersInterface { 95 public: 96 virtual void DiscoveredServers(std::vector<string> serverList) = 0; ~DiscoveredServersInterface()97 virtual ~DiscoveredServersInterface() {} 98 }; 99 100 // ===================================================== 101 // class IP 102 // ===================================================== 103 class Ip { 104 private: 105 unsigned char bytes[4]; 106 107 public: 108 Ip(); 109 Ip(unsigned char byte0, unsigned char byte1, unsigned char byte2, unsigned char byte3); 110 Ip(const string& ipString); 111 static void Inet_NtoA(uint32 addr, char * ipbuf); 112 getByte(int byteIndex)113 unsigned char getByte(int byteIndex) {return bytes[byteIndex];} 114 string getString() const; 115 }; 116 117 // ===================================================== 118 // class Socket 119 // ===================================================== 120 121 #ifdef WIN32 122 class SocketManager{ 123 public: 124 SocketManager(); 125 ~SocketManager(); 126 }; 127 #endif 128 129 class Socket { 130 131 protected: 132 //#ifdef WIN32 133 //static SocketManager wsaManager; 134 //#endif 135 PLATFORM_SOCKET sock; 136 time_t lastDebugEvent; 137 static int broadcast_portno; 138 std::string ipAddress; 139 std::string connectedIpAddress; 140 141 //SimpleTaskThread *pingThread; 142 std::map<string,double> pingCache; 143 time_t lastThreadedPing; 144 //Mutex pingThreadAccessor; 145 146 Mutex *dataSynchAccessorRead; 147 Mutex *dataSynchAccessorWrite; 148 149 Mutex *inSocketDestructorSynchAccessor; 150 bool inSocketDestructor; 151 152 bool isSocketBlocking; 153 time_t lastSocketError; 154 155 static string host_name; 156 static std::vector<string> intfTypes; 157 158 public: 159 Socket(PLATFORM_SOCKET sock); 160 Socket(); 161 virtual ~Socket(); 162 163 static int getLastSocketError(); 164 static const char * getLastSocketErrorText(int *errNumber=NULL); 165 static string getLastSocketErrorFormattedText(int *errNumber=NULL); 166 setIntfTypes(std::vector<string> intfTypes)167 static void setIntfTypes(std::vector<string> intfTypes) { Socket::intfTypes = intfTypes; } 168 static bool disableNagle; 169 static int DEFAULT_SOCKET_SENDBUF_SIZE; 170 static int DEFAULT_SOCKET_RECVBUF_SIZE; 171 getBroadCastPort()172 static int getBroadCastPort() { return broadcast_portno; } setBroadCastPort(int value)173 static void setBroadCastPort(int value) { broadcast_portno = value; } 174 static std::vector<std::string> getLocalIPAddressList(); 175 176 // Int lookup is socket fd while bool result is whether or not that socket was signalled for reading 177 static bool hasDataToRead(std::map<PLATFORM_SOCKET,bool> &socketTriggeredList); 178 static bool hasDataToRead(PLATFORM_SOCKET socket); 179 bool hasDataToRead(); 180 181 static bool hasDataToReadWithWait(PLATFORM_SOCKET socket,int waitMicroseconds); 182 bool hasDataToReadWithWait(int waitMicroseconds); 183 184 virtual void disconnectSocket(); 185 getSocketId()186 PLATFORM_SOCKET getSocketId() const { return sock; } 187 188 int getDataToRead(bool wantImmediateReply=false); 189 int send(const void *data, int dataSize); 190 int receive(void *data, int dataSize, bool tryReceiveUntilDataSizeMet); 191 int peek(void *data, int dataSize, bool mustGetData=true,int *pLastSocketError=NULL); 192 193 void setBlock(bool block); 194 static void setBlock(bool block, PLATFORM_SOCKET socket); 195 bool getBlock(); 196 197 bool isReadable(bool lockMutex=false); 198 bool isWritable(struct timeval *timeVal=NULL,bool lockMutex=false); 199 bool isConnected(); 200 201 static string getHostName(); 202 static string getIp(); 203 bool isSocketValid() const; 204 static bool isSocketValid(const PLATFORM_SOCKET *validateSocket); 205 206 static double getAveragePingMS(std::string host, int pingCount=5); 207 float getThreadedPingMS(std::string host); 208 209 virtual std::string getIpAddress(); setIpAddress(std::string value)210 virtual void setIpAddress(std::string value) { ipAddress = value; } 211 212 uint32 getConnectedIPAddress(string IP=""); 213 214 protected: 215 static void throwException(string str); 216 }; 217 218 class SafeSocketBlockToggleWrapper { 219 protected: 220 Socket *socket; 221 bool originallyBlocked; 222 bool newBlocked; 223 public: 224 SafeSocketBlockToggleWrapper(Socket *socket, bool toggle); 225 ~SafeSocketBlockToggleWrapper(); 226 void Restore(); 227 }; 228 229 class BroadCastClientSocketThread : public BaseThread 230 { 231 private: 232 DiscoveredServersInterface *discoveredServersCB; 233 234 public: 235 BroadCastClientSocketThread(DiscoveredServersInterface *cb); 236 virtual void execute(); 237 }; 238 239 // ===================================================== 240 // class ClientSocket 241 // ===================================================== 242 class ClientSocket: public Socket { 243 public: 244 ClientSocket(); 245 virtual ~ClientSocket(); 246 247 void connect(const Ip &ip, int port); 248 static void discoverServers(DiscoveredServersInterface *cb); 249 250 static void stopBroadCastClientThread(); 251 252 protected: 253 254 static BroadCastClientSocketThread *broadCastClientThread; 255 static void startBroadCastClientThread(DiscoveredServersInterface *cb); 256 }; 257 258 class BroadCastSocketThread : public BaseThread 259 { 260 private: 261 Mutex *mutexPauseBroadcast; 262 bool pauseBroadcast; 263 int boundPort; 264 265 public: 266 BroadCastSocketThread(int boundPort); 267 virtual ~BroadCastSocketThread(); 268 virtual void execute(); 269 virtual bool canShutdown(bool deleteSelfIfShutdownDelayed=false); 270 271 bool getPauseBroadcast(); 272 void setPauseBroadcast(bool value); 273 }; 274 275 // ===================================================== 276 // class ServerSocket 277 // ===================================================== 278 class ServerSocket: public Socket, public UPNPInitInterface { 279 protected: 280 281 bool portBound; 282 int boundPort; 283 string bindSpecificAddress; 284 285 static int externalPort; 286 static int ftpServerPort; 287 288 static int maxPlayerCount; 289 290 virtual void UPNPInitStatus(bool result); 291 BroadCastSocketThread *broadCastThread; 292 void startBroadCastThread(); 293 void resumeBroadcast(); 294 bool isBroadCastThreadRunning(); 295 vector<string> blockIPList; 296 297 bool basicMode; 298 299 public: 300 ServerSocket(bool basicMode = false); 301 virtual ~ServerSocket(); 302 void bind(int port); 303 void listen(int connectionQueueSize= SOMAXCONN); 304 Socket *accept(bool errorOnFail=true); 305 void stopBroadCastThread(); 306 void pauseBroadcast(); 307 308 309 void addIPAddressToBlockedList(string value); 310 bool isIPAddressBlocked(string value) const; 311 void removeBlockedIPAddress(string value); 312 void clearBlockedIPAddress(); 313 bool hasBlockedIPAddresses() const; 314 setBindPort(int port)315 void setBindPort(int port) { boundPort = port; } getBindPort()316 int getBindPort() const { return boundPort; } isPortBound()317 bool isPortBound() const { return portBound; } 318 setBindSpecificAddress(string value)319 void setBindSpecificAddress(string value) { bindSpecificAddress = value;} 320 setExternalPort(int port)321 static void setExternalPort(int port) { externalPort = port; } getExternalPort()322 static int getExternalPort() { return externalPort; } 323 setFTPServerPort(int port)324 static void setFTPServerPort(int port) { ftpServerPort = port; } getFTPServerPort()325 static int getFTPServerPort() { return ftpServerPort; } 326 327 virtual void disconnectSocket(); 328 329 void NETdiscoverUPnPDevices(); 330 setMaxPlayerCount(int value)331 static void setMaxPlayerCount(int value) { maxPlayerCount=value; } 332 333 static Mutex mutexUpnpdiscoverThread; 334 static SDL_Thread *upnpdiscoverThread; 335 static bool cancelUpnpdiscoverThread; 336 }; 337 338 // ===================================================== 339 // class UPNP_Tools 340 // ===================================================== 341 class UPNP_Tools { 342 343 public: 344 345 static bool isUPNP; 346 static bool enabledUPNP; 347 static Mutex mutexUPNP; 348 349 static int upnp_init(void *param); 350 351 static bool upnp_add_redirect(int ports[2],bool mutexLock=true); 352 static void upnp_rem_redirect(int ext_port); 353 354 static void NETaddRedirects(std::vector<int> UPNPPortForwardList, bool mutexLock=true); 355 static void NETremRedirects(int ext_port); 356 357 static void AddUPNPPortForward(int internalPort, int externalPort); 358 static void RemoveUPNPPortForward(int internalPort, int externalPort); 359 }; 360 361 }}//end namespace 362 363 #endif 364