Skip to content

Commit

Permalink
Fix SendPaquet thread safe issue
Browse files Browse the repository at this point in the history
Creating a new write method that handle more than one buffer at once.

Thank to @ryancheung for pointing and for his PR cmangos/mangos-classic#311
Thank to @namreeb for his analyse.

close cmangos/mangos-classic#311
  • Loading branch information
cyberium committed Aug 22, 2017
1 parent 6d253f7 commit 09d9122
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 20 deletions.
8 changes: 4 additions & 4 deletions src/game/Server/WorldSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ void WorldSocket::SendPacket(const WorldPacket& pct, bool immediate)
ServerPktHeader header(pct.size() + 2, pct.GetOpcode());
m_crypt.EncryptSend((uint8*)header.header, header.getHeaderLength());

Write((const char *)header.header, header.getHeaderLength());

if (!!pct.size())
Write((const char *)pct.contents(), pct.size());
if (pct.size() > 0)
Write(reinterpret_cast<const char *>(&header.header), header.getHeaderLength(), reinterpret_cast<const char *>(pct.contents()), pct.size());
else
Write(reinterpret_cast<const char *>(&header.header), header.getHeaderLength());

if (immediate)
ForceFlushOut();
Expand Down
41 changes: 25 additions & 16 deletions src/shared/Network/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,28 +162,37 @@ bool Socket::Read(char *buffer, int length)
return true;
}

void Socket::Write(const char *buffer, int length)
void Socket::Write(const char *header, int headerSize, const char* content, int contentSize)
{
std::lock_guard<std::mutex> guard(m_mutex);

switch (m_writeState)
{
case WriteState::Idle:
m_outBuffer->Write(buffer, length);
StartWriteFlushTimer();
break;
// get the correct buffer depending on the current writing state
PacketBuffer* outBuffer = m_writeState == WriteState::Sending ? m_secondaryOutBuffer.get() : m_outBuffer.get();

case WriteState::Buffering:
m_outBuffer->Write(buffer, length);
break;
// write the header
outBuffer->Write(header, headerSize);

case WriteState::Sending:
m_secondaryOutBuffer->Write(buffer, length);
break;
// write the content
outBuffer->Write(content, contentSize);

default:
assert(false);
}
// flush data if need
if (m_writeState == WriteState::Idle)
StartWriteFlushTimer();
}

void Socket::Write(const char *buffer, int length)
{
std::lock_guard<std::mutex> guard(m_mutex);

// get the correct buffer depending on the current writing state
PacketBuffer* outBuffer = m_writeState == WriteState::Sending ? m_secondaryOutBuffer.get() : m_outBuffer.get();

// write the header
outBuffer->Write(buffer, length);

// flush data if need
if (m_writeState == WriteState::Idle)
StartWriteFlushTimer();
}

// note that this function assumes that the socket mutex is locked
Expand Down
1 change: 1 addition & 0 deletions src/shared/Network/Socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ namespace MaNGOS
void ReadSkip(int length) { m_inBuffer->Read(nullptr, length); }

void Write(const char *buffer, int length);
void Write(const char *header, int headerSize, const char* content, int contentSize);

boost::asio::ip::tcp::socket &GetAsioSocket() { return m_socket; }

Expand Down

0 comments on commit 09d9122

Please sign in to comment.