blob: 2d92b721a2916495883ade01dbddda40f39a7ebc [file] [log] [blame]
William A. Kennington IIIeac9d472020-08-03 13:57:14 -07001#include <fcntl.h>
2#include <fmt/format.h>
3#include <stdplus/exception.hpp>
4#include <stdplus/fd/impl.hpp>
5#include <stdplus/util/cexec.hpp>
6#include <string_view>
7#include <sys/ioctl.h>
8#include <sys/socket.h>
9#include <unistd.h>
10
11namespace stdplus
12{
13namespace fd
14{
15
16using namespace std::literals::string_view_literals;
17
Patrick Williams68975b92022-04-27 16:00:26 -050018std::span<std::byte> FdImpl::read(std::span<std::byte> buf)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070019{
20 ssize_t amt = ::read(get(), buf.data(), buf.size());
21 if (amt == -1)
22 {
23 if (errno == EAGAIN || errno == EWOULDBLOCK)
24 {
25 return {};
26 }
27 throw util::makeSystemError(errno, "read");
28 }
29 else if (amt == 0)
30 {
31 throw exception::Eof("read");
32 }
33 return buf.subspan(0, amt);
34}
35
Patrick Williams68975b92022-04-27 16:00:26 -050036std::span<std::byte> FdImpl::recv(std::span<std::byte> buf, RecvFlags flags)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070037{
38 ssize_t amt =
39 ::recv(get(), buf.data(), buf.size(), static_cast<int>(flags));
40 if (amt == -1)
41 {
42 if (errno == EAGAIN || errno == EWOULDBLOCK)
43 {
44 return {};
45 }
46 throw util::makeSystemError(errno, "recv");
47 }
48 else if (amt == 0)
49 {
50 throw exception::Eof("recv");
51 }
52 return buf.subspan(0, amt);
53}
54
Patrick Williams68975b92022-04-27 16:00:26 -050055std::span<const std::byte> FdImpl::write(std::span<const std::byte> data)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070056{
57 ssize_t amt = ::write(get(), data.data(), data.size());
58 if (amt == -1)
59 {
60 if (errno == EAGAIN || errno == EWOULDBLOCK)
61 {
62 return {};
63 }
64 throw util::makeSystemError(errno, "write");
65 }
66 return data.subspan(0, amt);
67}
68
Patrick Williams68975b92022-04-27 16:00:26 -050069std::span<const std::byte> FdImpl::send(std::span<const std::byte> data,
70 SendFlags flags)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070071{
72 ssize_t amt =
73 ::send(get(), data.data(), data.size(), static_cast<int>(flags));
74 if (amt == -1)
75 {
76 if (errno == EAGAIN || errno == EWOULDBLOCK)
77 {
78 return {};
79 }
80 throw util::makeSystemError(errno, "send");
81 }
82 return data.subspan(0, amt);
83}
84
85static std::string_view whenceStr(Whence whence)
86{
87 switch (whence)
88 {
89 case Whence::Set:
90 return "set"sv;
91 case Whence::Cur:
92 return "cur"sv;
93 case Whence::End:
94 return "end"sv;
95 default:
96 return "Unknown whence"sv;
97 }
98}
99
100size_t FdImpl::lseek(off_t offset, Whence whence)
101{
102 return CHECK_ERRNO(::lseek(get(), offset, static_cast<int>(whence)),
103 fmt::format("lseek {}B {}", offset, whenceStr(whence)));
104}
105
106void FdImpl::truncate(off_t size)
107{
108 CHECK_ERRNO(::ftruncate(get(), size), fmt::format("ftruncate {}B", size));
109}
110
Patrick Williams68975b92022-04-27 16:00:26 -0500111void FdImpl::bind(std::span<const std::byte> sockaddr)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700112{
113 CHECK_ERRNO(
114 ::bind(get(), reinterpret_cast<const struct sockaddr*>(sockaddr.data()),
115 sockaddr.size()),
116 "bind");
117}
118
William A. Kennington III1151c6d2022-02-08 15:11:12 -0800119void FdImpl::listen(int backlog)
120{
121 CHECK_ERRNO(::listen(get(), backlog), "listen");
122}
123
Patrick Williams68975b92022-04-27 16:00:26 -0500124std::tuple<std::optional<int>, std::span<std::byte>>
125 FdImpl::accept(std::span<std::byte> sockaddr)
William A. Kennington III1151c6d2022-02-08 15:11:12 -0800126{
127 socklen_t len = sockaddr.size();
128 auto fd = ::accept(
129 get(), reinterpret_cast<struct sockaddr*>(sockaddr.data()), &len);
130 if (fd == -1)
131 {
132 if (errno == EAGAIN || errno == EWOULDBLOCK)
133 {
134 return {};
135 }
136 throw util::makeSystemError(errno, "accept");
137 }
138 return std::make_tuple(fd, sockaddr.subspan(0, len));
139}
140
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700141void FdImpl::setsockopt(SockLevel level, SockOpt optname,
Patrick Williams68975b92022-04-27 16:00:26 -0500142 std::span<const std::byte> opt)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700143{
144 CHECK_ERRNO(::setsockopt(get(), static_cast<int>(level),
145 static_cast<int>(optname), opt.data(), opt.size()),
146 "setsockopt");
147}
148
149int FdImpl::ioctl(unsigned long id, void* data)
150{
151 return constIoctl(id, data);
152}
153
154int FdImpl::constIoctl(unsigned long id, void* data) const
155{
156 return CHECK_ERRNO(::ioctl(get(), id, data),
157 fmt::format("ioctl {:#x}", id));
158}
159
160void FdImpl::fcntlSetfd(FdFlags flags)
161{
162 CHECK_ERRNO(::fcntl(get(), F_SETFD, static_cast<int>(flags)),
163 "fcntl setfd");
164}
165
166FdFlags FdImpl::fcntlGetfd() const
167{
168 return FdFlags(CHECK_ERRNO(::fcntl(get(), F_GETFD), "fcntl getfd"));
169}
170
171void FdImpl::fcntlSetfl(FileFlags flags)
172{
173 CHECK_ERRNO(::fcntl(get(), F_SETFL, static_cast<int>(flags)),
174 "fcntl setfl");
175}
176
177FileFlags FdImpl::fcntlGetfl() const
178{
179 return FileFlags(CHECK_ERRNO(::fcntl(get(), F_GETFL), "fcntl getfl"));
180}
181
182} // namespace fd
183} // namespace stdplus