diff options
Diffstat (limited to 'src/network')
| -rw-r--r-- | src/network/clientpackethandler.cpp | 98 | ||||
| -rw-r--r-- | src/network/networkexceptions.h | 8 | ||||
| -rw-r--r-- | src/network/networkpacket.cpp | 49 | ||||
| -rw-r--r-- | src/network/networkpacket.h | 2 | ||||
| -rw-r--r-- | src/network/serverpackethandler.cpp | 109 |
5 files changed, 146 insertions, 120 deletions
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 55f85571d..2fea03fbf 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -450,10 +450,10 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt) string initialization data } */ - + LocalPlayer *player = m_env.getLocalPlayer(); - bool try_reattach = player && player->isWaitingForReattach(); - + bool try_reattach = player && player->isWaitingForReattach(); + try { u8 type; u16 removed_count, added_count, id; @@ -596,13 +596,13 @@ void Client::handleCommand_Breath(NetworkPacket* pkt) } void Client::handleCommand_MovePlayer(NetworkPacket* pkt) -{ +{ LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); if ((player->getCAO() && player->getCAO()->getParentId()) || player->isWaitingForReattach()) return; - + v3f pos; f32 pitch, yaw; @@ -622,10 +622,10 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt) it would just force the pitch and yaw values to whatever the camera points to. */ - + if (g_settings->getBool("no_force_rotate")) return; - + ClientEvent *event = new ClientEvent(); event->type = CE_PLAYER_FORCE_MOVE; event->player_force_move.pitch = pitch; @@ -833,12 +833,12 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt) *pkt >> pitch; *pkt >> ephemeral; } catch (PacketError &e) {}; - + SimpleSoundSpec sound_spec(name, gain, fade, pitch); - + if (m_mods_loaded && m_script->on_play_sound(sound_spec)) return; - + // Start playing int client_id = -1; switch(type) { @@ -987,10 +987,10 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt) ClientEvent *event = new ClientEvent(); event->type = CE_SPAWN_PARTICLE; event->spawn_particle = new ParticleParameters(p); - + if (m_mods_loaded && m_script->on_spawn_particle(*event->spawn_particle)) return; - + m_client_event_queue.push(event); } @@ -1063,9 +1063,6 @@ void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt) void Client::handleCommand_HudAdd(NetworkPacket* pkt) { - std::string datastring(pkt->getString(0), pkt->getSize()); - std::istringstream is(datastring, std::ios_base::binary); - u32 server_id; u8 type; v2f pos; @@ -1092,22 +1089,23 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) } catch(PacketError &e) {}; ClientEvent *event = new ClientEvent(); - event->type = CE_HUDADD; - event->hudadd.server_id = server_id; - event->hudadd.type = type; - event->hudadd.pos = new v2f(pos); - event->hudadd.name = new std::string(name); - event->hudadd.scale = new v2f(scale); - event->hudadd.text = new std::string(text); - event->hudadd.number = number; - event->hudadd.item = item; - event->hudadd.dir = dir; - event->hudadd.align = new v2f(align); - event->hudadd.offset = new v2f(offset); - event->hudadd.world_pos = new v3f(world_pos); - event->hudadd.size = new v2s32(size); - event->hudadd.z_index = z_index; - event->hudadd.text2 = new std::string(text2); + event->type = CE_HUDADD; + event->hudadd = new ClientEventHudAdd(); + event->hudadd->server_id = server_id; + event->hudadd->type = type; + event->hudadd->pos = pos; + event->hudadd->name = name; + event->hudadd->scale = scale; + event->hudadd->text = text; + event->hudadd->number = number; + event->hudadd->item = item; + event->hudadd->dir = dir; + event->hudadd->align = align; + event->hudadd->offset = offset; + event->hudadd->world_pos = world_pos; + event->hudadd->size = size; + event->hudadd->z_index = z_index; + event->hudadd->text2 = text2; m_client_event_queue.push(event); } @@ -1117,16 +1115,10 @@ void Client::handleCommand_HudRemove(NetworkPacket* pkt) *pkt >> server_id; - auto i = m_hud_server_to_client.find(server_id); - if (i != m_hud_server_to_client.end()) { - int client_id = i->second; - m_hud_server_to_client.erase(i); - - ClientEvent *event = new ClientEvent(); - event->type = CE_HUDRM; - event->hudrm.id = client_id; - m_client_event_queue.push(event); - } + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDRM; + event->hudrm.id = server_id; + m_client_event_queue.push(event); } void Client::handleCommand_HudChange(NetworkPacket* pkt) @@ -1153,19 +1145,17 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt) else *pkt >> intdata; - std::unordered_map<u32, u32>::const_iterator i = m_hud_server_to_client.find(server_id); - if (i != m_hud_server_to_client.end()) { - ClientEvent *event = new ClientEvent(); - event->type = CE_HUDCHANGE; - event->hudchange.id = i->second; - event->hudchange.stat = (HudElementStat)stat; - event->hudchange.v2fdata = new v2f(v2fdata); - event->hudchange.v3fdata = new v3f(v3fdata); - event->hudchange.sdata = new std::string(sdata); - event->hudchange.data = intdata; - event->hudchange.v2s32data = new v2s32(v2s32data); - m_client_event_queue.push(event); - } + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDCHANGE; + event->hudchange = new ClientEventHudChange(); + event->hudchange->id = server_id; + event->hudchange->stat = static_cast<HudElementStat>(stat); + event->hudchange->v2fdata = v2fdata; + event->hudchange->v3fdata = v3fdata; + event->hudchange->sdata = sdata; + event->hudchange->data = intdata; + event->hudchange->v2s32data = v2s32data; + m_client_event_queue.push(event); } void Client::handleCommand_HudSetFlags(NetworkPacket* pkt) diff --git a/src/network/networkexceptions.h b/src/network/networkexceptions.h index f4913928c..58a3bb490 100644 --- a/src/network/networkexceptions.h +++ b/src/network/networkexceptions.h @@ -56,12 +56,6 @@ public: InvalidIncomingDataException(const char *s) : BaseException(s) {} }; -class InvalidOutgoingDataException : public BaseException -{ -public: - InvalidOutgoingDataException(const char *s) : BaseException(s) {} -}; - class NoIncomingDataException : public BaseException { public: @@ -103,4 +97,4 @@ class SendFailedException : public BaseException { public: SendFailedException(const std::string &s) : BaseException(s) {} -};
\ No newline at end of file +}; diff --git a/src/network/networkpacket.cpp b/src/network/networkpacket.cpp index 6d0abb12c..a71e26572 100644 --- a/src/network/networkpacket.cpp +++ b/src/network/networkpacket.cpp @@ -50,7 +50,7 @@ void NetworkPacket::checkReadOffset(u32 from_offset, u32 field_size) } } -void NetworkPacket::putRawPacket(u8 *data, u32 datasize, session_t peer_id) +void NetworkPacket::putRawPacket(const u8 *data, u32 datasize, session_t peer_id) { // If a m_command is already set, we are rewriting on same packet // This is not permitted @@ -145,6 +145,8 @@ void NetworkPacket::putLongString(const std::string &src) putRawString(src.c_str(), msgsize); } +static constexpr bool NEED_SURROGATE_CODING = sizeof(wchar_t) > 2; + NetworkPacket& NetworkPacket::operator>>(std::wstring& dst) { checkReadOffset(m_read_offset, 2); @@ -160,9 +162,16 @@ NetworkPacket& NetworkPacket::operator>>(std::wstring& dst) checkReadOffset(m_read_offset, strLen * 2); dst.reserve(strLen); - for(u16 i=0; i<strLen; i++) { - wchar_t c16 = readU16(&m_data[m_read_offset]); - dst.append(&c16, 1); + for (u16 i = 0; i < strLen; i++) { + wchar_t c = readU16(&m_data[m_read_offset]); + if (NEED_SURROGATE_CODING && c >= 0xD800 && c < 0xDC00 && i+1 < strLen) { + i++; + m_read_offset += sizeof(u16); + + wchar_t c2 = readU16(&m_data[m_read_offset]); + c = 0x10000 + ( ((c & 0x3ff) << 10) | (c2 & 0x3ff) ); + } + dst.push_back(c); m_read_offset += sizeof(u16); } @@ -175,15 +184,37 @@ NetworkPacket& NetworkPacket::operator<<(const std::wstring &src) throw PacketError("String too long"); } - u16 msgsize = src.size(); + if (!NEED_SURROGATE_CODING || src.size() == 0) { + *this << static_cast<u16>(src.size()); + for (u16 i = 0; i < src.size(); i++) + *this << static_cast<u16>(src[i]); - *this << msgsize; + return *this; + } - // Write string - for (u16 i=0; i<msgsize; i++) { - *this << (u16) src[i]; + // write dummy value, to be overwritten later + const u32 len_offset = m_read_offset; + u32 written = 0; + *this << static_cast<u16>(0xfff0); + + for (u16 i = 0; i < src.size(); i++) { + wchar_t c = src[i]; + if (c > 0xffff) { + // Encode high code-points as surrogate pairs + u32 n = c - 0x10000; + *this << static_cast<u16>(0xD800 | (n >> 10)) + << static_cast<u16>(0xDC00 | (n & 0x3ff)); + written += 2; + } else { + *this << static_cast<u16>(c); + written++; + } } + if (written > WIDE_STRING_MAX_LEN) + throw PacketError("String too long"); + writeU16(&m_data[len_offset], written); + return *this; } diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h index e77bfb744..c7ff03b8e 100644 --- a/src/network/networkpacket.h +++ b/src/network/networkpacket.h @@ -34,7 +34,7 @@ public: ~NetworkPacket(); - void putRawPacket(u8 *data, u32 datasize, session_t peer_id); + void putRawPacket(const u8 *data, u32 datasize, session_t peer_id); void clear(); // Getters diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index c636d01e1..708ddbf20 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -56,12 +56,12 @@ void Server::handleCommand_Init(NetworkPacket* pkt) session_t peer_id = pkt->getPeerId(); RemoteClient *client = getClient(peer_id, CS_Created); + Address addr; std::string addr_s; try { - Address address = getPeerAddress(peer_id); - addr_s = address.serializeString(); - } - catch (con::PeerNotFoundException &e) { + addr = m_con->GetPeerAddress(peer_id); + addr_s = addr.serializeString(); + } catch (con::PeerNotFoundException &e) { /* * no peer for this packet found * most common reason is peer timeout, e.g. peer didn't @@ -73,13 +73,14 @@ void Server::handleCommand_Init(NetworkPacket* pkt) return; } - // If net_proto_version is set, this client has already been handled if (client->getState() > CS_Created) { verbosestream << "Server: Ignoring multiple TOSERVER_INITs from " << addr_s << " (peer_id=" << peer_id << ")" << std::endl; return; } + client->setCachedAddress(addr); + verbosestream << "Server: Got TOSERVER_INIT from " << addr_s << " (peer_id=" << peer_id << ")" << std::endl; @@ -173,6 +174,16 @@ void Server::handleCommand_Init(NetworkPacket* pkt) return; } + RemotePlayer *player = m_env->getPlayer(playername); + + // If player is already connected, cancel + if (player && player->getPeerId() != PEER_ID_INEXISTENT) { + actionstream << "Server: Player with name \"" << playername << + "\" tried to connect, but player with same name is already connected" << std::endl; + DenyAccess(peer_id, SERVER_ACCESSDENIED_ALREADY_CONNECTED); + return; + } + m_clients.setPlayerName(peer_id, playername); //TODO (later) case insensitivity @@ -437,18 +448,20 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt) u8 count; *pkt >> count; - RemoteClient *client = getClient(pkt->getPeerId()); - if ((s16)pkt->getSize() < 1 + (int)count * 6) { throw con::InvalidIncomingDataException ("GOTBLOCKS length is too short"); } + m_clients.lock(); + RemoteClient *client = m_clients.lockedGetClientNoEx(pkt->getPeerId()); + for (u16 i = 0; i < count; i++) { v3s16 p; *pkt >> p; client->GotBlock(p); } + m_clients.unlock(); } void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao, @@ -485,8 +498,12 @@ void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao, pitch = modulo360f(pitch); yaw = wrapDegrees_0_360(yaw); - playersao->setBasePosition(position); - player->setSpeed(speed); + if (!playersao->isAttached()) { + // Only update player positions when moving freely + // to not interfere with attachment handling + playersao->setBasePosition(position); + player->setSpeed(speed); + } playersao->setLookPitch(pitch); playersao->setPlayerYaw(yaw); playersao->setFov(fov); @@ -619,21 +636,36 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt) const bool player_has_interact = checkPriv(player->getName(), "interact"); - auto check_inv_access = [player, player_has_interact] ( + auto check_inv_access = [player, player_has_interact, this] ( const InventoryLocation &loc) -> bool { - if (loc.type == InventoryLocation::CURRENT_PLAYER) - return false; // Only used internally on the client, never sent - if (loc.type == InventoryLocation::PLAYER) { - // Allow access to own inventory in all cases - return loc.name == player->getName(); - } - if (!player_has_interact) { + // Players without interact may modify their own inventory + if (!player_has_interact && loc.type != InventoryLocation::PLAYER) { infostream << "Cannot modify foreign inventory: " << "No interact privilege" << std::endl; return false; } - return true; + + switch (loc.type) { + case InventoryLocation::CURRENT_PLAYER: + // Only used internally on the client, never sent + return false; + case InventoryLocation::PLAYER: + // Allow access to own inventory in all cases + return loc.name == player->getName(); + case InventoryLocation::NODEMETA: + { + // Check for out-of-range interaction + v3f node_pos = intToFloat(loc.p, BS); + v3f player_pos = player->getPlayerSAO()->getEyePosition(); + f32 d = player_pos.getDistanceFrom(node_pos); + return checkInteractDistance(player, d, "inventory"); + } + case InventoryLocation::DETACHED: + return getInventoryMgr()->checkDetachedInventoryAccess(loc, player->getName()); + default: + return false; + } }; /* @@ -653,18 +685,6 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt) !check_inv_access(ma->to_inv)) return; - InventoryLocation *remote = ma->from_inv.type == InventoryLocation::PLAYER ? - &ma->to_inv : &ma->from_inv; - - // Check for out-of-range interaction - if (remote->type == InventoryLocation::NODEMETA) { - v3f node_pos = intToFloat(remote->p, BS); - v3f player_pos = player->getPlayerSAO()->getEyePosition(); - f32 d = player_pos.getDistanceFrom(node_pos); - if (!checkInteractDistance(player, d, "inventory")) - return; - } - /* Disable moving items out of craftpreview */ @@ -749,21 +769,8 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt) void Server::handleCommand_ChatMessage(NetworkPacket* pkt) { - /* - u16 command - u16 length - wstring message - */ - u16 len; - *pkt >> len; - std::wstring message; - for (u16 i = 0; i < len; i++) { - u16 tmp_wchar; - *pkt >> tmp_wchar; - - message += (wchar_t)tmp_wchar; - } + *pkt >> message; session_t peer_id = pkt->getPeerId(); RemotePlayer *player = m_env->getPlayer(peer_id); @@ -775,15 +782,13 @@ void Server::handleCommand_ChatMessage(NetworkPacket* pkt) return; } - // Get player name of this client std::string name = player->getName(); - std::wstring wname = narrow_to_wide(name); - std::wstring answer_to_sender = handleChat(name, wname, message, true, player); + std::wstring answer_to_sender = handleChat(name, message, true, player); if (!answer_to_sender.empty()) { // Send the answer to sender - SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_NORMAL, - answer_to_sender, wname)); + SendChatMessage(peer_id, ChatMessage(CHATMESSAGE_TYPE_SYSTEM, + answer_to_sender)); } } @@ -1046,6 +1051,12 @@ void Server::handleCommand_Interact(NetworkPacket *pkt) if (pointed.type == POINTEDTHING_NODE) { target_pos = intToFloat(pointed.node_undersurface, BS); } else if (pointed.type == POINTEDTHING_OBJECT) { + if (playersao->getId() == pointed_object->getId()) { + actionstream << "Server: " << player->getName() + << " attempted to interact with themselves" << std::endl; + m_script->on_cheat(playersao, "interacted_with_self"); + return; + } target_pos = pointed_object->getBasePosition(); } float d = playersao->getEyePosition().getDistanceFrom(target_pos); |
