blob: c069a5ab13a7f7644edbc561699d0571b6da02e9 [file] [log] [blame]
William A. Kennington IIIeac9d472020-08-03 13:57:14 -07001#include <stdplus/exception.hpp>
2#include <stdplus/fd/ops.hpp>
Patrick Williamsd1984dd2023-05-10 16:12:44 -05003
William A. Kennington III6417c632023-07-17 02:56:52 -07004#include <format>
William A. Kennington IIIeac9d472020-08-03 13:57:14 -07005#include <utility>
6
7namespace stdplus
8{
9namespace fd
10{
11namespace detail
12{
13
14template <typename Fun, typename Byte, typename... Args>
Patrick Williams68975b92022-04-27 16:00:26 -050015static void opExact(const char* name, Fun&& fun, Fd& fd, std::span<Byte> data,
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070016 Args&&... args)
17{
William A. Kennington III93ae9702023-12-22 16:41:17 -080018 std::size_t total = 0;
19 try
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070020 {
William A. Kennington III93ae9702023-12-22 16:41:17 -080021 while (total < data.size())
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070022 {
Patrick Williamsd8e0af52024-08-16 15:21:12 -040023 auto r =
24 (fd.*fun)(data.subspan(total), std::forward<Args>(args)...);
William A. Kennington III93ae9702023-12-22 16:41:17 -080025 if (r.size() == 0)
26 {
27 throw exception::WouldBlock(
28 std::format("{} missing", name, data.size()));
29 }
30 total += r.size();
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070031 }
William A. Kennington III93ae9702023-12-22 16:41:17 -080032 }
33 catch (const std::system_error&)
34 {
35 if (total != 0)
36 {
37 throw exception::Incomplete(
38 std::format("{} is {}B/{}B", name, total, data.size()));
39 }
40 throw;
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070041 }
42}
43
Patrick Williams68975b92022-04-27 16:00:26 -050044void readExact(Fd& fd, std::span<std::byte> data)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070045{
46 opExact("readExact", &Fd::read, fd, data);
47}
48
Patrick Williams68975b92022-04-27 16:00:26 -050049void recvExact(Fd& fd, std::span<std::byte> data, RecvFlags flags)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070050{
51 opExact("recvExact", &Fd::recv, fd, data, flags);
52}
53
Patrick Williams68975b92022-04-27 16:00:26 -050054void writeExact(Fd& fd, std::span<const std::byte> data)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070055{
56 opExact("writeExact", &Fd::write, fd, data);
57}
58
Patrick Williams68975b92022-04-27 16:00:26 -050059void sendExact(Fd& fd, std::span<const std::byte> data, SendFlags flags)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070060{
61 opExact("sendExact", &Fd::send, fd, data, flags);
62}
63
William A. Kennington III4edcc6e2023-12-19 17:24:54 -080064void sendtoExact(Fd& fd, std::span<const std::byte> data, SendFlags flags,
65 std::span<const std::byte> addr)
66{
67 auto r = fd.sendto(data, flags, addr);
68 if (r.size() == 0)
69 {
70 throw exception::WouldBlock("sendto");
71 }
72 if (r.size() < data.size())
73 {
74 throw exception::Incomplete("sendto");
75 }
76}
77
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070078template <typename Fun, typename Byte, typename... Args>
Patrick Williamsd8e0af52024-08-16 15:21:12 -040079static std::span<Byte>
80 opAligned(const char* name, Fun&& fun, Fd& fd, size_t align,
81 std::span<Byte> data, Args&&... args)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070082{
William A. Kennington IIIb88c4572023-12-22 16:43:42 -080083 std::size_t total = 0;
84 try
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070085 {
William A. Kennington IIIb88c4572023-12-22 16:43:42 -080086 do
William A. Kennington IIIeac9d472020-08-03 13:57:14 -070087 {
Patrick Williamsd8e0af52024-08-16 15:21:12 -040088 auto r =
89 (fd.*fun)(data.subspan(total), std::forward<Args>(args)...);
William A. Kennington IIIb88c4572023-12-22 16:43:42 -080090 if (total != 0 && r.size() == 0)
91 {
92 throw exception::Incomplete(
93 std::format("{} is {}B/{}B", name, total % align, align));
94 }
95 total += r.size();
96 } while (total % align != 0);
97 }
98 catch (const std::system_error&)
99 {
100 if (total % align)
101 {
102 throw exception::Incomplete(
103 std::format("{} is {}B/{}B", name, total % align, align));
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700104 }
William A. Kennington IIIb88c4572023-12-22 16:43:42 -0800105 throw;
106 }
107 return std::span<Byte>(data.data(), total);
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700108}
109
Patrick Williams68975b92022-04-27 16:00:26 -0500110std::span<std::byte> readAligned(Fd& fd, size_t align, std::span<std::byte> buf)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700111{
112 return opAligned("readAligned", &Fd::read, fd, align, buf);
113}
114
Patrick Williams68975b92022-04-27 16:00:26 -0500115std::span<std::byte> recvAligned(Fd& fd, size_t align, std::span<std::byte> buf,
116 RecvFlags flags)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700117{
118 return opAligned("recvAligned", &Fd::recv, fd, align, buf, flags);
119}
120
Patrick Williams68975b92022-04-27 16:00:26 -0500121std::span<const std::byte> writeAligned(Fd& fd, size_t align,
122 std::span<const std::byte> data)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700123{
124 return opAligned("writeAligned", &Fd::write, fd, align, data);
125}
126
Patrick Williamsd8e0af52024-08-16 15:21:12 -0400127std::span<const std::byte> sendAligned(
128 Fd& fd, size_t align, std::span<const std::byte> data, SendFlags flags)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700129{
130 return opAligned("sendAligned", &Fd::send, fd, align, data, flags);
131}
132
William A. Kennington IIId589b1b2023-12-24 10:39:30 -0800133constexpr std::size_t maxStrideB = 65536;
134
135void readAll(Fd& fd, function_view<std::span<std::byte>(size_t req)> resize)
136{
137 std::size_t strideB = 256;
138 std::size_t totalB = 0;
139 auto doRead = [&]() {
140 auto buf = resize(totalB + strideB);
141 auto r = fd.read(buf.subspan(totalB));
142 if (r.size() == 0)
143 {
144 throw exception::WouldBlock("readAll");
145 }
146 totalB += r.size();
147 };
148 auto validateSize = [&]() {
149 auto buf = resize(totalB);
150 if (totalB != buf.size())
151 {
152 throw exception::Incomplete(
153 std::format("readAll extra {}B", buf.size() - totalB));
154 }
155 };
156 try
157 {
158 while (strideB < maxStrideB)
159 {
160 doRead();
161 if (totalB >= strideB)
162 {
163 strideB = strideB << 1;
164 }
165 }
166 while (true)
167 {
168 doRead();
169 }
170 }
171 catch (const exception::Eof&)
172 {
173 validateSize();
174 return;
175 }
176 catch (const std::system_error&)
177 {
178 validateSize();
179 throw;
180 }
181}
182
William A. Kennington III4829c9d2023-12-24 10:39:43 -0800183std::span<std::byte> readAllFixed(Fd& fd, size_t align,
184 std::span<std::byte> buf)
185{
186 std::size_t totalB = 0;
187 auto validateSize = [&]() {
188 if (totalB % align != 0)
189 {
190 throw exception::Incomplete(std::format(
191 "readAllFixed partial {}B/{}B", totalB % align, align));
192 }
193 };
194 try
195 {
196 while (totalB < buf.size())
197 {
198 auto r = fd.read(
199 buf.subspan(totalB, std::min(maxStrideB, buf.size() - totalB)));
200 if (r.size() == 0)
201 {
202 throw exception::WouldBlock("readAllFixed");
203 }
204 totalB += r.size();
205 }
206 std::byte b;
207 auto r = fd.read(std::span(&b, 1));
208 if (r.size() == 0)
209 {
210 throw exception::WouldBlock("readAllFixed");
211 }
212 throw std::system_error(
213 std::make_error_code(std::errc::value_too_large),
214 "readAllFixed overflow");
215 }
216 catch (const exception::Eof& e)
217 {
218 validateSize();
219 return buf.subspan(0, totalB);
220 }
221 catch (const std::system_error& e)
222 {
223 validateSize();
224 throw;
225 }
226}
227
William A. Kennington III4aec6d12024-01-08 15:28:34 -0800228void verifyExact(size_t expected, size_t actual)
229{
230 if (expected != actual)
231 {
232 throw exception::WouldBlock("verifyExact");
233 }
234}
235
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700236} // namespace detail
237} // namespace fd
238} // namespace stdplus