git-svn-id: https://scorched3d.svn.sourceforge.net/svnroot/scorched3d/trunk/scorched...
[scorched3d/parasti.git] / src / common / net / NetServerTCP2Destination.cpp
blob9a745a71a0fda750fb375e4577e70bcd46353dd1
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 #ifdef WIN32
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #include <winsock2.h>
25 #else
26 #include <errno.h>
27 #endif
29 #include <net/NetServerTCP2.h>
30 #include <net/NetMessagePool.h>
31 #include <net/NetOptions.h>
32 #include <common/Logger.h>
33 #include <common/Clock.h>
34 #include <set>
36 static int SDLNet_TCP_Recv_Wrapper(TCPsocket sock, void *data, int maxlen)
38 #ifdef WIN32
39 WSASetLastError(0);
40 #else
41 errno = 0;
42 #endif
44 int result = SDLNet_TCP_Recv(sock, data, maxlen);
45 if (result <= 0)
47 #ifdef WIN32
48 int wsacp = WSAGetLastError();
49 if (wsacp != WSAECONNRESET)
51 Logger::log(S3D::formatStringBuffer(
52 "SDLNet_TCP_Recv_Wrapper: WSA Error code %i", wsacp));
54 #else
55 int errnocp = errno;
56 if (errnocp != ECONNRESET)
58 Logger::log(S3D::formatStringBuffer(
59 "SDLNet_TCP_Recv_Wrapper: Error code %i", errnocp));
61 #endif
64 return result;
67 static int SDLNet_TCP_Send_Wrapper(TCPsocket sock, void *datap, int len)
69 #ifdef WIN32
70 WSASetLastError(0);
71 #else
72 errno = 0;
73 #endif
75 int result = SDLNet_TCP_Send(sock, datap, len);
76 if (result <= 0)
78 #ifdef WIN32
79 int wsacp = WSAGetLastError();
80 if (wsacp != WSAECONNRESET)
82 Logger::log(S3D::formatStringBuffer(
83 "SDLNet_TCP_Send_Wrapper: WSA Error code %i", wsacp));
85 #else
86 int errnocp = errno;
87 if (errnocp != ECONNRESET)
89 Logger::log(S3D::formatStringBuffer(
90 "SDLNet_TCP_Send_Wrapper: Error code %i", errnocp));
92 #endif
95 return result;
98 NetServerTCP2Destination::NetServerTCP2Destination(
99 NetMessageHandler *incomingMessageHandler,
100 TCPsocket socket,
101 unsigned int destinationId) :
102 socket_(socket), socketSet_(0),
103 currentMessage_(0), currentMessageLen_(0),
104 currentMessageSentLen_(0),
105 destinationId_(destinationId),
106 packetLogging_(false),
107 messagesSent_(0), messagesRecieved_(0),
108 bytesIn_(0), bytesOut_(0),
109 incomingMessageHandler_(incomingMessageHandler),
110 sendRecvThread_(0),
111 stopped_(false), finished_(false)
113 socketSet_ = SDLNet_AllocSocketSet(1);
114 SDLNet_TCP_AddSocket(socketSet_, socket_);
116 outgoingMessageHandler_.setMessageHandler(this);
117 packetLogging_ = NetOptions::instance()->getPacketLogging();
119 sendRecvThread_ = SDL_CreateThread(
120 NetServerTCP2Destination::sendRecvThreadFunc, (void *) this);
121 if (sendRecvThread_ == 0)
123 Logger::log(
124 "NetServerTCP2Destination: Failed to create NetServerTCP2Destination thread");
128 NetServerTCP2Destination::~NetServerTCP2Destination()
130 SDLNet_FreeSocketSet(socketSet_);
131 socketSet_ = 0;
133 if (socket_) SDLNet_TCP_Close(socket_);
134 socket_ = 0;
136 if (currentMessage_) NetMessagePool::instance()->addToPool(currentMessage_);
137 currentMessage_ = 0;
139 std::list<NetMessage *>::iterator itor;
140 for (itor = outgoingMessages_.begin();
141 itor != outgoingMessages_.end();
142 itor++)
144 NetMessagePool::instance()->addToPool(*itor);
147 int status;
148 SDL_WaitThread(sendRecvThread_, &status);
149 sendRecvThread_ = 0;
151 if (packetLogging_)
153 Logger::log(S3D::formatStringBuffer("NetServerTCP2Destination %u: destroyed",
154 destinationId_));
158 unsigned int NetServerTCP2Destination::getIpAddress()
160 return getIpAddressFromSocket(socket_);
163 unsigned int NetServerTCP2Destination::getIpAddressFromSocket(TCPsocket socket)
165 unsigned int addr = 0;
166 IPaddress *address = SDLNet_TCP_GetPeerAddress(socket);
167 if (address)
169 addr = SDLNet_Read32(&address->host);
171 return addr;
174 int NetServerTCP2Destination::sendRecvThreadFunc(void *c)
176 // Call a non-static class thread to do the processing in (just for convienience)
177 NetServerTCP2Destination *th = (NetServerTCP2Destination*) c;
178 th->actualSendRecvFunc();
179 th->finished_ = true;
180 return 0;
183 void NetServerTCP2Destination::actualSendRecvFunc()
185 Clock netClock;
186 while (!stopped_)
189 // Reset clock
190 netClock.getTimeDifference();
194 // Update messages
195 outgoingMessageHandler_.processMessages();
196 float timeDiff = netClock.getTimeDifference();
197 if (timeDiff > 5.0f)
199 Logger::log(S3D::formatStringBuffer(
200 "NetServerTCP2Destination %u: messages took %.2f seconds",
201 destinationId_,
202 timeDiff));
206 SocketResult sendResult;
208 // Send
209 sendResult = checkOutgoing();
210 float timeDiff = netClock.getTimeDifference();
211 if (timeDiff > 5.0f)
213 Logger::log(S3D::formatStringBuffer(
214 "NetServerTCP2Destination %u: outgoing took %.2f seconds",
215 destinationId_,
216 timeDiff));
218 if (sendResult == SocketClosed) break;
221 SocketResult recvResult;
223 // Recv
224 recvResult = checkIncoming();
225 float timeDiff = netClock.getTimeDifference();
226 if (timeDiff > 5.0f)
228 Logger::log(S3D::formatStringBuffer(
229 "NetServerTCP2Destination %u: incoming took %.2f seconds",
230 destinationId_,
231 timeDiff));
233 if (recvResult == SocketClosed) break;
236 if (sendResult == SocketEmpty &&
237 recvResult == SocketEmpty)
239 SDL_Delay(10);
243 if (packetLogging_)
245 Logger::log(S3D::formatStringBuffer("NetServerTCP2Destination %u: shutdown",
246 destinationId_));
250 void NetServerTCP2Destination::processMessage(NetMessage &oldmessage)
252 // Get a new buffer from the pool
253 NetMessage *message = NetMessagePool::instance()->
254 getFromPool(NetMessage::SentMessage,
255 oldmessage.getDestinationId(), getIpAddress());
257 // Copy old buffer into new buffer
258 NetBuffer &buffer = oldmessage.getBuffer();
259 message->getBuffer().allocate(buffer.getBufferUsed());
260 memcpy(message->getBuffer().getBuffer(),
261 buffer.getBuffer(), buffer.getBufferUsed());
262 message->getBuffer().setBufferUsed(buffer.getBufferUsed());
264 // Add to list of outgoing
265 outgoingMessages_.push_back(message);
267 if (packetLogging_)
269 Logger::log(S3D::formatStringBuffer(
270 "NetServerTCP2Destination %u: Adding a new message, %u now waiting",
271 destinationId_,
272 outgoingMessages_.size()));
276 NetServerTCP2Destination::SocketResult NetServerTCP2Destination::checkIncoming()
278 bool activity = false;
279 for (int i=0; i<2000; i++)
281 // Check if the socket is ready to give us data
282 int numready = SDLNet_CheckSockets(socketSet_, 0);
283 if (numready == -1)
285 //if (packetLogging_)
287 Logger::log(S3D::formatStringBuffer(
288 "NetServerTCP2Destination %u: CheckSockets returned an error %i",
289 destinationId_,
290 numready));
292 return SocketClosed;
294 if (numready == 0) return (i==0?SocketEmpty:SocketActivity);
295 if (!SDLNet_SocketReady(socket_)) return (activity?SocketActivity:SocketEmpty);
297 // Get data from socket
298 char buffer[1];
299 int recv = SDLNet_TCP_Recv_Wrapper(socket_, &buffer, 1);
300 if (recv <= 0)
302 //if (packetLogging_)
304 Logger::log(S3D::formatStringBuffer(
305 "NetServerTCP2Destination %u: Recv returned an error %i",
306 destinationId_,
307 recv));
309 return SocketClosed;
311 currentMessagePart_.addDataToBuffer(buffer, 1);
313 // Update stats
314 NetInterface::getBytesIn()++;
315 bytesIn_++;
316 activity = true;
318 // Get messagetype and len
319 if (currentMessagePart_.getBufferUsed() == 5)
321 NetBufferReader reader(currentMessagePart_);
322 reader.getFromBuffer(currentMessageType_);
323 reader.getFromBuffer(currentMessageLen_);
326 // Check if a full message has been recieved
327 if (currentMessagePart_.getBufferUsed() >= 5 &&
328 currentMessagePart_.getBufferUsed() == currentMessageLen_)
330 if (currentMessageType_ & TypeMessage)
332 if (!currentMessage_)
334 currentMessage_ = NetMessagePool::instance()->
335 getFromPool(NetMessage::BufferMessage,
336 destinationId_, getIpAddress());
339 // A full message part has been received
340 currentMessage_->getBuffer().addDataToBuffer(
341 currentMessagePart_.getBuffer() + 5,
342 currentMessagePart_.getBufferUsed() - 5);
343 if (currentMessageType_ & TypeLast)
345 // A finished message has been recieved
346 messagesRecieved_++;
347 incomingMessageHandler_->addMessage(currentMessage_);
348 currentMessage_ = 0;
351 // Log
352 if (packetLogging_)
354 Logger::log(S3D::formatStringBuffer(
355 "NetServerTCP2Destination %u: Recieved a message part, %s",
356 destinationId_,
357 (currentMessageType_ & TypeLast?"last":"not last")));
360 else
362 Logger::log(S3D::formatStringBuffer(
363 "NetServerTCP2Destination %u: Unknown message type %i received",
364 destinationId_,
365 currentMessageType_));
366 return SocketClosed;
369 currentMessageLen_ = 0;
370 currentMessagePart_.reset();
374 return (activity?SocketActivity:SocketEmpty);
377 NetServerTCP2Destination::SocketResult NetServerTCP2Destination::checkOutgoing()
379 // See if we have any messages to send
380 if (outgoingMessages_.empty()) return SocketEmpty;
382 // Check to see how much to send
383 NetMessage *message = outgoingMessages_.front();
384 int sendAmount = message->getBuffer().getBufferUsed() - currentMessageSentLen_;
385 if (sendAmount > 100) sendAmount = 100;
387 if (currentMessageSentLen_ == 0)
389 // Send Len
390 if(!sendHeader(TypeMessage | TypeLast,
391 5 + message->getBuffer().getBufferUsed()))
393 return SocketClosed;
397 // Send data
398 int result = SDLNet_TCP_Send_Wrapper(socket_,
399 (void *) &message->getBuffer().getBuffer()[currentMessageSentLen_],
400 sendAmount);
401 if(result < sendAmount) // Socket Closed
403 Logger::log(S3D::formatStringBuffer(
404 "NetServerTCP2Destination %u: Failed to send buffer %i of %i. Socket closed",
405 destinationId_, result, sendAmount));
406 return SocketClosed;
409 NetInterface::getBytesOut() += result;
410 bytesOut_ += result;
412 // Check if we have finished sending this message
413 currentMessageSentLen_ += sendAmount;
414 if (currentMessageSentLen_ == message->getBuffer().getBufferUsed())
416 outgoingMessages_.pop_front();
417 currentMessageSentLen_ = 0;
418 incomingMessageHandler_->addMessage(message);
420 messagesSent_++;
421 if (packetLogging_)
423 Logger::log(S3D::formatStringBuffer(
424 "NetServerTCP2Destination %u: Sent a message part, %s",
425 destinationId_,
426 "last"));
430 return SocketActivity;
433 bool NetServerTCP2Destination::sendHeader(char headerType, int len)
435 NetMessage *ackMessage = NetMessagePool::instance()->
436 getFromPool(NetMessage::BufferMessage, 0, 0);
438 // Form Header
439 ackMessage->getBuffer().addToBuffer(headerType);
440 ackMessage->getBuffer().addToBuffer(len);
442 // Send Header
443 int result = SDLNet_TCP_Send_Wrapper(socket_,
444 (void *) ackMessage->getBuffer().getBuffer(),
445 ackMessage->getBuffer().getBufferUsed());
447 NetInterface::getBytesOut() += result;
448 bytesOut_ += result;
450 NetMessagePool::instance()->addToPool(ackMessage);
452 if (result != ackMessage->getBuffer().getBufferUsed())
454 Logger::log(S3D::formatStringBuffer(
455 "NetServerTCP2Destination %u: Failed to send header %i of %i. Socket closed",
456 destinationId_, result, ackMessage->getBuffer().getBufferUsed()));
459 return (result == ackMessage->getBuffer().getBufferUsed());
462 void NetServerTCP2Destination::printStats(unsigned int destination)
464 Logger::log(S3D::formatStringBuffer("TCP2 Destination %u net stats:", destination));
465 Logger::log(S3D::formatStringBuffer(" %u messages sent, %u messages recieved",
466 messagesSent_, messagesRecieved_));
467 Logger::log(S3D::formatStringBuffer(" %u bytes in, %u bytes out",
468 bytesIn_, bytesOut_));