1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2009
4 // This file is part of Scorched3D.
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>
28 NetServerTCP3::NetServerTCP3() :
29 serverDestinationId_(UINT_MAX
), nextDestinationId_(1),
31 serverSock_(0), serverSockSet_(0),
34 NetOptions::instance()->readOptionsFromFile();
35 NetOptions::instance()->writeOptionsToFile();
37 serverSockSet_
= SDLNet_AllocSocketSet(1);
40 NetServerTCP3::~NetServerTCP3()
42 SDLNet_FreeSocketSet(serverSockSet_
);
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
)
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",
68 // Stop any previous connections
71 // Create a new socket for the client
72 TCPsocket clientSock
= SDLNet_TCP_Open(&serverAddress
);
75 Logger::log(S3D::formatStringBuffer("NetServerTCP3: Failed to open client socket : %s",
81 serverDestinationId_
= addDestination(clientSock
);
83 // Start sending/recieving on the anon port
84 if (!startProcessing()) return false;
89 bool NetServerTCP3::start(int portNo
)
96 // Stop any previous connections
99 // Get the local ip address
101 if(SDLNet_ResolveHost(&localip
, NULL
, portNo
)==-1)
106 // we seem to be able to open the same port
108 // This is fixed as the server info port catches it
109 serverSock_
= SDLNet_TCP_Open(&localip
);
112 Logger::log(S3D::formatStringBuffer("NetServerTCP3: Failed to open server socket %i", portNo
));
115 SDLNet_TCP_AddSocket(serverSockSet_
, serverSock_
);
117 // Start sending/recieving on this socket
118 if (!startProcessing()) return false;
123 void NetServerTCP3::stop()
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"));
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"));
163 void NetServerTCP3::actualSendRecvFunc()
172 timeDiff
= netClock
.getTimeDifference();
175 Logger::log(S3D::formatStringBuffer(
176 "NetServerTCP3: checkClients took %.2f seconds",
180 // Check for new connections
181 checkNewConnections();
182 timeDiff
= netClock
.getTimeDifference();
185 Logger::log(S3D::formatStringBuffer(
186 "NetServerTCP3: checkNewConnections took %.2f seconds",
190 // sleep so we don't go into an infinite loop
192 netClock
.getTimeDifference();
194 // Check for any new messages we should send and process them
195 outgoingMessageHandler_
.processMessages();
196 timeDiff
= netClock
.getTimeDifference();
199 Logger::log(S3D::formatStringBuffer(
200 "NetServerTCP3: processMessages took %.2f seconds",
205 if (serverSock_
) SDLNet_TCP_Close(serverSock_
);
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_
);
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();
236 NetServerTCP3Destination
*destination
= itor
->second
;
237 if (destination
->anyFinished())
239 destroyDestination(itor
->first
, NetMessage::UserDisconnect
);
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())
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
)
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
);
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())
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
);
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);
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);
326 outgoingMessageHandler_
.addMessage(message
);
329 void NetServerTCP3::sendMessageServer(NetBuffer
&buffer
,
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());
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())
377 if (serverDestinationId_
== destinationId
)
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
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
);
423 return destinationId
;