blob: 55efbab33d65c0478cdaab7ff547366ce4d3b942 [file] [log] [blame]
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdplus/exception.hpp>
#include <stdplus/fd/impl.hpp>
#include <stdplus/util/cexec.hpp>
#include <format>
#include <string_view>
namespace stdplus
{
namespace fd
{
using namespace std::literals::string_view_literals;
std::span<std::byte> FdImpl::read(std::span<std::byte> buf)
{
ssize_t amt = ::read(get(), buf.data(), buf.size());
if (amt == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
return {};
}
throw util::makeSystemError(errno, "read");
}
else if (amt == 0)
{
throw exception::Eof("read");
}
return buf.subspan(0, amt);
}
std::span<std::byte> FdImpl::recv(std::span<std::byte> buf, RecvFlags flags)
{
ssize_t amt = ::recv(get(), buf.data(), buf.size(),
static_cast<int>(flags));
if (amt == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
return {};
}
throw util::makeSystemError(errno, "recv");
}
else if (amt == 0)
{
throw exception::Eof("recv");
}
return buf.subspan(0, amt);
}
std::span<const std::byte> FdImpl::write(std::span<const std::byte> data)
{
ssize_t amt = ::write(get(), data.data(), data.size());
if (amt == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
return {};
}
throw util::makeSystemError(errno, "write");
}
return data.subspan(0, amt);
}
std::span<const std::byte> FdImpl::send(std::span<const std::byte> data,
SendFlags flags)
{
ssize_t amt = ::send(get(), data.data(), data.size(),
static_cast<int>(flags));
if (amt == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
return {};
}
throw util::makeSystemError(errno, "send");
}
return data.subspan(0, amt);
}
static std::string_view whenceStr(Whence whence)
{
switch (whence)
{
case Whence::Set:
return "set"sv;
case Whence::Cur:
return "cur"sv;
case Whence::End:
return "end"sv;
default:
return "Unknown whence"sv;
}
}
size_t FdImpl::lseek(off_t offset, Whence whence)
{
return CHECK_ERRNO(::lseek(get(), offset, static_cast<int>(whence)),
std::format("lseek {}B {}", offset, whenceStr(whence)));
}
void FdImpl::truncate(off_t size)
{
CHECK_ERRNO(::ftruncate(get(), size), std::format("ftruncate {}B", size));
}
void FdImpl::bind(std::span<const std::byte> sockaddr)
{
CHECK_ERRNO(
::bind(get(), reinterpret_cast<const struct sockaddr*>(sockaddr.data()),
sockaddr.size()),
"bind");
}
void FdImpl::listen(int backlog)
{
CHECK_ERRNO(::listen(get(), backlog), "listen");
}
std::optional<std::tuple<int, std::span<std::byte>>>
FdImpl::accept(std::span<std::byte> sockaddr)
{
socklen_t len = sockaddr.size();
auto fd = ::accept(
get(), reinterpret_cast<struct sockaddr*>(sockaddr.data()), &len);
if (fd == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
return std::nullopt;
}
throw util::makeSystemError(errno, "accept");
}
return std::make_tuple(fd, sockaddr.subspan(0, len));
}
void FdImpl::setsockopt(SockLevel level, SockOpt optname,
std::span<const std::byte> opt)
{
CHECK_ERRNO(::setsockopt(get(), static_cast<int>(level),
static_cast<int>(optname), opt.data(), opt.size()),
"setsockopt");
}
int FdImpl::ioctl(unsigned long id, void* data)
{
return constIoctl(id, data);
}
int FdImpl::constIoctl(unsigned long id, void* data) const
{
return CHECK_ERRNO(::ioctl(get(), id, data),
std::format("ioctl {:#x}", id));
}
void FdImpl::fcntlSetfd(FdFlags flags)
{
CHECK_ERRNO(::fcntl(get(), F_SETFD, static_cast<int>(flags)),
"fcntl setfd");
}
FdFlags FdImpl::fcntlGetfd() const
{
return FdFlags(CHECK_ERRNO(::fcntl(get(), F_GETFD), "fcntl getfd"));
}
void FdImpl::fcntlSetfl(FileFlags flags)
{
CHECK_ERRNO(::fcntl(get(), F_SETFL, static_cast<int>(flags)),
"fcntl setfl");
}
FileFlags FdImpl::fcntlGetfl() const
{
return FileFlags(CHECK_ERRNO(::fcntl(get(), F_GETFL), "fcntl getfl"));
}
std::span<std::byte> FdImpl::mmap(std::span<std::byte> window, ProtFlags prot,
MMapFlags flags, off_t offset)
{
auto ret = ::mmap(window.data(), window.size(), static_cast<int>(prot),
static_cast<int>(flags), get(), offset);
if (ret == MAP_FAILED)
{
util::doError(errno, "mmap");
}
return {reinterpret_cast<std::byte*>(ret), window.size()};
}
void FdImpl::munmap(std::span<std::byte> window)
{
CHECK_ERRNO(::munmap(window.data(), window.size()), "munmap");
}
} // namespace fd
} // namespace stdplus