From d334756bb6401fd12cdd5f50cd2b913c4396a260 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 14 Jan 2025 19:15:34 +0100 Subject: [PATCH] Propagate peer ID change to outgoing reliables Otherwise a desync could ocurr since the server does strict checking. fixes #15627 --- src/network/mtp/impl.cpp | 31 +++++++++++++++++++++++++++++++ src/network/mtp/impl.h | 2 +- src/network/mtp/internal.h | 7 ++++++- src/network/mtp/threads.cpp | 25 +++++++++++++++++++++++++ src/network/mtp/threads.h | 1 + 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/network/mtp/impl.cpp b/src/network/mtp/impl.cpp index 02ee6bfdafe5a..48f3854548b1f 100644 --- a/src/network/mtp/impl.cpp +++ b/src/network/mtp/impl.cpp @@ -53,6 +53,15 @@ u16 BufferedPacket::getSeqnum() const return readU16(&data[BASE_HEADER_SIZE + 1]); } +void BufferedPacket::setSenderPeerId(session_t id) +{ + if (size() < BASE_HEADER_SIZE) { + assert(false); // should never happen + return; + } + writeU16(&data[4], id); +} + BufferedPacketPtr makePacket(const Address &address, const SharedBuffer &data, u32 protocol_id, session_t sender_peer_id, u8 channel) { @@ -337,6 +346,13 @@ void ReliablePacketBuffer::insert(BufferedPacketPtr &p_ptr, u16 next_expected) m_oldest_non_answered_ack = m_list.front()->getSeqnum(); } +void ReliablePacketBuffer::fixPeerId(session_t new_id) +{ + MutexAutoLock listlock(m_list_mutex); + for (auto &packet : m_list) + packet->setSenderPeerId(new_id); +} + void ReliablePacketBuffer::incrementTimeouts(float dtime) { MutexAutoLock listlock(m_list_mutex); @@ -569,6 +585,13 @@ ConnectionCommandPtr ConnectionCommand::resend_one(session_t peer_id) return c; } +ConnectionCommandPtr ConnectionCommand::peer_id_set(session_t own_peer_id) +{ + auto c = create(CONNCMD_PEER_ID_SET); + c->peer_id = own_peer_id; + return c; +} + ConnectionCommandPtr ConnectionCommand::send(session_t peer_id, u8 channelnum, NetworkPacket *pkt, bool reliable) { @@ -1615,6 +1638,14 @@ void Connection::DisconnectPeer(session_t peer_id) putCommand(ConnectionCommand::disconnect_peer(peer_id)); } +void Connection::SetPeerID(session_t id) +{ + assert(id != PEER_ID_INEXISTENT); + m_peer_id = id; + // fix peer id in existing queued reliable packets + putCommand(ConnectionCommand::peer_id_set(id)); +} + void Connection::doResendOne(session_t peer_id) { assert(peer_id != PEER_ID_INEXISTENT); diff --git a/src/network/mtp/impl.h b/src/network/mtp/impl.h index 1bc408a017cf7..a88012b222708 100644 --- a/src/network/mtp/impl.h +++ b/src/network/mtp/impl.h @@ -256,7 +256,7 @@ class Connection final : public IConnection UDPPeer* createServerPeer(const Address& sender); bool deletePeer(session_t peer_id, bool timeout); - void SetPeerID(session_t id) { m_peer_id = id; } + void SetPeerID(session_t id); void doResendOne(session_t peer_id); diff --git a/src/network/mtp/internal.h b/src/network/mtp/internal.h index cc82b09f66319..e3ad39bdee340 100644 --- a/src/network/mtp/internal.h +++ b/src/network/mtp/internal.h @@ -187,6 +187,7 @@ struct BufferedPacket { DISABLE_CLASS_COPY(BufferedPacket) u16 getSeqnum() const; + void setSenderPeerId(session_t id); inline size_t size() const { return m_data.size(); } @@ -250,6 +251,8 @@ class ReliablePacketBuffer BufferedPacketPtr popFirst(); BufferedPacketPtr popSeqnum(u16 seqnum); void insert(BufferedPacketPtr &p_ptr, u16 next_expected); + /// Adjusts the sender peer ID for all packets + void fixPeerId(session_t id); void incrementTimeouts(float dtime); u32 getTimedOuts(float timeout); @@ -307,7 +310,8 @@ enum ConnectionCommandType{ CONNCMD_SEND_TO_ALL, CONCMD_ACK, CONCMD_CREATE_PEER, - CONNCMD_RESEND_ONE + CONNCMD_RESEND_ONE, + CONNCMD_PEER_ID_SET }; // This is very similar to ConnectionEvent @@ -328,6 +332,7 @@ struct ConnectionCommand static ConnectionCommandPtr disconnect(); static ConnectionCommandPtr disconnect_peer(session_t peer_id); static ConnectionCommandPtr resend_one(session_t peer_id); + static ConnectionCommandPtr peer_id_set(session_t own_peer_id); static ConnectionCommandPtr send(session_t peer_id, u8 channelnum, NetworkPacket *pkt, bool reliable); static ConnectionCommandPtr ack(session_t peer_id, u8 channelnum, const Buffer &data); static ConnectionCommandPtr createPeer(session_t peer_id, const Buffer &data); diff --git a/src/network/mtp/threads.cpp b/src/network/mtp/threads.cpp index 9976e9a04ef9f..12f5a787a2d9d 100644 --- a/src/network/mtp/threads.cpp +++ b/src/network/mtp/threads.cpp @@ -476,6 +476,11 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommandPtr &c_ptr << " UDP processing CONNCMD_DISCONNECT_PEER" << std::endl); disconnect_peer(c.peer_id); return; + case CONNCMD_PEER_ID_SET: + LOG(dout_con << m_connection->getDesc() + << " UDP processing CONNCMD_PEER_ID_SET" << std::endl); + fix_peer_id(c.peer_id); + return; case CONNCMD_SEND: LOG(dout_con << m_connection->getDesc() << " UDP processing CONNCMD_SEND" << std::endl); @@ -579,6 +584,26 @@ void ConnectionSendThread::disconnect_peer(session_t peer_id) dynamic_cast(&peer)->m_pending_disconnect = true; } +void ConnectionSendThread::fix_peer_id(session_t own_peer_id) +{ + auto peerIds = m_connection->getPeerIDs(); + for (const session_t peerId : peerIds) { + PeerHelper peer = m_connection->getPeerNoEx(peerId); + if (!peer) + continue; + + UDPPeer *udpPeer = dynamic_cast(&peer); + if (!udpPeer) + continue; + + for (int ch = 0; ch < CHANNEL_COUNT; ch++) { + auto &channel = udpPeer->channels[ch]; + + channel.outgoing_reliables_sent.fixPeerId(own_peer_id); + } + } +} + void ConnectionSendThread::send(session_t peer_id, u8 channelnum, const SharedBuffer &data) { diff --git a/src/network/mtp/threads.h b/src/network/mtp/threads.h index bf660bddf0e55..e5a1db2e5651f 100644 --- a/src/network/mtp/threads.h +++ b/src/network/mtp/threads.h @@ -70,6 +70,7 @@ class ConnectionSendThread : public Thread void connect(Address address); void disconnect(); void disconnect_peer(session_t peer_id); + void fix_peer_id(session_t own_peer_id); void send(session_t peer_id, u8 channelnum, const SharedBuffer &data); void sendReliable(ConnectionCommandPtr &c); void sendToAll(u8 channelnum, const SharedBuffer &data);