diff options
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/net/ea/network.cpp | 342 | ||||
-rw-r--r-- | src/net/ea/network.h | 111 | ||||
-rw-r--r-- | src/net/eathena/network.cpp | 302 | ||||
-rw-r--r-- | src/net/eathena/network.h | 63 | ||||
-rw-r--r-- | src/net/tmwa/network.cpp | 302 | ||||
-rw-r--r-- | src/net/tmwa/network.h | 63 |
8 files changed, 481 insertions, 706 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a048fa30e..322264d6b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -761,6 +761,8 @@ SET(SRCS_EVOL net/ea/itemhandler.h net/ea/loginhandler.cpp net/ea/loginhandler.h + net/ea/network.cpp + net/ea/network.h net/ea/npchandler.cpp net/ea/npchandler.h net/ea/partyhandler.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 60c1a3659..08463f6b2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -681,6 +681,8 @@ manaplus_SOURCES += \ net/ea/itemhandler.h \ net/ea/loginhandler.cpp \ net/ea/loginhandler.h \ + net/ea/network.cpp \ + net/ea/network.h \ net/ea/npchandler.cpp \ net/ea/npchandler.h \ net/ea/partyhandler.cpp \ diff --git a/src/net/ea/network.cpp b/src/net/ea/network.cpp new file mode 100644 index 000000000..ccf126a22 --- /dev/null +++ b/src/net/ea/network.cpp @@ -0,0 +1,342 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "net/ea/network.h" + +#include "configuration.h" +#include "logger.h" + +#include "net/messagehandler.h" +#include "net/messagein.h" + +#include "net/eathena/protocol.h" + +#include "utils/gettext.h" +#include "utils/stringutils.h" + +#include <assert.h> +#include <sstream> + +#include "debug.h" + +namespace Ea +{ + +const unsigned int BUFFER_SIZE = 1000000; +const unsigned int BUFFER_LIMIT = 930000; + +int networkThread(void *data) +{ + Network *network = static_cast<Network*>(data); + + if (!network || !network->realConnect()) + return -1; + + network->receive(); + + return 0; +} + +Network::Network() : + mSocket(nullptr), + mInBuffer(new char[BUFFER_SIZE]), + mOutBuffer(new char[BUFFER_SIZE]), + mInSize(0), + mOutSize(0), + mToSkip(0), + mState(IDLE), + mWorkerThread(nullptr) +{ + SDLNet_Init(); + + mMutex = SDL_CreateMutex(); +} + +Network::~Network() +{ + if (mState != IDLE && mState != NET_ERROR) + disconnect(); + + SDL_DestroyMutex(mMutex); + mMutex = nullptr; + + delete []mInBuffer; + delete []mOutBuffer; + + SDLNet_Quit(); +} + +bool Network::connect(ServerInfo server) +{ + if (mState != IDLE && mState != NET_ERROR) + { + logger->log1("Tried to connect an already connected socket!"); + assert(false); + return false; + } + + if (server.hostname.empty()) + { + setError(_("Empty address given to Network::connect()!")); + return false; + } + + logger->log("Network::Connecting to %s:%i", + server.hostname.c_str(), server.port); + + mServer.hostname = server.hostname; + mServer.port = server.port; + + // Reset to sane values + mOutSize = 0; + mInSize = 0; + mToSkip = 0; + + mState = CONNECTING; + mWorkerThread = SDL_CreateThread(networkThread, this); + if (!mWorkerThread) + { + setError("Unable to create network worker thread"); + return false; + } + + return true; +} + +void Network::disconnect() +{ + mState = IDLE; + + if (mWorkerThread && SDL_GetThreadID(mWorkerThread)) + { + SDL_WaitThread(mWorkerThread, nullptr); + mWorkerThread = nullptr; + } + + if (mSocket) + { + // need call SDLNet_TCP_DelSocket? + SDLNet_TCP_Close(mSocket); + mSocket = nullptr; + int sleep = config.getIntValue("networksleep"); + if (sleep > 0) + SDL_Delay(sleep); + } +} + +void Network::flush() +{ + if (!mOutSize || mState != CONNECTED) + return; + + int ret; + + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); + DEBUGLOG("Send " + toString(mOutSize) + " bytes"); + if (ret < static_cast<int>(mOutSize)) + { + setError("Error in SDLNet_TCP_Send(): " + + std::string(SDLNet_GetError())); + } + mOutSize = 0; + SDL_mutexV(mMutex); +} + +void Network::skip(int len) +{ + SDL_mutexP(mMutex); + mToSkip += len; + if (!mInSize) + { + SDL_mutexV(mMutex); + return; + } + + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + SDL_mutexV(mMutex); +} + +bool Network::realConnect() +{ + IPaddress ipAddress; + + if (SDLNet_ResolveHost(&ipAddress, mServer.hostname.c_str(), + mServer.port) == -1) + { + std::string errorMessage = _("Unable to resolve host \"") + + mServer.hostname + "\""; + setError(errorMessage); + logger->log("SDLNet_ResolveHost: %s", errorMessage.c_str()); + return false; + } + + mState = CONNECTING; + + mSocket = SDLNet_TCP_Open(&ipAddress); + if (!mSocket) + { + logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); + setError(SDLNet_GetError()); + return false; + } + + logger->log("Network::Started session with %s:%i", + ipToString(ipAddress.host), ipAddress.port); + + mState = CONNECTED; + + return true; +} + +void Network::receive() +{ + SDLNet_SocketSet set; + + if (!(set = SDLNet_AllocSocketSet(1))) + { + setError("Error in SDLNet_AllocSocketSet(): " + + std::string(SDLNet_GetError())); + return; + } + + if (SDLNet_TCP_AddSocket(set, mSocket) == -1) + { + setError("Error in SDLNet_AddSocket(): " + + std::string(SDLNet_GetError())); + } + + while (mState == CONNECTED) + { + // TODO Try to get this to block all the time while still being able + // to escape the loop + int numReady = SDLNet_CheckSockets(set, (static_cast<uint32_t>(500))); + int ret; + switch (numReady) + { + case -1: + logger->log1("Error: SDLNet_CheckSockets"); + // FALLTHROUGH + case 0: + break; + + case 1: + // Receive data from the socket + SDL_mutexP(mMutex); + if (mInSize > BUFFER_LIMIT) + { + SDL_mutexV(mMutex); + SDL_Delay(100); + continue; + } + + ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, + BUFFER_SIZE - mInSize); + + if (!ret) + { + // We got disconnected + mState = IDLE; + logger->log1("Disconnected."); + } + else if (ret < 0) + { + setError(_("Connection to server terminated. ") + + std::string(SDLNet_GetError())); + } + else + { +// DEBUGLOG("Receive " + toString(ret) + " bytes"); + mInSize += ret; + if (mToSkip) + { + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + } + } + SDL_mutexV(mMutex); + break; + + default: + // more than one socket is ready.. + // this should not happen since we only listen once socket. + std::stringstream errorStream; + errorStream << "Error in SDLNet_TCP_Recv(), " << numReady + << " sockets are ready: " << SDLNet_GetError(); + setError(errorStream.str()); + break; + } + } + + if (SDLNet_TCP_DelSocket(set, mSocket) == -1) + logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); + + SDLNet_FreeSocketSet(set); +} + +void Network::setError(const std::string &error) +{ + logger->log("Network error: %s", error.c_str()); + mError = error; + mState = NET_ERROR; +} + +uint16_t Network::readWord(int pos) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_Swap16((*(uint16_t*)(mInBuffer + (pos)))); +#else + return (*reinterpret_cast<uint16_t*>(mInBuffer + (pos))); +#endif +} + +void Network::fixSendBuffer() +{ + if (mOutSize > BUFFER_LIMIT) + { + if (mState != CONNECTED) + mOutSize = 0; + else + flush(); + } +} + +} // namespace EAthena diff --git a/src/net/ea/network.h b/src/net/ea/network.h new file mode 100644 index 000000000..2fe2037a9 --- /dev/null +++ b/src/net/ea/network.h @@ -0,0 +1,111 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NET_EA_NETWORK_H +#define NET_EA_NETWORK_H + +#include "net/serverinfo.h" + +#include "net/messagein.h" +#include "net/messageout.h" + +#include <SDL_net.h> +#include <SDL_thread.h> + +#include <map> +#include <string> + +namespace Ea +{ + +class Network +{ + public: + Network(); + + ~Network(); + + bool connect(ServerInfo server); + + void disconnect(); + + ServerInfo getServer() const + { return mServer; } + + int getState() const + { return mState; } + + const std::string &getError() const + { return mError; } + + bool isConnected() const + { return mState == CONNECTED; } + + int getInSize() const + { return mInSize; } + + void skip(int len); + + void flush(); + + void fixSendBuffer(); + + // ERROR replaced by NET_ERROR because already defined in Windows + enum + { + IDLE = 0, + CONNECTED, + CONNECTING, + DATA, + NET_ERROR + }; + + protected: + friend int networkThread(void *data); + + void setError(const std::string &error); + + uint16_t readWord(int pos); + + bool realConnect(); + + void receive(); + + TCPsocket mSocket; + + ServerInfo mServer; + + char *mInBuffer, *mOutBuffer; + unsigned int mInSize, mOutSize; + + unsigned int mToSkip; + + int mState; + std::string mError; + + SDL_Thread *mWorkerThread; + SDL_mutex *mMutex; +}; + +} // namespace Ea + +#endif // NET_EA_NETWORK_H diff --git a/src/net/eathena/network.cpp b/src/net/eathena/network.cpp index d01613075..5cfe0af1a 100644 --- a/src/net/eathena/network.cpp +++ b/src/net/eathena/network.cpp @@ -112,112 +112,17 @@ short packet_lengths[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -const unsigned int BUFFER_SIZE = 1000000; -const unsigned int BUFFER_LIMIT = 930000; - -int networkThread(void *data) -{ - Network *network = static_cast<Network*>(data); - - if (!network || !network->realConnect()) - return -1; - - network->receive(); - - return 0; -} - Network *Network::mInstance = nullptr; -Network::Network() : - mSocket(nullptr), - mInBuffer(new char[BUFFER_SIZE]), - mOutBuffer(new char[BUFFER_SIZE]), - mInSize(0), - mOutSize(0), - mToSkip(0), - mState(IDLE), - mWorkerThread(nullptr) +Network::Network() { - SDLNet_Init(); - - mMutex = SDL_CreateMutex(); mInstance = this; } Network::~Network() { clearHandlers(); - - if (mState != IDLE && mState != NET_ERROR) - disconnect(); - - SDL_DestroyMutex(mMutex); - mMutex = nullptr; mInstance = nullptr; - - delete []mInBuffer; - delete []mOutBuffer; - - SDLNet_Quit(); -} - -bool Network::connect(ServerInfo server) -{ - if (mState != IDLE && mState != NET_ERROR) - { - logger->log1("Tried to connect an already connected socket!"); - assert(false); - return false; - } - - if (server.hostname.empty()) - { - setError(_("Empty address given to Network::connect()!")); - return false; - } - - logger->log("Network::Connecting to %s:%i", - server.hostname.c_str(), server.port); - - mServer.hostname = server.hostname; - mServer.port = server.port; - - // Reset to sane values - mOutSize = 0; - mInSize = 0; - mToSkip = 0; - - mState = CONNECTING; - mWorkerThread = SDL_CreateThread(networkThread, this); - if (!mWorkerThread) - { - setError("Unable to create network worker thread"); - return false; - } - - return true; -} - -void Network::disconnect() -{ - mState = IDLE; - - if (mWorkerThread && SDL_GetThreadID(mWorkerThread)) - { - SDL_WaitThread(mWorkerThread, nullptr); - mWorkerThread = nullptr; - } - - if (mSocket) - { - // need call SDLNet_TCP_DelSocket? - SDLNet_TCP_Close(mSocket); - mSocket = nullptr; - int sleep = config.getIntValue("networksleep"); - if (sleep > 0) - SDL_Delay(sleep); - } } void Network::registerHandler(MessageHandler *handler) @@ -278,49 +183,6 @@ void Network::dispatchMessages() } } -void Network::flush() -{ - if (!mOutSize || mState != CONNECTED) - return; - - int ret; - - SDL_mutexP(mMutex); - ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); - DEBUGLOG("Send " + toString(mOutSize) + " bytes"); - if (ret < static_cast<int>(mOutSize)) - { - setError("Error in SDLNet_TCP_Send(): " + - std::string(SDLNet_GetError())); - } - mOutSize = 0; - SDL_mutexV(mMutex); -} - -void Network::skip(int len) -{ - SDL_mutexP(mMutex); - mToSkip += len; - if (!mInSize) - { - SDL_mutexV(mMutex); - return; - } - - if (mInSize >= mToSkip) - { - mInSize -= mToSkip; - memmove(mInBuffer, mInBuffer + mToSkip, mInSize); - mToSkip = 0; - } - else - { - mToSkip -= mInSize; - mInSize = 0; - } - SDL_mutexV(mMutex); -} - bool Network::messageReady() { int len = -1; @@ -358,11 +220,18 @@ MessageIn Network::getNextMessage() int msgId = readWord(0); int len; if (msgId == SMSG_SERVER_VERSION_RESPONSE) + { len = 10; + } else if (msgId == SMSG_UPDATE_HOST2) + { len = -1; + } else - len = packet_lengths[msgId]; + { + if (msgId >= 0 && msgId < sizeof(packet_lengths) / sizeof (short)) + len = packet_lengths[msgId]; + } if (len == -1) len = readWord(2); @@ -378,162 +247,9 @@ MessageIn Network::getNextMessage() return msg; } -bool Network::realConnect() -{ - IPaddress ipAddress; - - if (SDLNet_ResolveHost(&ipAddress, mServer.hostname.c_str(), - mServer.port) == -1) - { - std::string errorMessage = _("Unable to resolve host \"") + - mServer.hostname + "\""; - setError(errorMessage); - logger->log("SDLNet_ResolveHost: %s", errorMessage.c_str()); - return false; - } - - mState = CONNECTING; - - mSocket = SDLNet_TCP_Open(&ipAddress); - if (!mSocket) - { - logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); - setError(SDLNet_GetError()); - return false; - } - - logger->log("Network::Started session with %s:%i", - ipToString(ipAddress.host), ipAddress.port); - - mState = CONNECTED; - - return true; -} - -void Network::receive() -{ - SDLNet_SocketSet set; - - if (!(set = SDLNet_AllocSocketSet(1))) - { - setError("Error in SDLNet_AllocSocketSet(): " + - std::string(SDLNet_GetError())); - return; - } - - if (SDLNet_TCP_AddSocket(set, mSocket) == -1) - { - setError("Error in SDLNet_AddSocket(): " + - std::string(SDLNet_GetError())); - } - - while (mState == CONNECTED) - { - // TODO Try to get this to block all the time while still being able - // to escape the loop - int numReady = SDLNet_CheckSockets(set, (static_cast<uint32_t>(500))); - int ret; - switch (numReady) - { - case -1: - logger->log1("Error: SDLNet_CheckSockets"); - // FALLTHROUGH - case 0: - break; - - case 1: - // Receive data from the socket - SDL_mutexP(mMutex); - if (mInSize > BUFFER_LIMIT) - { - SDL_mutexV(mMutex); - SDL_Delay(100); - continue; - } - - ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, - BUFFER_SIZE - mInSize); - - if (!ret) - { - // We got disconnected - mState = IDLE; - logger->log1("Disconnected."); - } - else if (ret < 0) - { - setError(_("Connection to server terminated. ") + - std::string(SDLNet_GetError())); - } - else - { -// DEBUGLOG("Receive " + toString(ret) + " bytes"); - mInSize += ret; - if (mToSkip) - { - if (mInSize >= mToSkip) - { - mInSize -= mToSkip; - memmove(mInBuffer, mInBuffer + mToSkip, mInSize); - mToSkip = 0; - } - else - { - mToSkip -= mInSize; - mInSize = 0; - } - } - } - SDL_mutexV(mMutex); - break; - - default: - // more than one socket is ready.. - // this should not happen since we only listen once socket. - std::stringstream errorStream; - errorStream << "Error in SDLNet_TCP_Recv(), " << numReady - << " sockets are ready: " << SDLNet_GetError(); - setError(errorStream.str()); - break; - } - } - - if (SDLNet_TCP_DelSocket(set, mSocket) == -1) - logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); - - SDLNet_FreeSocketSet(set); -} - Network *Network::instance() { return mInstance; } -void Network::setError(const std::string &error) -{ - logger->log("Network error: %s", error.c_str()); - mError = error; - mState = NET_ERROR; -} - -uint16_t Network::readWord(int pos) -{ -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap16((*(uint16_t*)(mInBuffer + (pos)))); -#else - return (*reinterpret_cast<uint16_t*>(mInBuffer + (pos))); -#endif -} - -void Network::fixSendBuffer() -{ - if (mOutSize > BUFFER_LIMIT) - { - if (mState != CONNECTED) - mOutSize = 0; - else - flush(); - } -} - } // namespace EAthena diff --git a/src/net/eathena/network.h b/src/net/eathena/network.h index 1fdcf7c6e..0ce8591ff 100644 --- a/src/net/eathena/network.h +++ b/src/net/eathena/network.h @@ -23,6 +23,8 @@ #ifndef NET_EATHENA_NETWORK_H #define NET_EATHENA_NETWORK_H +#include "net/ea/network.h" + #include "net/serverinfo.h" #include "net/eathena/messagehandler.h" @@ -44,89 +46,30 @@ namespace EAthena { -class Network +class Network : public Ea::Network { public: Network(); ~Network(); - bool connect(ServerInfo server); - - void disconnect(); - - ServerInfo getServer() const - { return mServer; } - void registerHandler(MessageHandler *handler); void unregisterHandler(MessageHandler *handler); void clearHandlers(); - int getState() const - { return mState; } - - const std::string &getError() const - { return mError; } - - bool isConnected() const - { return mState == CONNECTED; } - - int getInSize() const - { return mInSize; } - - void skip(int len); - bool messageReady(); MessageIn getNextMessage(); void dispatchMessages(); - void flush(); - - void fixSendBuffer(); - - // ERROR replaced by NET_ERROR because already defined in Windows - enum - { - IDLE = 0, - CONNECTED, - CONNECTING, - DATA, - NET_ERROR - }; - protected: - friend int networkThread(void *data); friend class MessageOut; static Network *instance(); - void setError(const std::string &error); - - uint16_t readWord(int pos); - - bool realConnect(); - - void receive(); - - TCPsocket mSocket; - - ServerInfo mServer; - - char *mInBuffer, *mOutBuffer; - unsigned int mInSize, mOutSize; - - unsigned int mToSkip; - - int mState; - std::string mError; - - SDL_Thread *mWorkerThread; - SDL_mutex *mMutex; - typedef std::map<uint16_t, MessageHandler*> MessageHandlers; typedef MessageHandlers::iterator MessageHandlerIterator; MessageHandlers mMessageHandlers; diff --git a/src/net/tmwa/network.cpp b/src/net/tmwa/network.cpp index 4f2f85a51..98f6485a7 100644 --- a/src/net/tmwa/network.cpp +++ b/src/net/tmwa/network.cpp @@ -90,112 +90,17 @@ short packet_lengths[] = -1, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -const unsigned int BUFFER_SIZE = 1000000; -const unsigned int BUFFER_LIMIT = 930000; - -int networkThread(void *data) -{ - Network *network = static_cast<Network*>(data); - - if (!network || !network->realConnect()) - return -1; - - network->receive(); - - return 0; -} - Network *Network::mInstance = nullptr; -Network::Network() : - mSocket(nullptr), - mInBuffer(new char[BUFFER_SIZE]), - mOutBuffer(new char[BUFFER_SIZE]), - mInSize(0), - mOutSize(0), - mToSkip(0), - mState(IDLE), - mWorkerThread(nullptr) +Network::Network() { - SDLNet_Init(); - - mMutex = SDL_CreateMutex(); mInstance = this; } Network::~Network() { clearHandlers(); - - if (mState != IDLE && mState != NET_ERROR) - disconnect(); - - SDL_DestroyMutex(mMutex); - mMutex = nullptr; mInstance = nullptr; - - delete []mInBuffer; - delete []mOutBuffer; - - SDLNet_Quit(); -} - -bool Network::connect(ServerInfo server) -{ - if (mState != IDLE && mState != NET_ERROR) - { - logger->log1("Tried to connect an already connected socket!"); - assert(false); - return false; - } - - if (server.hostname.empty()) - { - setError(_("Empty address given to Network::connect()!")); - return false; - } - - logger->log("Network::Connecting to %s:%i", - server.hostname.c_str(), server.port); - - mServer.hostname = server.hostname; - mServer.port = server.port; - - // Reset to sane values - mOutSize = 0; - mInSize = 0; - mToSkip = 0; - - mState = CONNECTING; - mWorkerThread = SDL_CreateThread(networkThread, this); - if (!mWorkerThread) - { - setError("Unable to create network worker thread"); - return false; - } - - return true; -} - -void Network::disconnect() -{ - mState = IDLE; - - if (mWorkerThread && SDL_GetThreadID(mWorkerThread)) - { - SDL_WaitThread(mWorkerThread, nullptr); - mWorkerThread = nullptr; - } - - if (mSocket) - { - // need call SDLNet_TCP_DelSocket? - SDLNet_TCP_Close(mSocket); - mSocket = nullptr; - int sleep = config.getIntValue("networksleep"); - if (sleep > 0) - SDL_Delay(sleep); - } } void Network::registerHandler(MessageHandler *handler) @@ -256,49 +161,6 @@ void Network::dispatchMessages() } } -void Network::flush() -{ - if (!mOutSize || mState != CONNECTED) - return; - - int ret; - - SDL_mutexP(mMutex); - ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); - DEBUGLOG("Send " + toString(mOutSize) + " bytes"); - if (ret < static_cast<int>(mOutSize)) - { - setError("Error in SDLNet_TCP_Send(): " + - std::string(SDLNet_GetError())); - } - mOutSize = 0; - SDL_mutexV(mMutex); -} - -void Network::skip(int len) -{ - SDL_mutexP(mMutex); - mToSkip += len; - if (!mInSize) - { - SDL_mutexV(mMutex); - return; - } - - if (mInSize >= mToSkip) - { - mInSize -= mToSkip; - memmove(mInBuffer, mInBuffer + mToSkip, mInSize); - mToSkip = 0; - } - else - { - mToSkip -= mInSize; - mInSize = 0; - } - SDL_mutexV(mMutex); -} - bool Network::messageReady() { int len = -1; @@ -308,11 +170,18 @@ bool Network::messageReady() { int msgId = readWord(0); if (msgId == SMSG_SERVER_VERSION_RESPONSE) + { len = 10; + } else if (msgId == SMSG_UPDATE_HOST2) + { len = -1; + } else - len = packet_lengths[msgId]; + { + if (msgId >= 0 && msgId < sizeof(packet_lengths) / sizeof (short)) + len = packet_lengths[msgId]; + } if (len == -1 && mInSize > 4) len = readWord(2); @@ -356,162 +225,9 @@ MessageIn Network::getNextMessage() return msg; } -bool Network::realConnect() -{ - IPaddress ipAddress; - - if (SDLNet_ResolveHost(&ipAddress, mServer.hostname.c_str(), - mServer.port) == -1) - { - std::string errorMessage = _("Unable to resolve host \"") + - mServer.hostname + "\""; - setError(errorMessage); - logger->log("SDLNet_ResolveHost: %s", errorMessage.c_str()); - return false; - } - - mState = CONNECTING; - - mSocket = SDLNet_TCP_Open(&ipAddress); - if (!mSocket) - { - logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); - setError(SDLNet_GetError()); - return false; - } - - logger->log("Network::Started session with %s:%i", - ipToString(ipAddress.host), ipAddress.port); - - mState = CONNECTED; - - return true; -} - -void Network::receive() -{ - SDLNet_SocketSet set; - - if (!(set = SDLNet_AllocSocketSet(1))) - { - setError("Error in SDLNet_AllocSocketSet(): " + - std::string(SDLNet_GetError())); - return; - } - - if (SDLNet_TCP_AddSocket(set, mSocket) == -1) - { - setError("Error in SDLNet_AddSocket(): " + - std::string(SDLNet_GetError())); - } - - while (mState == CONNECTED) - { - // TODO Try to get this to block all the time while still being able - // to escape the loop - int numReady = SDLNet_CheckSockets(set, (static_cast<uint32_t>(500))); - int ret; - switch (numReady) - { - case -1: - logger->log1("Error: SDLNet_CheckSockets"); - // FALLTHROUGH - case 0: - break; - - case 1: - // Receive data from the socket - SDL_mutexP(mMutex); - if (mInSize > BUFFER_LIMIT) - { - SDL_mutexV(mMutex); - SDL_Delay(100); - continue; - } - - ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, - BUFFER_SIZE - mInSize); - - if (!ret) - { - // We got disconnected - mState = IDLE; - logger->log1("Disconnected."); - } - else if (ret < 0) - { - setError(_("Connection to server terminated. ") + - std::string(SDLNet_GetError())); - } - else - { -// DEBUGLOG("Receive " + toString(ret) + " bytes"); - mInSize += ret; - if (mToSkip) - { - if (mInSize >= mToSkip) - { - mInSize -= mToSkip; - memmove(mInBuffer, mInBuffer + mToSkip, mInSize); - mToSkip = 0; - } - else - { - mToSkip -= mInSize; - mInSize = 0; - } - } - } - SDL_mutexV(mMutex); - break; - - default: - // more than one socket is ready.. - // this should not happen since we only listen once socket. - std::stringstream errorStream; - errorStream << "Error in SDLNet_TCP_Recv(), " << numReady - << " sockets are ready: " << SDLNet_GetError(); - setError(errorStream.str()); - break; - } - } - - if (SDLNet_TCP_DelSocket(set, mSocket) == -1) - logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); - - SDLNet_FreeSocketSet(set); -} - Network *Network::instance() { return mInstance; } -void Network::setError(const std::string &error) -{ - logger->log("Network error: %s", error.c_str()); - mError = error; - mState = NET_ERROR; -} - -uint16_t Network::readWord(int pos) -{ -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - return SDL_Swap16((*(uint16_t*)(mInBuffer + (pos)))); -#else - return (*reinterpret_cast<uint16_t*>(mInBuffer + (pos))); -#endif -} - -void Network::fixSendBuffer() -{ - if (mOutSize > BUFFER_LIMIT) - { - if (mState != CONNECTED) - mOutSize = 0; - else - flush(); - } -} - } // namespace TmwAthena diff --git a/src/net/tmwa/network.h b/src/net/tmwa/network.h index cc7ae129b..b110b7fb9 100644 --- a/src/net/tmwa/network.h +++ b/src/net/tmwa/network.h @@ -23,6 +23,8 @@ #ifndef NET_TA_NETWORK_H #define NET_TA_NETWORK_H +#include "net/ea/network.h" + #include "net/serverinfo.h" #include "net/tmwa/messagehandler.h" @@ -45,89 +47,30 @@ namespace TmwAthena { -class Network +class Network : public Ea::Network { public: Network(); ~Network(); - bool connect(ServerInfo server); - - void disconnect(); - - ServerInfo getServer() const - { return mServer; } - void registerHandler(MessageHandler *handler); void unregisterHandler(MessageHandler *handler); void clearHandlers(); - int getState() const - { return mState; } - - const std::string &getError() const - { return mError; } - - bool isConnected() const - { return mState == CONNECTED; } - - int getInSize() const - { return mInSize; } - - void skip(int len); - bool messageReady(); MessageIn getNextMessage(); void dispatchMessages(); - void flush(); - - void fixSendBuffer(); - - // ERROR replaced by NET_ERROR because already defined in Windows - enum - { - IDLE = 0, - CONNECTED, - CONNECTING, - DATA, - NET_ERROR - }; - protected: - friend int networkThread(void *data); friend class MessageOut; static Network *instance(); - void setError(const std::string &error); - - uint16_t readWord(int pos); - - bool realConnect(); - - void receive(); - - TCPsocket mSocket; - - ServerInfo mServer; - - char *mInBuffer, *mOutBuffer; - unsigned int mInSize, mOutSize; - - unsigned int mToSkip; - - int mState; - std::string mError; - - SDL_Thread *mWorkerThread; - SDL_mutex *mMutex; - typedef std::map<uint16_t, MessageHandler*> MessageHandlers; typedef MessageHandlers::iterator MessageHandlerIterator; MessageHandlers mMessageHandlers; |