mpd/src/event/BufferedSocket.cxx

103 lines
1.9 KiB
C++
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
#include "BufferedSocket.hxx"
#include "net/SocketError.hxx"
2013-11-28 11:50:54 +01:00
2019-07-05 09:59:00 +02:00
#include <stdexcept>
inline BufferedSocket::ssize_t
BufferedSocket::DirectRead(std::span<std::byte> dest) noexcept
{
const auto nbytes = GetSocket().Read((char *)dest.data(), dest.size());
2023-03-06 15:57:36 +01:00
if (nbytes > 0) [[likely]]
return nbytes;
if (nbytes == 0) {
OnSocketClosed();
return -1;
}
const auto code = GetSocketError();
if (IsSocketErrorReceiveWouldBlock(code))
return 0;
if (IsSocketErrorClosed(code))
OnSocketClosed();
else
OnSocketError(std::make_exception_ptr(MakeSocketError(code, "Failed to receive from socket")));
return -1;
}
bool
2017-12-20 10:42:17 +01:00
BufferedSocket::ReadToBuffer() noexcept
{
assert(IsDefined());
const auto buffer = input.Write();
assert(!buffer.empty());
const auto nbytes = DirectRead(buffer);
if (nbytes > 0)
input.Append(nbytes);
return nbytes >= 0;
}
bool
2017-12-20 10:42:17 +01:00
BufferedSocket::ResumeInput() noexcept
{
assert(IsDefined());
while (true) {
const auto buffer = input.Read();
if (buffer.empty()) {
event.ScheduleRead();
return true;
}
const auto result = OnSocketInput(buffer.data(), buffer.size());
switch (result) {
case InputResult::MORE:
if (input.IsFull()) {
OnSocketError(std::make_exception_ptr(std::runtime_error("Input buffer is full")));
return false;
}
event.ScheduleRead();
return true;
case InputResult::PAUSE:
event.CancelRead();
return true;
case InputResult::AGAIN:
continue;
case InputResult::CLOSED:
return false;
}
}
}
void
2017-11-10 20:20:07 +01:00
BufferedSocket::OnSocketReady(unsigned flags) noexcept
{
assert(IsDefined());
2023-03-06 15:57:36 +01:00
if (flags & (SocketEvent::ERROR|SocketEvent::HANGUP)) [[unlikely]] {
OnSocketClosed();
return;
}
if (flags & SocketEvent::READ) {
assert(!input.IsFull());
if (!ReadToBuffer() || !ResumeInput())
return;
if (!input.IsFull())
event.ScheduleRead();
}
}