diff options
Diffstat (limited to 'src/game')
-rw-r--r-- | src/game/WorldSocket.cpp | 87 | ||||
-rw-r--r-- | src/game/WorldSocket.h | 4 |
2 files changed, 82 insertions, 9 deletions
diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp index 1b63ec01421..d1cf5f91822 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; @@ -979,16 +991,73 @@ 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()); + + if (m_OutBuffer->space () < pct.size () + header.getHeaderLength()) + { + // be sure to send big packet (otherwise, they would stay in the queue) + // So for packet larger than 1K, just check if there are some usefull space + if (pct.size() > 1024 && m_OutBuffer->space () < header.getHeaderLength() + 1024) + { + 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) + ACE_ASSERT (false); + + 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"); @@ -999,7 +1068,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 |