git-svn-id: https://scorched3d.svn.sourceforge.net/svnroot/scorched3d/trunk/scorched...
[scorched3d/parasti.git] / src / common / net / NetServerTCP3.cpp
blobe1a75af5863a2e5ce239f5c38a6ad0d19b7327d6
1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2009
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Scorched3D; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ////////////////////////////////////////////////////////////////////////////////
21 #include <net/NetServerTCP3.h>
22 #include <net/NetMessagePool.h>
23 #include <net/NetOptions.h>
24 #include <common/Logger.h>
25 #include <common/Clock.h>
26 #include <limits.h>
28 NetServerTCP3::NetServerTCP3() :
29 serverDestinationId_(UINT_MAX), nextDestinationId_(1),
30 sendRecvThread_(0),
31 serverSock_(0), serverSockSet_(0),
32 stopped_(false)
34 NetOptions::instance()->readOptionsFromFile();
35 NetOptions::instance()->writeOptionsToFile();
37 serverSockSet_ = SDLNet_AllocSocketSet(1);
40 NetServerTCP3::~NetServerTCP3()
42 SDLNet_FreeSocketSet(serverSockSet_);
43 serverSockSet_ = 0;
46 bool NetServerTCP3::started()
48 // Do we have a valid send/recieve thread
49 return (sendRecvThread_ != 0);
52 bool NetServerTCP3::connect(const char *hostName, int portNo)
54 if(SDLNet_Init()==-1)
56 return false;
59 // Resolve server address
60 IPaddress serverAddress;
61 if (SDLNet_ResolveHost(&serverAddress, hostName, portNo) != 0)
63 Logger::log(S3D::formatStringBuffer("NetServerTCP3: Failed to resolve host %s:%i",
64 hostName, portNo));
65 return false;
68 // Stop any previous connections
69 stop();
71 // Create a new socket for the client
72 TCPsocket clientSock = SDLNet_TCP_Open(&serverAddress);
73 if (!clientSock)
75 Logger::log(S3D::formatStringBuffer("NetServerTCP3: Failed to open client socket : %s",
76 SDLNet_GetError()));
77 return false;
80 // Add client socket
81 serverDestinationId_ = addDestination(clientSock);
83 // Start sending/recieving on the anon port
84 if (!startProcessing()) return false;
86 return true;
89 bool NetServerTCP3::start(int portNo)
91 if(SDLNet_Init()==-1)
93 return false;
96 // Stop any previous connections
97 stop();
99 // Get the local ip address
100 IPaddress localip;
101 if(SDLNet_ResolveHost(&localip, NULL, portNo)==-1)
103 return false;
106 // we seem to be able to open the same port
107 // multiple times!!!
108 // This is fixed as the server info port catches it
109 serverSock_ = SDLNet_TCP_Open(&localip);
110 if (!serverSock_)
112 Logger::log(S3D::formatStringBuffer("NetServerTCP3: Failed to open server socket %i", portNo));
113 return false;
115 SDLNet_TCP_AddSocket(serverSockSet_, serverSock_);
117 // Start sending/recieving on this socket
118 if (!startProcessing()) return false;
120 return true;
123 void NetServerTCP3::stop()
125 if (started())
127 disconnectAllClients();
128 while (started()) SDL_Delay(100);
132 bool NetServerTCP3::startProcessing()
134 // Check if we are already running
135 DIALOG_ASSERT(!sendRecvThread_);
137 // We are going to process all incoming message
138 outgoingMessageHandler_.setMessageHandler(this);
140 // Create the processing thread
141 sendRecvThread_ = SDL_CreateThread(
142 NetServerTCP3::sendRecvThreadFunc, (void *) this);
143 if (sendRecvThread_ == 0)
145 Logger::log(S3D::formatStringBuffer("NetServerTCP3: Failed to create NetServerTCP3 thread"));
146 return false;
149 return true;
152 int NetServerTCP3::sendRecvThreadFunc(void *c)
154 // Call a non-static class thread to do the processing in (just for convienience)
155 NetServerTCP3 *th = (NetServerTCP3*) c;
156 th->actualSendRecvFunc();
158 th->sendRecvThread_ = 0;
159 Logger::log(S3D::formatStringBuffer("NetServerTCP3: shutdown"));
160 return 0;
163 void NetServerTCP3::actualSendRecvFunc()
165 float timeDiff;
166 stopped_ = false;
167 Clock netClock;
168 while(!stopped_)
170 // Send/recv packets
171 checkClients();
172 timeDiff = netClock.getTimeDifference();
173 if (timeDiff > 1.0f)
175 Logger::log(S3D::formatStringBuffer(
176 "NetServerTCP3: checkClients took %.2f seconds",
177 timeDiff));
180 // Check for new connections
181 checkNewConnections();
182 timeDiff = netClock.getTimeDifference();
183 if (timeDiff > 1.0f)
185 Logger::log(S3D::formatStringBuffer(
186 "NetServerTCP3: checkNewConnections took %.2f seconds",
187 timeDiff));
190 // sleep so we don't go into an infinite loop
191 SDL_Delay(10);
192 netClock.getTimeDifference();
194 // Check for any new messages we should send and process them
195 outgoingMessageHandler_.processMessages();
196 timeDiff = netClock.getTimeDifference();
197 if (timeDiff > 1.0f)
199 Logger::log(S3D::formatStringBuffer(
200 "NetServerTCP3: processMessages took %.2f seconds",
201 timeDiff));
205 if (serverSock_) SDLNet_TCP_Close(serverSock_);
206 serverSock_ = 0;
209 void NetServerTCP3::checkNewConnections()
211 if (!serverSock_) return; // Check if we are running a server
213 int numready = SDLNet_CheckSockets(serverSockSet_, 10);
214 if (numready == -1) return;
215 if (numready == 0) return;
217 if(SDLNet_SocketReady(serverSock_))
219 TCPsocket clientSock = SDLNet_TCP_Accept(serverSock_);
220 if (clientSock)
222 // add client
223 addDestination(clientSock);
228 void NetServerTCP3::checkClients()
230 // Check each destination to see if it has closed
231 std::map<unsigned int, NetServerTCP3Destination *>::iterator itor;
232 for (itor = destinations_.begin();
233 itor != destinations_.end();
234 itor++)
236 NetServerTCP3Destination *destination = itor->second;
237 if (destination->anyFinished())
239 destroyDestination(itor->first, NetMessage::UserDisconnect);
240 break;
244 // Check each destination that is closing to see if it has finished
245 if (finishedDestinations_.empty()) return;
247 NetServerTCP3Destination *destination = finishedDestinations_.front();
248 if (destination->allFinished())
250 delete destination;
251 finishedDestinations_.pop_front();
255 void NetServerTCP3::processMessage(NetMessage &message)
257 // We have been told to send a message to a client
259 // Check if we have been told to disconect all clients
260 if (message.getMessageType() == NetMessage::DisconnectAllMessage)
262 // Foreach client
263 while (!destinations_.empty())
265 // Get the first client
266 std::map<unsigned int, NetServerTCP3Destination *>::iterator itor =
267 destinations_.begin();
268 unsigned int destinationId = (*itor).first;
269 NetServerTCP3Destination *destination = (*itor).second;
271 // This is a message telling us to kick the client, do so
272 destroyDestination(destinationId, NetMessage::KickDisconnect);
275 stopped_ = true;
276 return;
279 // Look up this destination in the list of current
280 std::map<unsigned int, NetServerTCP3Destination *>::iterator itor =
281 destinations_.find(message.getDestinationId());
282 if (itor == destinations_.end())
284 return;
287 NetServerTCP3Destination *destination = (*itor).second;
288 if (message.getMessageType() == NetMessage::DisconnectMessage)
290 // This is a message telling us to kick the client, do so
291 destroyDestination(message.getDestinationId(), NetMessage::KickDisconnect);
293 else
295 // Add this buffer to the list of items to be sent
296 NetMessage *newMessage = NetMessagePool::instance()->getFromPool(
297 message.getMessageType(), message.getDestinationId(),
298 message.getIpAddress(), message.getFlags());
299 newMessage->getBuffer().allocate(message.getBuffer().getBufferUsed());
300 memcpy(newMessage->getBuffer().getBuffer(),
301 message.getBuffer().getBuffer(),
302 message.getBuffer().getBufferUsed());
303 newMessage->getBuffer().setBufferUsed(message.getBuffer().getBufferUsed());
305 destination->sendMessage(newMessage);
309 void NetServerTCP3::disconnectAllClients()
311 // Get a new buffer from the pool (with the discconect type set)
312 NetMessage *message = NetMessagePool::instance()->
313 getFromPool(NetMessage::DisconnectAllMessage, 0, 0);
315 // Send Mesage
316 outgoingMessageHandler_.addMessage(message);
319 void NetServerTCP3::disconnectClient(unsigned int destination)
321 // Get a new buffer from the pool (with the discconect type set)
322 NetMessage *message = NetMessagePool::instance()->
323 getFromPool(NetMessage::DisconnectMessage, destination, 0);
325 // Send Mesage
326 outgoingMessageHandler_.addMessage(message);
329 void NetServerTCP3::sendMessageServer(NetBuffer &buffer,
330 unsigned int flags)
332 // Send a message to the server
333 sendMessageDest(buffer, serverDestinationId_, flags);
336 void NetServerTCP3::sendMessageDest(NetBuffer &buffer,
337 unsigned int destination, unsigned int flags)
339 // Get a new buffer from the pool
340 NetMessage *message = NetMessagePool::instance()->
341 getFromPool(NetMessage::BufferMessage,
342 destination, 0, flags);
344 // Add message to new buffer
345 message->getBuffer().allocate(buffer.getBufferUsed());
346 memcpy(message->getBuffer().getBuffer(),
347 buffer.getBuffer(), buffer.getBufferUsed());
348 message->getBuffer().setBufferUsed(buffer.getBufferUsed());
350 // Send Mesage
351 outgoingMessageHandler_.addMessage(message);
354 int NetServerTCP3::processMessages()
356 // Process any messages that we have recieved
357 return incomingMessageHandler_.processMessages();
360 void NetServerTCP3::setMessageHandler(NetMessageHandlerI *handler)
362 // Set the message handler to process any messages that we recieve
363 incomingMessageHandler_.setMessageHandler(handler);
366 void NetServerTCP3::destroyDestination(unsigned int destinationId,
367 NetMessage::DisconnectFlags type)
369 // Destroy this destination
370 std::map<unsigned int, NetServerTCP3Destination *>::iterator itor =
371 destinations_.find(destinationId);
372 if (itor == destinations_.end())
374 return;
377 if (serverDestinationId_ == destinationId)
379 stopped_ = true;
380 serverDestinationId_ = UINT_MAX;
383 NetServerTCP3Destination *destination = (*itor).second;
385 // Get a new buffer from the pool (with the discconect type set)
386 NetMessage *message = NetMessagePool::instance()->
387 getFromPool(NetMessage::DisconnectMessage,
388 destinationId, destination->getIpAddress());
389 message->setFlags((unsigned int) type);
391 destinations_.erase(itor);
392 destination->printStats();
393 destination->close();
394 finishedDestinations_.push_back(destination);
396 // Add to outgoing message pool
397 incomingMessageHandler_.addMessage(message);
400 unsigned int NetServerTCP3::addDestination(TCPsocket &socket)
402 NetInterface::getConnects() ++;
404 // Allocate new destination id
405 do {
406 nextDestinationId_++;
407 } while (nextDestinationId_ == 0 || nextDestinationId_ == UINT_MAX);
408 unsigned int destinationId = nextDestinationId_;
410 // Create new destination
411 NetServerTCP3Destination *destination =
412 new NetServerTCP3Destination(
413 &incomingMessageHandler_, socket, destinationId);
414 destinations_[destinationId] = destination;
416 // Get a new buffer from the pool (with the connect type set)
417 NetMessage *message = NetMessagePool::instance()->
418 getFromPool(NetMessage::ConnectMessage,
419 destinationId, destination->getIpAddress());
420 incomingMessageHandler_.addMessage(message);
422 // Return new id
423 return destinationId;