Core/Networking: Rewrite networking threading model

Each network thread has its own io_service - this means that all operations on a given socket except queueing packets run from a single thread, removing the need for locking
Sending packets now writes to a lockfree intermediate queue directly, encryption is applied in network thread if it was required at the time of sending the packet
This commit is contained in:
Shauren
2016-02-19 19:23:04 +01:00
parent 06ec1b8fe8
commit 97a79af470
16 changed files with 325 additions and 210 deletions

View File

@@ -654,12 +654,37 @@ void Battlenet::Session::CheckIpCallback(PreparedQueryResult result)
bool Battlenet::Session::Update()
{
EncryptableBuffer* queued;
MessageBuffer buffer((std::size_t(BufferSizes::Read)));
while (_bufferQueue.Dequeue(queued))
{
std::size_t packetSize = queued->Buffer.GetActiveSize();
if (queued->Encrypt)
_crypt.EncryptSend(queued->Buffer.GetReadPointer(), packetSize);
if (buffer.GetRemainingSpace() < packetSize)
{
QueuePacket(std::move(buffer));
buffer.Resize(std::size_t(BufferSizes::Read));
}
if (buffer.GetRemainingSpace() >= packetSize)
buffer.Write(queued->Buffer.GetReadPointer(), packetSize);
else // single packet larger than 16384 bytes - client will reject.
QueuePacket(std::move(queued->Buffer));
delete queued;
}
if (buffer.GetActiveSize() > 0)
QueuePacket(std::move(buffer));
if (!BattlenetSocket::Update())
return false;
if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
auto callback = std::move(_queryCallback);
auto callback = _queryCallback;
_queryCallback = nullptr;
callback(_queryFuture.get());
}
@@ -679,15 +704,12 @@ void Battlenet::Session::AsyncWrite(ServerPacket* packet)
packet->Write();
MessageBuffer buffer;
buffer.Write(packet->GetData(), packet->GetSize());
EncryptableBuffer* buffer = new EncryptableBuffer();
buffer->Buffer.Write(packet->GetData(), packet->GetSize());
buffer->Encrypt = _crypt.IsInitialized();
delete packet;
std::unique_lock<std::mutex> guard(_writeLock);
_crypt.EncryptSend(buffer.GetReadPointer(), buffer.GetActiveSize());
QueuePacket(std::move(buffer), guard);
_bufferQueue.Enqueue(buffer);
}
inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse)