1 /***************************************************************************
2  *      Mechanized Assault and Exploration Reloaded Projectfile            *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18  ***************************************************************************/
19 #ifndef networkH
20 #define networkH
21 #include <SDL_net.h>
22 #include <string>
23 #include <memory>
24 #include "defines.h"
25 #include "utility/thread/mutex.h"
26 
27 class cNetMessage;
28 
29 #define MAX_CLIENTS     10   // maximal number of clients that can connect to the server
30 #define PACKAGE_LENGTH  1024 // maximal length of a TCP/IP package
31 #define START_CHAR      ('\xFF') // start character in netmessages
32 
33 // the first client message must be smaller then the first menu message!
34 #define FIRST_SERVER_MESSAGE 10
35 #define FIRST_CLIENT_MESSAGE 100
36 #define FIRST_MENU_MESSAGE   1000
37 
38 /**
39 * Callback for the networkthread
40 *@author alzi alias DoctorDeath
41 */
42 int CallbackHandleNetworkThread (void* arg);
43 
44 enum SOCKET_TYPES
45 {
46 	FREE_SOCKET,
47 	SERVER_SOCKET,
48 	CLIENT_SOCKET
49 };
50 
51 enum SOCKET_STATES
52 {
53 	STATE_UNUSED,
54 	STATE_READY,
55 	STATE_NEW,
56 	STATE_DYING,
57 	STATE_DELETE
58 };
59 
60 //------------------------------------------------------------------------
61 /**
62 * Structure with data and its length.
63 *@author alzi alias DoctorDeath
64 */
65 struct sDataBuffer
66 {
67 	uint32_t iLength;
68 	char data[5 * PACKAGE_LENGTH];
69 
70 	char* getWritePointer();
71 	int getFreeSpace() const;
72 	void deleteFront (int n);
73 
74 	/**
75 	* Clears the data buffer and sets his length to 0.
76 	*@author alzi alias DoctorDeath
77 	*/
78 	void clear();
79 };
80 
81 //------------------------------------------------------------------------
82 /**
83 * Structure for Sockets used by the TCP-Class.
84 *@author alzi alias DoctorDeath
85 */
86 struct sSocket
87 {
88 	sSocket();
89 	~sSocket();
90 
91 	int iType;
92 	int iState;
93 
94 	TCPsocket socket;
95 	sDataBuffer buffer;
96 	unsigned int messagelength;
97 };
98 
99 /**
100 * Interface called each time a message is received by network.
101 */
102 class INetMessageReceiver
103 {
104 public:
~INetMessageReceiver()105 	virtual ~INetMessageReceiver() {}
106 	virtual void pushEvent (std::unique_ptr<cNetMessage> message) = 0;
107 
108 	// when switching the NetMessageReceiver in cTcp, the new receiver will get
109 	// all remaining messages from the old receiver
popEvent()110 	virtual std::unique_ptr<cNetMessage> popEvent() { throw std::runtime_error("Method not implemented"); };
111 };
112 
113 //------------------------------------------------------------------------
114 /**
115 * Class for the handling of events over TCP/IP
116 *@author alzi alias DoctorDeath
117 */
118 class cTCP
119 {
120 public:
121 	/**
122 	 * Creates the mutexes, initialises some variables
123 	 * and the sockets and starts the network thread.
124 	 *@author alzi alias DoctorDeath
125 	 */
126 	cTCP();
127 
128 	/**
129 	 * Destroys the mutexes, the sockets and exits the network thread.
130 	 *@author alzi alias DoctorDeath
131 	 */
132 	~cTCP();
133 
134 	/**
135 	* Creates a new server on the port.
136 	*@author alzi alias DoctorDeath
137 	*return 0 on succes, -1 if an error occurs
138 	*/
139 	int create (int port);
140 	/**
141 	* Connects as client to the IP on the port.
142 	*@author alzi alias DoctorDeath
143 	*return 0 on succes, -1 if an error occurs
144 	*/
145 	int connect (const std::string& sIP, int port);
146 
147 	/**
148 	* checks whether the given socket is connected
149 	*/
150 	bool isConnected (unsigned int socketIndex) const;
151 	/**
152 	* Closes the connection to the socket.
153 	*@author alzi alias DoctorDeath
154 	*param iClientNumber Number of client/socket
155 	*                    to which the connection should be closed.
156 	*/
157 	void close (unsigned int iClientNumber);
158 
159 	/**
160 	* Sends data of an given length to the client/socket.
161 	*@author alzi alias DoctorDeath
162 	*param iClientNumber Number of client/socket
163 	*                    to which the data should be send.
164 	*param iLength Length of data to be send.
165 	*param buffer buffer with data to be send.
166 	*return 0 on succes, -1 if an error occurs
167 	*/
168 	int sendTo (unsigned int iClientNumber, unsigned int iLength, const char* buffer);
169 	/**
170 	* Sends the data to all sockets to which this machine is connected.
171 	*@author alzi alias DoctorDeath
172 	*param iLength Length of data to be send.
173 	*param buffer buffer with data to be send.
174 	*return 0 on succes, -1 if an error occurs
175 	*/
176 	int send (unsigned int iLength, const char* buffer);
177 
178 	/**
179 	* Set message receiver.
180 	* @author joris alias Jarod
181 	*/
182 	void setMessageReceiver (INetMessageReceiver* messageReceiver);
183 
184 	/**
185 	* Gets the number of currently connected sockets.
186 	*@author alzi alias DoctorDeath
187 	*return Number of sockets.
188 	*/
189 	int getSocketCount() const;
190 	/**
191 	* Gets the status of the connection.
192 	*@author alzi alias DoctorDeath
193 	*return 1 if connected, 0 if not.
194 	*/
195 	int getConnectionStatus() const;
196 	/**
197 	* looks if this machine is the host.
198 	*@author alzi alias DoctorDeath
199 	*return true if is host, false if not.
200 	*/
201 	bool isHost() const;
202 
203 	/**
204 	* Thread function which handles new incoming connections and data.
205 	*@author alzi alias DoctorDeath
206 	*/
207 	void HandleNetworkThread();
208 
209 private:
210 	/**
211 	* Searchs for the first unused socket and allocates memory
212 	* for a new one if there are no free sockets.
213 	*@author alzi alias DoctorDeath
214 	*@return index of found socket
215 	*/
216 	int getFreeSocket();
217 	/**
218 	* Deletes the socket, frees its memory
219 	* and sorts the rest sockets in the list.
220 	*@author alzi alias DoctorDeath
221 	*/
222 	void deleteSocket (int socketIndex);
223 
224 	void pushEvent (std::unique_ptr<cNetMessage> message);
225 
226 	void pushEventTCP_Close (unsigned int socketIndex);
227 
228 	void HandleNetworkThread_STATE_NEW (unsigned int socketIndex);
229 	void HandleNetworkThread_SERVER (unsigned int socketIndex);
230 	void HandleNetworkThread_CLIENT (unsigned int socketIndex);
231 	void HandleNetworkThread_CLIENT_pushReadyMessage (unsigned int socketIndex);
232 
233 private:
234 	cMutex TCPMutex;
235 
236 	SDL_Thread* TCPHandleThread;
237 	volatile bool bExit;
238 	bool bHost;
239 
240 	unsigned int iLast_Socket;
241 	sSocket Sockets[MAX_CLIENTS];
242 	SDLNet_SocketSet SocketSet;
243 	IPaddress ipaddr;
244 	INetMessageReceiver* messageReceiver;
245 };
246 
247 #endif // networkH
248