diff --git a/common/net/servertalk_server_connection.cpp b/common/net/servertalk_server_connection.cpp index 0942c9d50..f3823cda6 100644 --- a/common/net/servertalk_server_connection.cpp +++ b/common/net/servertalk_server_connection.cpp @@ -11,6 +11,7 @@ EQ::Net::ServertalkServerConnection::ServertalkServerConnection(std::shared_ptr< m_connection->OnRead(std::bind(&ServertalkServerConnection::OnRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_connection->OnDisconnect(std::bind(&ServertalkServerConnection::OnDisconnect, this, std::placeholders::_1)); m_connection->Start(); + m_legacy_mode = false; } EQ::Net::ServertalkServerConnection::~ServertalkServerConnection() @@ -19,17 +20,73 @@ EQ::Net::ServertalkServerConnection::~ServertalkServerConnection() void EQ::Net::ServertalkServerConnection::Send(uint16_t opcode, EQ::Net::Packet & p) { - // pad zero size packets - if (p.Length() == 0) { - p.PutUInt8(0, 0); + if (m_legacy_mode) { + if (!m_connection) + return; + + if (opcode == ServerOP_UsertoWorldReq) { + auto req_in = (UsertoWorldRequest_Struct*)p.Data(); + + EQ::Net::DynamicPacket req; + size_t i = 0; + req.PutUInt32(i, req_in->lsaccountid); i += 4; + req.PutUInt32(i, req_in->worldid); i += 4; + req.PutUInt32(i, req_in->FromID); i += 4; + req.PutUInt32(i, req_in->ToID); i += 4; + req.PutData(i, req_in->IPAddr, 64); i += 64; + + EQ::Net::DynamicPacket out; + out.PutUInt16(0, ServerOP_UsertoWorldReqLeg); + out.PutUInt16(2, req.Length() + 4); + out.PutPacket(4, req); + + m_connection->Write((const char*)out.Data(), out.Length()); + return; + } + + if (opcode == ServerOP_LSClientAuth) { + auto req_in = (ClientAuth_Struct*)p.Data(); + + EQ::Net::DynamicPacket req; + size_t i = 0; + req.PutUInt32(i, req_in->loginserver_account_id); i += 4; + req.PutData(i, req_in->account_name, 30); i += 30; + req.PutData(i, req_in->key, 30); i += 30; + req.PutUInt8(i, req_in->lsadmin); i += 1; + req.PutUInt16(i, req_in->is_world_admin); i += 2; + req.PutUInt32(i, req_in->ip); i += 4; + req.PutUInt8(i, req_in->is_client_from_local_network); i += 1; + + EQ::Net::DynamicPacket out; + out.PutUInt16(0, ServerOP_LSClientAuthLeg); + out.PutUInt16(2, req.Length() + 4); + out.PutPacket(4, req); + + m_connection->Write((const char*)out.Data(), out.Length()); + return; + } + + EQ::Net::DynamicPacket out; + out.PutUInt16(0, opcode); + out.PutUInt16(2, p.Length() + 4); + out.PutPacket(4, p); + + m_connection->Write((const char*)out.Data(), out.Length()); + } else { + // pad zero size packets + // pad packets that would cause a collision with legacy identification code + // It's unlikely we'd send a 4MB msg for any reason but just incase. + if (p.Length() == 0 || p.Length() == 43061256) { + p.PutUInt8(0, 0); + } + + EQ::Net::DynamicPacket out; + out.PutUInt32(0, p.Length()); + out.PutUInt16(4, opcode); + out.PutPacket(6, p); + + InternalSend(ServertalkMessage, out); } - - EQ::Net::DynamicPacket out; - out.PutUInt32(0, p.Length()); - out.PutUInt16(4, opcode); - out.PutPacket(6, p); - - InternalSend(ServertalkMessage, out); } void EQ::Net::ServertalkServerConnection::SendPacket(ServerPacket *p) @@ -54,17 +111,41 @@ void EQ::Net::ServertalkServerConnection::OnMessage(std::functionConnectionIdentified(this); + ProcessOldReadBuffer(); + return; + } + /* //header: //uint32 length; @@ -129,6 +210,57 @@ void EQ::Net::ServertalkServerConnection::ProcessReadBuffer() } } +void EQ::Net::ServertalkServerConnection::ProcessOldReadBuffer() +{ + size_t current = 0; + size_t total = m_buffer.size(); + + while (current < total) { + auto left = total - current; + + /* + //header: + //uint32 length; + //uint8 type; + */ + uint16_t length = 0; + uint16_t opcode = 0; + if (left < 4) { + break; + } + + opcode = *(uint16_t*)&m_buffer[current]; + length = *(uint16_t*)&m_buffer[current + 2]; + if (length < 4) { + break; + } + + length -= 4; + + if (current + 4 + length > total) { + break; + } + + if (length == 0) { + EQ::Net::DynamicPacket p; + ProcessMessageOld(opcode, p); + } + else { + EQ::Net::StaticPacket p(&m_buffer[current + 4], length); + ProcessMessageOld(opcode, p); + } + + current += length + 4; + } + + if (current == total) { + m_buffer.clear(); + } + else { + m_buffer.erase(m_buffer.begin(), m_buffer.begin() + current); + } +} + void EQ::Net::ServertalkServerConnection::OnDisconnect(TCPConnection *c) { m_parent->ConnectionDisconnected(this); @@ -144,7 +276,7 @@ void EQ::Net::ServertalkServerConnection::SendHello() void EQ::Net::ServertalkServerConnection::InternalSend(ServertalkPacketType type, EQ::Net::Packet &p) { - if (!m_connection) + if (!m_connection || m_legacy_mode) return; EQ::Net::DynamicPacket out; @@ -201,3 +333,20 @@ void EQ::Net::ServertalkServerConnection::ProcessMessage(EQ::Net::Packet &p) LogError("Error parsing message from client: {0}", ex.what()); } } + +void EQ::Net::ServertalkServerConnection::ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p) +{ + try { + auto cb = m_message_callbacks.find(opcode); + if (cb != m_message_callbacks.end()) { + cb->second(opcode, p); + } + + if (m_message_callback) { + m_message_callback(opcode, p); + } + } + catch (std::exception &ex) { + LogError("Error parsing legacy message from client: {0}", ex.what()); + } +} diff --git a/common/net/servertalk_server_connection.h b/common/net/servertalk_server_connection.h index f8110f51a..8e262baa1 100644 --- a/common/net/servertalk_server_connection.h +++ b/common/net/servertalk_server_connection.h @@ -27,11 +27,13 @@ namespace EQ private: void OnRead(TCPConnection* c, const unsigned char* data, size_t sz); void ProcessReadBuffer(); + void ProcessOldReadBuffer(); void OnDisconnect(TCPConnection* c); void SendHello(); void InternalSend(ServertalkPacketType type, EQ::Net::Packet &p); void ProcessHandshake(EQ::Net::Packet &p); void ProcessMessage(EQ::Net::Packet &p); + void ProcessMessageOld(uint16_t opcode, EQ::Net::Packet &p); std::shared_ptr m_connection; ServertalkServer *m_parent; @@ -41,6 +43,7 @@ namespace EQ std::function m_message_callback; std::string m_identifier; std::string m_uuid; + bool m_legacy_mode; }; } }