Revert "Client: eliminate SetExpired(), call Close() directly"
This reverts commit 58d7804d66
. It
caused a use-after-free bug when Client::OnSocketError() was called
due to a failed write, e.g. if the output buffer was full.
This commit is contained in:
parent
e6600b8562
commit
f2cdbeace6
@ -122,9 +122,15 @@ public:
|
||||
|
||||
using FullyBufferedSocket::GetEventLoop;
|
||||
|
||||
void Close() noexcept;
|
||||
gcc_pure
|
||||
bool IsExpired() const noexcept {
|
||||
return !FullyBufferedSocket::IsDefined();
|
||||
}
|
||||
|
||||
using FullyBufferedSocket::Write;
|
||||
void Close() noexcept;
|
||||
void SetExpired() noexcept;
|
||||
|
||||
bool Write(const void *data, size_t length) noexcept;
|
||||
|
||||
/**
|
||||
* Write a null-terminated string.
|
||||
|
@ -25,11 +25,11 @@ Client::OnSocketError(std::exception_ptr ep) noexcept
|
||||
{
|
||||
FormatError(ep, "error on client %d", num);
|
||||
|
||||
Close();
|
||||
SetExpired();
|
||||
}
|
||||
|
||||
void
|
||||
Client::OnSocketClosed() noexcept
|
||||
{
|
||||
Close();
|
||||
SetExpired();
|
||||
}
|
||||
|
@ -18,16 +18,31 @@
|
||||
*/
|
||||
|
||||
#include "Client.hxx"
|
||||
#include "BackgroundCommand.hxx"
|
||||
#include "Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
void
|
||||
Client::SetExpired() noexcept
|
||||
{
|
||||
if (IsExpired())
|
||||
return;
|
||||
|
||||
background_command.reset();
|
||||
|
||||
FullyBufferedSocket::Close();
|
||||
timeout_event.Schedule(std::chrono::steady_clock::duration::zero());
|
||||
}
|
||||
|
||||
void
|
||||
Client::OnTimeout() noexcept
|
||||
{
|
||||
assert(!idle_waiting);
|
||||
assert(!background_command);
|
||||
if (!IsExpired()) {
|
||||
assert(!idle_waiting);
|
||||
assert(!background_command);
|
||||
|
||||
FormatDebug(client_domain, "[%u] timeout", num);
|
||||
FormatDebug(client_domain, "[%u] timeout", num);
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
@ -54,6 +54,9 @@ Client::IdleNotify() noexcept
|
||||
void
|
||||
Client::IdleAdd(unsigned flags) noexcept
|
||||
{
|
||||
if (IsExpired())
|
||||
return;
|
||||
|
||||
idle_flags |= flags;
|
||||
if (idle_waiting && (idle_flags & idle_subscriptions))
|
||||
IdleNotify();
|
||||
|
@ -42,7 +42,9 @@ Client::ProcessCommandList(bool list_ok,
|
||||
FormatDebug(client_domain, "process command \"%s\"", cmd);
|
||||
auto ret = command_process(*this, n++, cmd);
|
||||
FormatDebug(client_domain, "command returned %i", int(ret));
|
||||
if (ret != CommandResult::OK)
|
||||
if (IsExpired())
|
||||
return CommandResult::CLOSE;
|
||||
else if (ret != CommandResult::OK)
|
||||
return ret;
|
||||
else if (list_ok)
|
||||
Write("list_OK\n");
|
||||
@ -139,6 +141,9 @@ Client::ProcessLine(char *line) noexcept
|
||||
"[%u] command returned %i",
|
||||
id, int(ret));
|
||||
|
||||
if (IsExpired())
|
||||
return CommandResult::CLOSE;
|
||||
|
||||
if (ret == CommandResult::OK)
|
||||
command_success(*this);
|
||||
|
||||
|
@ -69,5 +69,10 @@ Client::OnSocketInput(void *data, size_t length) noexcept
|
||||
return InputResult::CLOSED;
|
||||
}
|
||||
|
||||
if (IsExpired()) {
|
||||
Close();
|
||||
return InputResult::CLOSED;
|
||||
}
|
||||
|
||||
return InputResult::AGAIN;
|
||||
}
|
||||
|
@ -21,6 +21,13 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
bool
|
||||
Client::Write(const void *data, size_t length) noexcept
|
||||
{
|
||||
/* if the client is going to be closed, do nothing */
|
||||
return !IsExpired() && FullyBufferedSocket::Write(data, length);
|
||||
}
|
||||
|
||||
bool
|
||||
Client::Write(const char *data) noexcept
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user