NetServerTCP2Destination.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #ifdef WIN32
00022 #define WIN32_LEAN_AND_MEAN
00023 #include <windows.h>
00024 #include <winsock2.h>
00025 #else
00026 #include <errno.h>
00027 #endif
00028 
00029 #include <net/NetServerTCP2.h>
00030 #include <net/NetMessagePool.h>
00031 #include <net/NetOptions.h>
00032 #include <common/Logger.h>
00033 #include <common/Clock.h>
00034 #include <set>
00035 
00036 static int SDLNet_TCP_Recv_Wrapper(TCPsocket sock, void *data, int maxlen)
00037 {
00038 #ifdef WIN32
00039         WSASetLastError(0);
00040 #else
00041         errno = 0;
00042 #endif
00043 
00044         int result = SDLNet_TCP_Recv(sock, data, maxlen);
00045         if (result <= 0)
00046         {
00047 #ifdef WIN32
00048                 int wsacp = WSAGetLastError();
00049                 if (wsacp != WSAECONNRESET)
00050                 {
00051                         Logger::log(S3D::formatStringBuffer(
00052                                 "SDLNet_TCP_Recv_Wrapper: WSA Error code %i", wsacp));
00053                 }
00054 #else
00055                 int errnocp = errno;
00056                 if (errnocp != ECONNRESET)
00057                 {
00058                         Logger::log(S3D::formatStringBuffer(
00059                                 "SDLNet_TCP_Recv_Wrapper: Error code %i", errnocp));
00060                 }
00061 #endif
00062         }
00063 
00064         return result;
00065 }
00066 
00067 static int SDLNet_TCP_Send_Wrapper(TCPsocket sock, void *datap, int len)
00068 {
00069 #ifdef WIN32
00070         WSASetLastError(0);
00071 #else
00072         errno = 0;
00073 #endif
00074 
00075         int result = SDLNet_TCP_Send(sock, datap, len);
00076         if (result <= 0)
00077         {
00078 #ifdef WIN32
00079                 int wsacp = WSAGetLastError();
00080                 if (wsacp != WSAECONNRESET)
00081                 {
00082                         Logger::log(S3D::formatStringBuffer(
00083                                 "SDLNet_TCP_Send_Wrapper: WSA Error code %i", wsacp));
00084                 }
00085 #else
00086                 int errnocp = errno;
00087                 if (errnocp != ECONNRESET)
00088                 {
00089                         Logger::log(S3D::formatStringBuffer(
00090                                 "SDLNet_TCP_Send_Wrapper: Error code %i", errnocp));
00091                 }
00092 #endif
00093         }
00094 
00095         return result;
00096 }
00097 
00098 NetServerTCP2Destination::NetServerTCP2Destination(
00099         NetMessageHandler *incomingMessageHandler, 
00100         TCPsocket socket,
00101         unsigned int destinationId) :
00102         socket_(socket), socketSet_(0), 
00103         currentMessage_(0), currentMessageLen_(0),
00104         currentMessageSentLen_(0),
00105         destinationId_(destinationId), 
00106         packetLogging_(false),
00107         messagesSent_(0), messagesRecieved_(0), 
00108         bytesIn_(0), bytesOut_(0), 
00109         incomingMessageHandler_(incomingMessageHandler),
00110         sendRecvThread_(0),
00111         stopped_(false), finished_(false)
00112 {
00113         socketSet_ = SDLNet_AllocSocketSet(1);
00114         SDLNet_TCP_AddSocket(socketSet_, socket_);
00115 
00116         outgoingMessageHandler_.setMessageHandler(this);
00117         packetLogging_ = NetOptions::instance()->getPacketLogging();
00118 
00119         sendRecvThread_ = SDL_CreateThread(
00120                 NetServerTCP2Destination::sendRecvThreadFunc, (void *) this);
00121         if (sendRecvThread_ == 0)
00122         {
00123                 Logger::log(
00124                         "NetServerTCP2Destination: Failed to create NetServerTCP2Destination thread");
00125         }
00126 }
00127 
00128 NetServerTCP2Destination::~NetServerTCP2Destination()
00129 {
00130         SDLNet_FreeSocketSet(socketSet_);
00131         socketSet_ = 0;
00132 
00133         if (socket_) SDLNet_TCP_Close(socket_);
00134         socket_ = 0;
00135 
00136         if (currentMessage_) NetMessagePool::instance()->addToPool(currentMessage_);
00137         currentMessage_ = 0;
00138 
00139         std::list<NetMessage *>::iterator itor;
00140         for (itor = outgoingMessages_.begin();
00141                 itor != outgoingMessages_.end();
00142                 itor++)
00143         {
00144                 NetMessagePool::instance()->addToPool(*itor);
00145         }
00146 
00147         int status;
00148         SDL_WaitThread(sendRecvThread_, &status);
00149         sendRecvThread_ = 0;
00150 
00151         if (packetLogging_)
00152         {
00153                 Logger::log(S3D::formatStringBuffer("NetServerTCP2Destination %u: destroyed",
00154                         destinationId_));
00155         }
00156 }
00157 
00158 unsigned int NetServerTCP2Destination::getIpAddress()
00159 {
00160         return getIpAddressFromSocket(socket_);
00161 }
00162 
00163 unsigned int NetServerTCP2Destination::getIpAddressFromSocket(TCPsocket socket)
00164 {
00165         unsigned int addr = 0;
00166         IPaddress *address = SDLNet_TCP_GetPeerAddress(socket);
00167         if (address)
00168         {
00169                 addr = SDLNet_Read32(&address->host);
00170         }
00171         return addr;
00172 }
00173 
00174 int NetServerTCP2Destination::sendRecvThreadFunc(void *c)
00175 {
00176         // Call a non-static class thread to do the processing in (just for convienience)
00177         NetServerTCP2Destination *th = (NetServerTCP2Destination*) c;
00178         th->actualSendRecvFunc();
00179         th->finished_ = true;
00180         return 0;
00181 }
00182 
00183 void NetServerTCP2Destination::actualSendRecvFunc()
00184 {
00185         Clock netClock;
00186         while (!stopped_)
00187         {
00188                 {
00189                         // Reset clock
00190                         netClock.getTimeDifference();
00191                 }
00192 
00193                 {
00194                         // Update messages
00195                         outgoingMessageHandler_.processMessages();
00196                         float timeDiff = netClock.getTimeDifference();
00197                         if (timeDiff > 5.0f)
00198                         {
00199                                 Logger::log(S3D::formatStringBuffer(
00200                                         "NetServerTCP2Destination %u: messages took %.2f seconds", 
00201                                         destinationId_,
00202                                         timeDiff));
00203                         }
00204                 }
00205 
00206                 SocketResult sendResult;
00207                 {
00208                         // Send
00209                         sendResult = checkOutgoing();
00210                         float timeDiff = netClock.getTimeDifference();
00211                         if (timeDiff > 5.0f)
00212                         {
00213                                 Logger::log(S3D::formatStringBuffer(
00214                                         "NetServerTCP2Destination %u: outgoing took %.2f seconds", 
00215                                         destinationId_,
00216                                         timeDiff));
00217                         }
00218                         if (sendResult == SocketClosed) break;
00219                 }
00220 
00221                 SocketResult recvResult;
00222                 {
00223                         // Recv
00224                         recvResult = checkIncoming();
00225                         float timeDiff = netClock.getTimeDifference();
00226                         if (timeDiff > 5.0f)
00227                         {
00228                                 Logger::log(S3D::formatStringBuffer(
00229                                         "NetServerTCP2Destination %u: incoming took %.2f seconds", 
00230                                         destinationId_,
00231                                         timeDiff));
00232                         }
00233                         if (recvResult == SocketClosed) break;
00234                 }
00235 
00236                 if (sendResult == SocketEmpty &&
00237                         recvResult == SocketEmpty)
00238                 {
00239                         SDL_Delay(10);
00240                 }
00241         }
00242 
00243         if (packetLogging_)
00244         {
00245                 Logger::log(S3D::formatStringBuffer("NetServerTCP2Destination %u: shutdown",
00246                         destinationId_));
00247         }
00248 }
00249 
00250 void NetServerTCP2Destination::processMessage(NetMessage &oldmessage)
00251 {
00252         // Get a new buffer from the pool
00253         NetMessage *message = NetMessagePool::instance()->
00254                 getFromPool(NetMessage::SentMessage, 
00255                         oldmessage.getDestinationId(), getIpAddress());
00256 
00257         // Copy old buffer into new buffer
00258         NetBuffer &buffer = oldmessage.getBuffer();
00259         message->getBuffer().allocate(buffer.getBufferUsed());
00260         memcpy(message->getBuffer().getBuffer(), 
00261                 buffer.getBuffer(), buffer.getBufferUsed());
00262         message->getBuffer().setBufferUsed(buffer.getBufferUsed());
00263 
00264         // Add to list of outgoing
00265         outgoingMessages_.push_back(message);
00266 
00267         if (packetLogging_)
00268         {
00269                 Logger::log(S3D::formatStringBuffer(
00270                         "NetServerTCP2Destination %u: Adding a new message, %u now waiting", 
00271                         destinationId_,
00272                         outgoingMessages_.size()));
00273         }
00274 }
00275 
00276 NetServerTCP2Destination::SocketResult NetServerTCP2Destination::checkIncoming()
00277 {
00278         bool activity = false;
00279         for (int i=0; i<2000; i++)
00280         {
00281                 // Check if the socket is ready to give us data
00282                 int numready = SDLNet_CheckSockets(socketSet_, 0);
00283                 if (numready == -1) 
00284                 {
00285                         //if (packetLogging_)
00286                         {
00287                                 Logger::log(S3D::formatStringBuffer(
00288                                         "NetServerTCP2Destination %u: CheckSockets returned an error %i", 
00289                                         destinationId_,
00290                                         numready));
00291                         }
00292                         return SocketClosed;
00293                 }
00294                 if (numready == 0) return (i==0?SocketEmpty:SocketActivity);
00295                 if (!SDLNet_SocketReady(socket_)) return (activity?SocketActivity:SocketEmpty);
00296 
00297                 // Get data from socket
00298                 char buffer[1];
00299                 int recv = SDLNet_TCP_Recv_Wrapper(socket_, &buffer, 1);
00300                 if (recv <= 0)
00301                 {
00302                         //if (packetLogging_)
00303                         {
00304                                 Logger::log(S3D::formatStringBuffer(
00305                                         "NetServerTCP2Destination %u: Recv returned an error %i", 
00306                                         destinationId_,
00307                                         recv));
00308                         }
00309                         return SocketClosed;
00310                 }
00311                 currentMessagePart_.addDataToBuffer(buffer, 1);
00312 
00313                 // Update stats
00314                 NetInterface::getBytesIn()++;
00315                 bytesIn_++;
00316                 activity = true;
00317                 
00318                 // Get messagetype and len
00319                 if (currentMessagePart_.getBufferUsed() == 5)
00320                 {
00321                         NetBufferReader reader(currentMessagePart_);
00322                         reader.getFromBuffer(currentMessageType_);
00323                         reader.getFromBuffer(currentMessageLen_);
00324                 }
00325 
00326                 // Check if a full message has been recieved
00327                 if (currentMessagePart_.getBufferUsed() >= 5 &&
00328                         currentMessagePart_.getBufferUsed() == currentMessageLen_)
00329                 {
00330                         if (currentMessageType_ & TypeMessage)
00331                         {
00332                                 if (!currentMessage_)
00333                                 {
00334                                         currentMessage_ = NetMessagePool::instance()->
00335                                                 getFromPool(NetMessage::BufferMessage, 
00336                                                         destinationId_, getIpAddress());
00337                                 }
00338 
00339                                 // A full message part has been received
00340                                 currentMessage_->getBuffer().addDataToBuffer(
00341                                         currentMessagePart_.getBuffer() + 5,
00342                                         currentMessagePart_.getBufferUsed() - 5);
00343                                 if (currentMessageType_ & TypeLast)
00344                                 {
00345                                         // A finished message has been recieved
00346                                         messagesRecieved_++;
00347                                         incomingMessageHandler_->addMessage(currentMessage_);
00348                                         currentMessage_ = 0;
00349                                 }
00350 
00351                                 // Log
00352                                 if (packetLogging_)
00353                                 {
00354                                         Logger::log(S3D::formatStringBuffer(
00355                                                 "NetServerTCP2Destination %u: Recieved a message part, %s", 
00356                                                 destinationId_,
00357                                                 (currentMessageType_ & TypeLast?"last":"not last")));
00358                                 }
00359                         }
00360                         else 
00361                         {
00362                                 Logger::log(S3D::formatStringBuffer(
00363                                         "NetServerTCP2Destination %u: Unknown message type %i received", 
00364                                         destinationId_,
00365                                         currentMessageType_));
00366                                 return SocketClosed;
00367                         }
00368 
00369                         currentMessageLen_ = 0;
00370                         currentMessagePart_.reset();
00371                 }
00372         }       
00373 
00374         return (activity?SocketActivity:SocketEmpty);
00375 }
00376 
00377 NetServerTCP2Destination::SocketResult NetServerTCP2Destination::checkOutgoing()
00378 {
00379         // See if we have any messages to send
00380         if (outgoingMessages_.empty()) return SocketEmpty;
00381 
00382         // Check to see how much to send
00383         NetMessage *message = outgoingMessages_.front();
00384         int sendAmount = message->getBuffer().getBufferUsed() - currentMessageSentLen_;
00385         if (sendAmount > 100) sendAmount = 100;
00386 
00387         if (currentMessageSentLen_ == 0)
00388         {
00389                 // Send Len
00390                 if(!sendHeader(TypeMessage | TypeLast, 
00391                         5 + message->getBuffer().getBufferUsed()))
00392                 {
00393                         return SocketClosed;
00394                 }
00395         }
00396 
00397         // Send data
00398         int result = SDLNet_TCP_Send_Wrapper(socket_, 
00399                 (void *) &message->getBuffer().getBuffer()[currentMessageSentLen_], 
00400                 sendAmount);
00401         if(result < sendAmount) // Socket Closed
00402         {
00403                 Logger::log(S3D::formatStringBuffer(
00404                         "NetServerTCP2Destination %u: Failed to send buffer %i of %i. Socket closed",
00405                         destinationId_, result, sendAmount));
00406                 return SocketClosed;
00407         }
00408 
00409         NetInterface::getBytesOut() += result;
00410         bytesOut_ += result;
00411 
00412         // Check if we have finished sending this message
00413         currentMessageSentLen_ += sendAmount;
00414         if (currentMessageSentLen_ == message->getBuffer().getBufferUsed())
00415         {
00416                 outgoingMessages_.pop_front();
00417                 currentMessageSentLen_ = 0;
00418                 incomingMessageHandler_->addMessage(message);
00419 
00420                 messagesSent_++;
00421                 if (packetLogging_)
00422                 {
00423                         Logger::log(S3D::formatStringBuffer(
00424                                 "NetServerTCP2Destination %u: Sent a message part, %s", 
00425                                 destinationId_,
00426                                 "last"));
00427                 }
00428         }
00429 
00430         return SocketActivity;
00431 }
00432 
00433 bool NetServerTCP2Destination::sendHeader(char headerType, int len)
00434 {
00435         NetMessage *ackMessage = NetMessagePool::instance()->
00436                 getFromPool(NetMessage::BufferMessage, 0, 0);
00437 
00438         // Form Header
00439         ackMessage->getBuffer().addToBuffer(headerType);
00440         ackMessage->getBuffer().addToBuffer(len);
00441 
00442         // Send Header
00443         int result = SDLNet_TCP_Send_Wrapper(socket_, 
00444                 (void *) ackMessage->getBuffer().getBuffer(), 
00445                 ackMessage->getBuffer().getBufferUsed());
00446 
00447         NetInterface::getBytesOut() += result;
00448         bytesOut_ += result;
00449 
00450         NetMessagePool::instance()->addToPool(ackMessage);
00451 
00452         if (result != ackMessage->getBuffer().getBufferUsed())
00453         {
00454                 Logger::log(S3D::formatStringBuffer(
00455                         "NetServerTCP2Destination %u: Failed to send header %i of %i. Socket closed",
00456                         destinationId_, result, ackMessage->getBuffer().getBufferUsed()));
00457         }
00458 
00459         return (result == ackMessage->getBuffer().getBufferUsed());
00460 }
00461 
00462 void NetServerTCP2Destination::printStats(unsigned int destination)
00463 {
00464         Logger::log(S3D::formatStringBuffer("TCP2 Destination %u net stats:", destination));
00465         Logger::log(S3D::formatStringBuffer("  %u messages sent, %u messages recieved",
00466                 messagesSent_, messagesRecieved_));
00467         Logger::log(S3D::formatStringBuffer("  %u bytes in, %u bytes out",
00468                 bytesIn_, bytesOut_));
00469 }

Generated on Mon Feb 16 15:14:51 2009 for Scorched3D by  doxygen 1.5.3