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 ////////////////////////////////////////////////////////////////////////////////
22 #define WIN32_LEAN_AND_MEAN
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>
36 static int SDLNet_TCP_Recv_Wrapper(TCPsocket sock
, void *data
, int maxlen
)
44 int result
= SDLNet_TCP_Recv(sock
, data
, maxlen
);
48 int wsacp
= WSAGetLastError();
49 if (wsacp
!= WSAECONNRESET
)
51 Logger::log(S3D::formatStringBuffer(
52 "SDLNet_TCP_Recv_Wrapper: WSA Error code %i", wsacp
));
56 if (errnocp
!= ECONNRESET
)
58 Logger::log(S3D::formatStringBuffer(
59 "SDLNet_TCP_Recv_Wrapper: Error code %i", errnocp
));
67 static int SDLNet_TCP_Send_Wrapper(TCPsocket sock
, void *datap
, int len
)
75 int result
= SDLNet_TCP_Send(sock
, datap
, len
);
79 int wsacp
= WSAGetLastError();
80 if (wsacp
!= WSAECONNRESET
)
82 Logger::log(S3D::formatStringBuffer(
83 "SDLNet_TCP_Send_Wrapper: WSA Error code %i", wsacp
));
87 if (errnocp
!= ECONNRESET
)
89 Logger::log(S3D::formatStringBuffer(
90 "SDLNet_TCP_Send_Wrapper: Error code %i", errnocp
));
98 NetServerTCP2Destination::NetServerTCP2Destination(
99 NetMessageHandler
*incomingMessageHandler
,
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
),
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)
124 "NetServerTCP2Destination: Failed to create NetServerTCP2Destination thread");
128 NetServerTCP2Destination::~NetServerTCP2Destination()
130 SDLNet_FreeSocketSet(socketSet_
);
133 if (socket_
) SDLNet_TCP_Close(socket_
);
136 if (currentMessage_
) NetMessagePool::instance()->addToPool(currentMessage_
);
139 std::list
<NetMessage
*>::iterator itor
;
140 for (itor
= outgoingMessages_
.begin();
141 itor
!= outgoingMessages_
.end();
144 NetMessagePool::instance()->addToPool(*itor
);
148 SDL_WaitThread(sendRecvThread_
, &status
);
153 Logger::log(S3D::formatStringBuffer("NetServerTCP2Destination %u: destroyed",
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
);
169 addr
= SDLNet_Read32(&address
->host
);
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;
183 void NetServerTCP2Destination::actualSendRecvFunc()
190 netClock
.getTimeDifference();
195 outgoingMessageHandler_
.processMessages();
196 float timeDiff
= netClock
.getTimeDifference();
199 Logger::log(S3D::formatStringBuffer(
200 "NetServerTCP2Destination %u: messages took %.2f seconds",
206 SocketResult sendResult
;
209 sendResult
= checkOutgoing();
210 float timeDiff
= netClock
.getTimeDifference();
213 Logger::log(S3D::formatStringBuffer(
214 "NetServerTCP2Destination %u: outgoing took %.2f seconds",
218 if (sendResult
== SocketClosed
) break;
221 SocketResult recvResult
;
224 recvResult
= checkIncoming();
225 float timeDiff
= netClock
.getTimeDifference();
228 Logger::log(S3D::formatStringBuffer(
229 "NetServerTCP2Destination %u: incoming took %.2f seconds",
233 if (recvResult
== SocketClosed
) break;
236 if (sendResult
== SocketEmpty
&&
237 recvResult
== SocketEmpty
)
245 Logger::log(S3D::formatStringBuffer("NetServerTCP2Destination %u: shutdown",
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
);
269 Logger::log(S3D::formatStringBuffer(
270 "NetServerTCP2Destination %u: Adding a new message, %u now waiting",
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);
285 //if (packetLogging_)
287 Logger::log(S3D::formatStringBuffer(
288 "NetServerTCP2Destination %u: CheckSockets returned an error %i",
294 if (numready
== 0) return (i
==0?SocketEmpty
:SocketActivity
);
295 if (!SDLNet_SocketReady(socket_
)) return (activity
?SocketActivity
:SocketEmpty
);
297 // Get data from socket
299 int recv
= SDLNet_TCP_Recv_Wrapper(socket_
, &buffer
, 1);
302 //if (packetLogging_)
304 Logger::log(S3D::formatStringBuffer(
305 "NetServerTCP2Destination %u: Recv returned an error %i",
311 currentMessagePart_
.addDataToBuffer(buffer
, 1);
314 NetInterface::getBytesIn()++;
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
347 incomingMessageHandler_
->addMessage(currentMessage_
);
354 Logger::log(S3D::formatStringBuffer(
355 "NetServerTCP2Destination %u: Recieved a message part, %s",
357 (currentMessageType_
& TypeLast
?"last":"not last")));
362 Logger::log(S3D::formatStringBuffer(
363 "NetServerTCP2Destination %u: Unknown message type %i received",
365 currentMessageType_
));
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)
390 if(!sendHeader(TypeMessage
| TypeLast
,
391 5 + message
->getBuffer().getBufferUsed()))
398 int result
= SDLNet_TCP_Send_Wrapper(socket_
,
399 (void *) &message
->getBuffer().getBuffer()[currentMessageSentLen_
],
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
));
409 NetInterface::getBytesOut() += 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
);
423 Logger::log(S3D::formatStringBuffer(
424 "NetServerTCP2Destination %u: Sent a message part, %s",
430 return SocketActivity
;
433 bool NetServerTCP2Destination::sendHeader(char headerType
, int len
)
435 NetMessage
*ackMessage
= NetMessagePool::instance()->
436 getFromPool(NetMessage::BufferMessage
, 0, 0);
439 ackMessage
->getBuffer().addToBuffer(headerType
);
440 ackMessage
->getBuffer().addToBuffer(len
);
443 int result
= SDLNet_TCP_Send_Wrapper(socket_
,
444 (void *) ackMessage
->getBuffer().getBuffer(),
445 ackMessage
->getBuffer().getBufferUsed());
447 NetInterface::getBytesOut() += 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_
));