diff --git a/common/net/daybreak_connection.cpp b/common/net/daybreak_connection.cpp index 08e73c234..3e668c549 100644 --- a/common/net/daybreak_connection.cpp +++ b/common/net/daybreak_connection.cpp @@ -105,10 +105,14 @@ void EQ::Net::DaybreakConnectionManager::Process() auto status = connection->m_status; if (status == StatusDisconnecting) { - iter = m_connections.erase(iter); - connection->FlushBuffer(); - connection->ChangeStatus(StatusDisconnected); - continue; + auto time_since_close = std::chrono::duration_cast(now - connection->m_close_time); + if (time_since_close.count() > m_options.connection_close_time) { + connection->FlushBuffer(); + connection->SendDisconnect(); + connection->ChangeStatus(StatusDisconnected); + iter = m_connections.erase(iter); + continue; + } } if (status == StatusConnecting) { @@ -310,16 +314,10 @@ EQ::Net::DaybreakConnection::~DaybreakConnection() void EQ::Net::DaybreakConnection::Close() { if (m_status == StatusConnected) { - DaybreakDisconnect disconnect; - disconnect.zero = 0; - disconnect.opcode = OP_SessionDisconnect; - disconnect.connect_code = HostToNetwork(m_connect_code); - DynamicPacket out; - out.PutSerialize(0, disconnect); - FlushBuffer(); - InternalSend(out); + SendDisconnect(); + m_close_time = Clock::now(); ChangeStatus(StatusDisconnecting); } else { @@ -489,6 +487,11 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) switch (p.GetInt8(1)) { case OP_Combined: { + if (m_status == StatusDisconnecting) { + SendDisconnect(); + return; + } + char *current = (char*)p.Data() + 2; char *end = (char*)p.Data() + p.Length(); while (current < end) { @@ -507,6 +510,11 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_AppCombined: { + if (m_status == StatusDisconnecting) { + SendDisconnect(); + return; + } + uint8_t *current = (uint8_t*)p.Data() + 2; uint8_t *end = (uint8_t*)p.Data() + p.Length(); @@ -597,6 +605,11 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_Packet3: case OP_Packet4: { + if (m_status == StatusDisconnecting) { + SendDisconnect(); + return; + } + auto header = p.GetSerialize(0); auto sequence = NetworkToHost(header.sequence); auto stream_id = header.opcode - OP_Packet; @@ -702,15 +715,8 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_SessionDisconnect: { if (m_status == StatusConnected || m_status == StatusDisconnecting) { - DaybreakDisconnect disconnect; - disconnect.zero = 0; - disconnect.opcode = OP_SessionDisconnect; - disconnect.connect_code = HostToNetwork(m_connect_code); - DynamicPacket out; - out.PutSerialize(0, disconnect); - FlushBuffer(); - InternalSend(out); + SendDisconnect(); } ChangeStatus(StatusDisconnecting); @@ -1002,7 +1008,7 @@ void EQ::Net::DaybreakConnection::ProcessResend() void EQ::Net::DaybreakConnection::ProcessResend(int stream) { - if (m_status == DbProtocolStatus::StatusDisconnected || m_status == DbProtocolStatus::StatusDisconnecting) { + if (m_status == DbProtocolStatus::StatusDisconnected) { return; } @@ -1018,13 +1024,12 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream) } } else { - if (entry.second.times_resent >= m_owner->m_options.max_resend_count) { + auto time_since_first_sent = std::chrono::duration_cast(now - entry.second.first_sent); + if (time_since_first_sent.count() >= m_owner->m_options.resend_timeout) { Close(); return; } - auto adjusted_resend = std::max((uint32_t)(m_resend_delay / (entry.second.times_resent + 1)), (uint32_t)m_owner->m_options.resend_delay_min); - if ((size_t)time_since_last_send.count() > m_resend_delay) { InternalBufferedSend(entry.second.packet); entry.second.last_sent = now; @@ -1099,6 +1104,17 @@ void EQ::Net::DaybreakConnection::SendOutOfOrderAck(int stream_id, uint16_t seq) InternalBufferedSend(p); } +void EQ::Net::DaybreakConnection::SendDisconnect() +{ + DaybreakDisconnect disconnect; + disconnect.zero = 0; + disconnect.opcode = OP_SessionDisconnect; + disconnect.connect_code = HostToNetwork(m_connect_code); + DynamicPacket out; + out.PutSerialize(0, disconnect); + InternalSend(out); +} + void EQ::Net::DaybreakConnection::InternalBufferedSend(Packet &p) { if (p.Length() > 0xFFU) { diff --git a/common/net/daybreak_connection.h b/common/net/daybreak_connection.h index cf40ee91f..c874411a8 100644 --- a/common/net/daybreak_connection.h +++ b/common/net/daybreak_connection.h @@ -138,6 +138,7 @@ namespace EQ Timestamp m_last_session_stats; size_t m_resend_delay; size_t m_rolling_ping; + Timestamp m_close_time; struct DaybreakSentPacket { @@ -193,6 +194,7 @@ namespace EQ void SendKeepAlive(); void SendAck(int stream, uint16_t seq); void SendOutOfOrderAck(int stream, uint16_t seq); + void SendDisconnect(); void InternalBufferedSend(Packet &p); void InternalSend(Packet &p); void InternalQueuePacket(Packet &p, int stream_id, bool reliable); @@ -224,7 +226,8 @@ namespace EQ simulated_in_packet_loss = 0; simulated_out_packet_loss = 0; tic_rate_hertz = 60.0; - max_resend_count = 10; + resend_timeout = 60000; + connection_close_time = 2000; } size_t max_packet_size; @@ -243,7 +246,8 @@ namespace EQ size_t simulated_in_packet_loss; size_t simulated_out_packet_loss; double tic_rate_hertz; - size_t max_resend_count; + size_t resend_timeout; + size_t connection_close_time; DaybreakEncodeType encode_passes[2]; int port; };