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