diff options
author | Rat <none@none> | 2009-11-10 10:16:26 +0100 |
---|---|---|
committer | Rat <none@none> | 2009-11-10 10:16:26 +0100 |
commit | 40dceb43d64918f948a744c8c231b93df360ffc9 (patch) | |
tree | 64f5710476ac20f8c804765b631091f163f66ac7 | |
parent | a0314df4af0258ab47c932589a86855d139b1725 (diff) |
*fix Character freeze after map change or login. Closes #19 patch by trazom
--HG--
branch : trunk
-rw-r--r-- | src/game/WorldSocket.cpp | 79 | ||||
-rw-r--r-- | src/game/WorldSocket.h | 4 |
2 files changed, 74 insertions, 9 deletions
diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp index c45e6b943d6..6991e4d112f 100644 --- a/src/game/WorldSocket.cpp +++ b/src/game/WorldSocket.cpp @@ -188,7 +188,8 @@ int WorldSocket::SendPacket (const WorldPacket& pct) sWorldLog.outLog ("\n"); } - if (iSendPacket (pct) == -1) + // don't try to send the packet if there are packets on the queue + if (!m_PacketQueue.is_empty() || iSendPacket(pct) == -1) { WorldPacket* npct; @@ -202,6 +203,12 @@ int WorldSocket::SendPacket (const WorldPacket& pct) sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed"); return -1; } + + // iSendPacket may fail if the packet is larger than the buffer (even in the buffer is empty) + // So we must try to flush so the packet may be sent partially + // don't cancel_wakeup_output here + if (iFlushPacketQueue()) + return schedule_wakeup_output(Guard); } return 0; @@ -321,10 +328,15 @@ int WorldSocket::handle_output (ACE_HANDLE) if (closing_) return -1; - const size_t send_len = m_OutBuffer->length (); + size_t send_len = m_OutBuffer->length(); if (send_len == 0) - return cancel_wakeup_output (Guard); + { + if (!iFlushPacketQueue()) + return cancel_wakeup_output(Guard); + + send_len = m_OutBuffer->length (); + } #ifdef MSG_NOSIGNAL ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL); @@ -960,7 +972,7 @@ int WorldSocket::HandlePing (WorldPacket& recvPacket) int WorldSocket::iSendPacket (const WorldPacket& pct) { ServerPktHeader header(pct.size()+2, pct.GetOpcode()); - if (m_OutBuffer->space () < pct.size () + header.getHeaderLength()) + if (m_OutBuffer->space() < pct.size () + header.getHeaderLength()) { errno = ENOBUFS; return -1; @@ -978,16 +990,65 @@ int WorldSocket::iSendPacket (const WorldPacket& pct) return 0; } -bool WorldSocket::iFlushPacketQueue () +/// Return 1 if some bytes written and packet completed +/// Return 0 if no byte written, but still remaining data +/// Return -1 if some bytes written and still remaining data +int WorldSocket::iSendPartialPacket(WorldPacket& pct) +{ + size_t remainingLen = pct.size() - pct.rpos(); + + if (pct.rpos() == 0) // nothing sent yet => send header + { + ServerPktHeader header(pct.size()+2, pct.GetOpcode()); + + // check if there is at least enough space for the header + if (m_OutBuffer->space () < header.getHeaderLength()) + return 0; // nothing written, still remaining data => 0 + + m_Crypt.EncryptSend(header.header, header.getHeaderLength()); + + if (m_OutBuffer->copy((char*) header.header, header.getHeaderLength()) == -1) + return 0; // no space left. This should not happend. Just return 0 as nothing written and still remaining data + + if (remainingLen == 0) + return 1; // header written, nothing else => 1 + } + + if ((m_OutBuffer->space()) < remainingLen) { + size_t len = m_OutBuffer->space(); + + if (m_OutBuffer->copy((char*) (pct.contents() + pct.rpos()), len) == -1) + ACE_ASSERT (false); + + pct.read_skip(len); + return -1; // packet will be pushed back on the queue + } + + if (m_OutBuffer->copy((char*) (pct.contents() + pct.rpos()), remainingLen) == -1) + ACE_ASSERT (false); + + return 1; // some byte written and packet completed +} + + +bool WorldSocket::iFlushPacketQueue() { WorldPacket *pct; bool haveone = false; - while (m_PacketQueue.dequeue_head (pct) == 0) + while (m_PacketQueue.dequeue_head(pct) == 0) { - if (iSendPacket (*pct) == -1) + int result = iSendPartialPacket(*pct); + + if (result != 0) + { + // some bytes were written + haveone = true; + } + + if (result <= 0) { - if (m_PacketQueue.enqueue_head (pct) == -1) + if (m_PacketQueue.enqueue_head(pct) == -1) { delete pct; sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head"); @@ -998,7 +1059,7 @@ bool WorldSocket::iFlushPacketQueue () } else { - haveone = true; + // packet completed delete pct; } } diff --git a/src/game/WorldSocket.h b/src/game/WorldSocket.h index 94f57d8d636..9b012ee23d3 100644 --- a/src/game/WorldSocket.h +++ b/src/game/WorldSocket.h @@ -175,6 +175,10 @@ class WorldSocket : protected WorldHandler /// Need to be called with m_OutBufferLock lock held int iSendPacket (const WorldPacket& pct); + /// Try to write WorldPacket to m_OutBuffer even partially, + /// Need to be called with m_OutBufferLock lock held + int iSendPartialPacket(WorldPacket& pct); + /// Flush m_PacketQueue if there are packets in it /// Need to be called with m_OutBufferLock lock held /// @return true if it wrote to the buffer ( AKA you need |