From 193034f09cd878421385d88d09e7fdeccb304980 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 16 Jul 2018 20:51:30 +0800 Subject: [PATCH 1/4] [Documentation] Add copyrigts --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index be15305d8..8d03a7db5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ TES3MP ====== +Copyright (c) 2008-2015, OpenMW Team +Copyright (c) 2016-2018, TES3MP Team + [![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp) TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), an open-source game engine that supports playing "The Elder Scrolls III: Morrowind" by Bethesda Softworks. From 1a9bf253f6ce17d482eebf39030042f54bb1d5cc Mon Sep 17 00:00:00 2001 From: Koncord Date: Tue, 17 Jul 2018 00:29:45 +0800 Subject: [PATCH 2/4] [Server] Simplify getPlayer methods, add isPlayerExists method --- apps/openmw-mp/Player.cpp | 15 +++++++++++---- apps/openmw-mp/Player.hpp | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/openmw-mp/Player.cpp b/apps/openmw-mp/Player.cpp index 6e66f8151..fb94a6159 100644 --- a/apps/openmw-mp/Player.cpp +++ b/apps/openmw-mp/Player.cpp @@ -54,9 +54,10 @@ void Players::newPlayer(RakNet::RakNetGUID guid) Player *Players::getPlayer(RakNet::RakNetGUID guid) { - if (players.count(guid) == 0) + auto it = players.find(guid); + if (it == players.end()) return nullptr; - return players[guid]; + return it->second; } TPlayers *Players::getPlayers() @@ -123,9 +124,10 @@ int Player::getLoadState() Player *Players::getPlayer(unsigned short id) { - if (slots.find(id) == slots.end()) + auto it = slots.find(id); + if (it == slots.end()) return nullptr; - return slots[id]; + return it->second; } CellController::TContainer *Player::getCells() @@ -174,3 +176,8 @@ void Player::forEachLoaded(std::function func) func(this, pl); } } + +bool Players::isPlayerExists(RakNet::RakNetGUID guid) +{ + return players.find(guid) != players.end(); +} diff --git a/apps/openmw-mp/Player.hpp b/apps/openmw-mp/Player.hpp index a956a4a52..487719343 100644 --- a/apps/openmw-mp/Player.hpp +++ b/apps/openmw-mp/Player.hpp @@ -34,6 +34,7 @@ public: static Player *getPlayer(unsigned short id); static TPlayers *getPlayers(); static unsigned short getLastPlayerId(); + static bool isPlayerExists(RakNet::RakNetGUID guid); private: static TPlayers players; From b5c957c473ffc924f72f4650d458994a0341bf48 Mon Sep 17 00:00:00 2001 From: Koncord Date: Tue, 17 Jul 2018 00:58:37 +0800 Subject: [PATCH 3/4] [Server] Move PreInit code to preInit method --- apps/openmw-mp/Networking.cpp | 145 ++++++++++++++++++---------------- apps/openmw-mp/Networking.hpp | 3 +- 2 files changed, 77 insertions(+), 71 deletions(-) diff --git a/apps/openmw-mp/Networking.cpp b/apps/openmw-mp/Networking.cpp index 41780a00c..1d622ff3f 100644 --- a/apps/openmw-mp/Networking.cpp +++ b/apps/openmw-mp/Networking.cpp @@ -212,88 +212,84 @@ void Networking::processWorldstatePacket(RakNet::Packet *packet) } -void Networking::update(RakNet::Packet *packet) +bool Networking::preInit(RakNet::Packet *packet, RakNet::BitStream &bsIn) { - Player *player = Players::getPlayer(packet->guid); - - RakNet::BitStream bsIn(&packet->data[1], packet->length, false); - - bsIn.IgnoreBytes((unsigned int) RakNet::RakNetGUID::size()); // Ignore GUID from received packet - - if (player == nullptr) + if (packet->data[0] != ID_GAME_PREINIT) { - if (packet->data[0] == ID_GAME_PREINIT) - { - DEBUG_PRINTF("ID_GAME_PREINIT"); - PacketPreInit::PluginContainer plugins; + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "%s sent wrong first packet (ID_GAME_PREINIT was expected)", + packet->systemAddress.ToString()); + peer->CloseConnection(packet->systemAddress, true); + } - PacketPreInit packetPreInit(peer); - packetPreInit.SetReadStream(&bsIn); - packetPreInit.setChecksums(&plugins); - packetPreInit.Read(); + DEBUG_PRINTF("ID_GAME_PREINIT"); + PacketPreInit::PluginContainer plugins; - if (!packetPreInit.isPacketValid()) - { - LOG_APPEND(Log::LOG_ERROR, "Invalid packetPreInit"); - peer->CloseConnection(packet->systemAddress, false); // close connection without notification - return; - } + PacketPreInit packetPreInit(peer); + packetPreInit.SetReadStream(&bsIn); + packetPreInit.setChecksums(&plugins); + packetPreInit.Read(); - auto plugin = plugins.begin(); - if (samples.size() == plugins.size()) - { - for (int i = 0; plugin != plugins.end(); plugin++, i++) - { - LOG_APPEND(Log::LOG_VERBOSE, "- %X\t%s", plugin->second[0], plugin->first.c_str()); - // Check if the filenames match, ignoring case - if (Misc::StringUtils::ciEqual(samples[i].first, plugin->first)) - { - auto &hashList = samples[i].second; - // Proceed if no checksums have been listed for this plugin on the server - if (hashList.empty()) - continue; - auto it = find(hashList.begin(), hashList.end(), plugin->second[0]); - // Break the loop if the client's checksum isn't among those accepted by - // the server - if (it == hashList.end()) - break; - - } - else // name is incorrect - break; - } - } - RakNet::BitStream bs; - packetPreInit.SetSendStream(&bs); + if (!packetPreInit.isPacketValid()) + { + LOG_APPEND(Log::LOG_ERROR, "Invalid packetPreInit"); + peer->CloseConnection(packet->systemAddress, false); // close connection without notification + return false; + } - // If the loop above was broken, then the client's plugins do not match the server's - if (pluginEnforcementState && plugin != plugins.end()) - { - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "%s was not allowed to connect due to incompatible plugins", packet->systemAddress.ToString()); - packetPreInit.setChecksums(&samples); - packetPreInit.Send(packet->systemAddress); - peer->CloseConnection(packet->systemAddress, true); - } - else + auto plugin = plugins.begin(); + if (samples.size() == plugins.size()) + { + for (int i = 0; plugin != plugins.end(); plugin++, i++) + { + LOG_APPEND(Log::LOG_VERBOSE, "- %X\t%s", plugin->second[0], plugin->first.c_str()); + // Check if the filenames match, ignoring case + if (Misc::StringUtils::ciEqual(samples[i].first, plugin->first)) { - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "%s was allowed to connect", packet->systemAddress.ToString()); - PacketPreInit::PluginContainer tmp; - packetPreInit.setChecksums(&tmp); - packetPreInit.Send(packet->systemAddress); + auto &hashList = samples[i].second; + // Proceed if no checksums have been listed for this plugin on the server + if (hashList.empty()) + continue; + auto it = find(hashList.begin(), hashList.end(), plugin->second[0]); + // Break the loop if the client's checksum isn't among those accepted by + // the server + if (it == hashList.end()) + break; } - return; + else // name is incorrect + break; } + } + RakNet::BitStream bs; + packetPreInit.SetSendStream(&bs); - playerPacketController->SetStream(&bsIn, 0); - + // If the loop above was broken, then the client's plugins do not match the server's + if (pluginEnforcementState && plugin != plugins.end()) + { + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "%s was not allowed to connect due to incompatible plugins", packet->systemAddress.ToString()); + packetPreInit.setChecksums(&samples); + packetPreInit.Send(packet->systemAddress); + peer->CloseConnection(packet->systemAddress, true); + } + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "%s was allowed to connect", packet->systemAddress.ToString()); + PacketPreInit::PluginContainer tmp; + packetPreInit.setChecksums(&tmp); + packetPreInit.Send(packet->systemAddress); + Players::newPlayer(packet->guid); // create player if connection allowed + playerPacketController->SetStream(&bsIn, nullptr); // and request handshake playerPacketController->GetPacket(ID_HANDSHAKE)->RequestData(packet->guid); - Players::newPlayer(packet->guid); - player = Players::getPlayer(packet->guid); - return; + return true; } - else if (playerPacketController->ContainsPacket(packet->data[0])) + + return false; +} + +void Networking::update(RakNet::Packet *packet, RakNet::BitStream &bsIn) +{ + if (playerPacketController->ContainsPacket(packet->data[0])) { - playerPacketController->SetStream(&bsIn, 0); + playerPacketController->SetStream(&bsIn, nullptr); processPlayerPacket(packet); } else if (actorPacketController->ContainsPacket(packet->data[0])) @@ -531,8 +527,17 @@ int Networking::mainLoop() case ID_UNCONNECTED_PING: break; default: - update(packet); + { + RakNet::BitStream bsIn(&packet->data[1], packet->length, false); + bsIn.IgnoreBytes((unsigned int) RakNet::RakNetGUID::size()); // Ignore GUID from received packet + + + if (Players::isPlayerExists(packet->guid)) + update(packet, bsIn); + else + preInit(packet, bsIn); break; + } } } TimerAPI::Tick(); diff --git a/apps/openmw-mp/Networking.hpp b/apps/openmw-mp/Networking.hpp index c1c003315..3b1801d4c 100644 --- a/apps/openmw-mp/Networking.hpp +++ b/apps/openmw-mp/Networking.hpp @@ -29,7 +29,7 @@ namespace mwmp void processActorPacket(RakNet::Packet *packet); void processObjectPacket(RakNet::Packet *packet); void processWorldstatePacket(RakNet::Packet *packet); - void update(RakNet::Packet *packet); + void update(RakNet::Packet *packet, RakNet::BitStream &bsIn); unsigned short numberOfConnections() const; unsigned int maxConnections() const; @@ -65,6 +65,7 @@ namespace mwmp void postInit(); private: + bool preInit(RakNet::Packet *packet, RakNet::BitStream &bsIn); PacketPreInit::PluginContainer getPluginListSample(); std::string serverPassword; static Networking *sThis; From 2e227c7af5a75574451c5c1dee49ead7179561f4 Mon Sep 17 00:00:00 2001 From: Koncord Date: Tue, 17 Jul 2018 01:07:56 +0800 Subject: [PATCH 4/4] [Server] Do not allow to connect with an empty plugin list --- apps/openmw-mp/Networking.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw-mp/Networking.cpp b/apps/openmw-mp/Networking.cpp index 1d622ff3f..2319ab799 100644 --- a/apps/openmw-mp/Networking.cpp +++ b/apps/openmw-mp/Networking.cpp @@ -229,7 +229,7 @@ bool Networking::preInit(RakNet::Packet *packet, RakNet::BitStream &bsIn) packetPreInit.setChecksums(&plugins); packetPreInit.Read(); - if (!packetPreInit.isPacketValid()) + if (!packetPreInit.isPacketValid() || plugins.empty()) { LOG_APPEND(Log::LOG_ERROR, "Invalid packetPreInit"); peer->CloseConnection(packet->systemAddress, false); // close connection without notification