NetServerTCPRead.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 #include <net/NetServerTCPRead.h>
00022 #include <net/NetServerTCP.h>
00023 #include <net/NetMessagePool.h>
00024 #include <common/Clock.h>
00025 #include <common/Logger.h>
00026 #include <common/Defines.h>
00027 
00028 NetServerTCPRead::NetServerTCPRead(unsigned int id,
00029                                                          TCPsocket socket,
00030                                                          NetServerTCPProtocol *protocol,
00031                                                          NetMessageHandler *messageHandler,
00032                                                          bool *checkDeleted) : 
00033         id_(id),
00034         socket_(socket), sockSet_(0), protocol_(protocol), 
00035         outgoingMessagesMutex_(0), checkDeleted_(checkDeleted),
00036         disconnect_(false), messageHandler_(messageHandler),
00037         sentDisconnect_(false), startCount_(0),
00038         ctrlThread_(0), recvThread_(0), sendThread_(0)
00039 {
00040         sockSet_ = SDLNet_AllocSocketSet(1);
00041         SDLNet_TCP_AddSocket(sockSet_, socket);
00042         outgoingMessagesMutex_ = SDL_CreateMutex();
00043 }
00044 
00045 NetServerTCPRead::~NetServerTCPRead()
00046 {
00047         SDL_LockMutex(outgoingMessagesMutex_);
00048         while (!newMessages_.empty())
00049         {
00050                 NetMessage *message = newMessages_.front();
00051                 newMessages_.pop_front();
00052                 NetMessagePool::instance()->addToPool(message);
00053         }
00054         SDL_UnlockMutex(outgoingMessagesMutex_);
00055 
00056         SDL_DestroyMutex(outgoingMessagesMutex_);
00057         outgoingMessagesMutex_ = 0;
00058         SDLNet_FreeSocketSet(sockSet_);
00059         sockSet_ = 0;
00060 }
00061 
00062 unsigned int NetServerTCPRead::getIpAddressFromSocket(TCPsocket socket)
00063 {
00064         unsigned int addr = 0;
00065         IPaddress *address = SDLNet_TCP_GetPeerAddress(socket);
00066         if (address)
00067         {
00068                 addr = SDLNet_Read32(&address->host);
00069         }
00070         return addr;
00071 }
00072 
00073 unsigned int NetServerTCPRead::getIpAddress()
00074 {
00075         return getIpAddressFromSocket(socket_);
00076 }
00077 
00078 void NetServerTCPRead::start()
00079 {
00080         // Send the player connected notification
00081         NetMessage *message = NetMessagePool::instance()->
00082                 getFromPool(NetMessage::ConnectMessage, 
00083                 id_,
00084                 getIpAddress());
00085         messageHandler_->addMessage(message);
00086 
00087         recvThread_ = SDL_CreateThread(
00088                 NetServerTCPRead::recvThreadFunc, (void *) this);
00089         sendThread_ = SDL_CreateThread(
00090                 NetServerTCPRead::sendThreadFunc, (void *) this);
00091         ctrlThread_ = SDL_CreateThread(
00092                 NetServerTCPRead::ctrlThreadFunc, (void *) this);
00093         if (!ctrlThread_ || !recvThread_ || !sendThread_)
00094         {
00095                 Logger::log( "ERROR: Run out of threads");
00096         }
00097 }
00098 
00099 void NetServerTCPRead::addMessage(NetMessage *message)
00100 {
00101         if (message->getMessageType() != NetMessage::DisconnectMessage && 
00102                 message->getBuffer().getBuffer() == 0) 
00103         { 
00104                 DIALOG_ASSERT(0); 
00105         }
00106 
00107         SDL_LockMutex(outgoingMessagesMutex_);
00108         newMessages_.push_back(message);
00109         if (message->getMessageType() == NetMessage::DisconnectMessage &&
00110                 !sentDisconnect_)
00111         {
00112                 sentDisconnect_ = true;
00113                 NetMessage *message = NetMessagePool::instance()->
00114                         getFromPool(NetMessage::DisconnectMessage, 
00115                                 id_,
00116                                 getIpAddress());
00117                 messageHandler_->addMessage(message);
00118         }
00119         SDL_UnlockMutex(outgoingMessagesMutex_);
00120 }
00121 
00122 bool NetServerTCPRead::getDisconnect()
00123 { 
00124         SDL_LockMutex(outgoingMessagesMutex_);
00125         bool result = disconnect_;      
00126         SDL_UnlockMutex(outgoingMessagesMutex_);
00127 
00128         if (result)
00129         {
00130                 int status = 0;
00131                 SDL_WaitThread(ctrlThread_, &status);
00132         }
00133         return result; 
00134 }
00135 
00136 int NetServerTCPRead::ctrlThreadFunc(void *netServerTCPRead)
00137 {
00138         NetServerTCPRead *ns = (NetServerTCPRead *) netServerTCPRead;
00139         ns->actualCtrlThreadFunc();
00140         return 0;
00141 }
00142 
00143 int NetServerTCPRead::sendThreadFunc(void *netServerTCPRead)
00144 {
00145         NetServerTCPRead *ns = (NetServerTCPRead *) netServerTCPRead;
00146         ns->actualSendRecvThreadFunc(true);
00147         return 0;
00148 }
00149 
00150 int NetServerTCPRead::recvThreadFunc(void *netServerTCPRead)
00151 {
00152         NetServerTCPRead *ns = (NetServerTCPRead *) netServerTCPRead;
00153         ns->actualSendRecvThreadFunc(false);
00154         return 0;
00155 }
00156 
00157 void NetServerTCPRead::actualCtrlThreadFunc()
00158 {
00159         // Ensure the other threads have started
00160         bool done = false;
00161         while (!done)
00162         {
00163                 SDL_LockMutex(outgoingMessagesMutex_);
00164                 if (startCount_ == 2) done = true;
00165                 SDL_UnlockMutex(outgoingMessagesMutex_);
00166                 SDL_Delay(100);
00167         }
00168 
00169         // Wait for the other threads to end
00170         int status;
00171         SDL_WaitThread(sendThread_, &status);
00172         SDL_WaitThread(recvThread_, &status);
00173 
00174         // Tidy socket
00175         SDLNet_TCP_Close(socket_);
00176 
00177         // Delete self
00178         SDL_LockMutex(outgoingMessagesMutex_);
00179         disconnect_ = true;
00180         *checkDeleted_ = true;
00181         SDL_UnlockMutex(outgoingMessagesMutex_);
00182 }
00183 
00184 void NetServerTCPRead::actualSendRecvThreadFunc(bool send)
00185 {
00186         SDL_LockMutex(outgoingMessagesMutex_);
00187         startCount_++;
00188         SDL_UnlockMutex(outgoingMessagesMutex_);
00189 
00190         Clock netClock;
00191         while (!sentDisconnect_)
00192         {
00193                 netClock.getTimeDifference();
00194 
00195                 if (send)
00196                 {       
00197                         if (!pollOutgoing()) break;
00198                 }
00199                 else
00200                 {
00201                         if (!pollIncoming()) break;
00202                 }
00203 
00204                 float timeDiff = netClock.getTimeDifference();
00205                 if (timeDiff > 15.0f)
00206                 {
00207                         Logger::log(S3D::formatStringBuffer(
00208                                 "Warning: %s net loop took %.2f seconds, client %u", 
00209                                 (send?"Send":"Recv"),
00210                                 timeDiff, id_));
00211                 }
00212         }
00213 
00214         SDL_LockMutex(outgoingMessagesMutex_);
00215         if (!sentDisconnect_)
00216         {
00217                 sentDisconnect_ = true;
00218                 NetMessage *message = NetMessagePool::instance()->
00219                         getFromPool(NetMessage::DisconnectMessage, 
00220                                 id_,
00221                                 getIpAddress());
00222                 messageHandler_->addMessage(message);
00223         }
00224         SDL_UnlockMutex(outgoingMessagesMutex_);
00225 }
00226 
00227 bool NetServerTCPRead::pollIncoming()
00228 {
00229         int numready = SDLNet_CheckSockets(sockSet_, 100);
00230         if (numready == -1) return false;
00231         if (numready == 0)
00232         {
00233                 SDL_Delay(10);
00234                 return true;
00235         }
00236 
00237         if(SDLNet_SocketReady(socket_))
00238         {
00239                 NetMessage *message = protocol_->readBuffer(socket_, id_);
00240                 if (!message)
00241                 {
00242                         //Logger::log( "Client socket has been closed.");
00243                         return false;
00244                 }
00245                 else
00246                 {
00247                         if (!sentDisconnect_)
00248                         {
00249                                 // We have a buffer containing the message
00250                                 messageHandler_->addMessage(message);
00251                         }
00252                         else
00253                         {
00254                                 NetMessagePool::instance()->addToPool(message);
00255                         }
00256                 }
00257         }
00258 
00259         return true;
00260 }
00261 
00262 bool NetServerTCPRead::pollOutgoing()
00263 {
00264         NetMessage *message = 0;
00265         SDL_LockMutex(outgoingMessagesMutex_);
00266         if (!newMessages_.empty())
00267         {
00268                 message = newMessages_.front();
00269                 newMessages_.pop_front();
00270         }
00271         SDL_UnlockMutex(outgoingMessagesMutex_);
00272 
00273         bool result = true;
00274         if (message)
00275         {
00276                 if (message->getMessageType() == NetMessage::DisconnectMessage)
00277                 {
00278                         result = false;
00279                 }
00280                 else
00281                 {
00282                         if (!protocol_->sendBuffer(message->getBuffer(), socket_, id_))
00283                         {
00284                                 Logger::log( "Failed to send message to client");
00285                                 result = false;
00286                         }
00287                 }
00288                 message->setType(NetMessage::SentMessage);
00289                 messageHandler_->addMessage(message);
00290         }
00291         else SDL_Delay(100);
00292 
00293         return result;
00294 }

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