blob: ca549f793abdf34f5fb1ac81ecb3dd537dd3f48e [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 {
William A. Kennington III93ae9702023-12-22 16:41:17 -080023 auto r = (fd.*fun)(data.subspan(total),
24 std::forward<Args>(args)...);
25 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 Williams68975b92022-04-27 16:00:26 -050079static std::span<Byte> opAligned(const char* name, Fun&& fun, Fd& fd,
80 size_t align, std::span<Byte> data,
81 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 {
William A. Kennington IIIb88c4572023-12-22 16:43:42 -080088 auto r = (fd.*fun)(data.subspan(total),
89 std::forward<Args>(args)...);
90 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 Williams68975b92022-04-27 16:00:26 -0500127std::span<const std::byte> sendAligned(Fd& fd, size_t align,
128 std::span<const std::byte> data,
129 SendFlags flags)
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700130{
131 return opAligned("sendAligned", &Fd::send, fd, align, data, flags);
132}
133
William A. Kennington IIId589b1b2023-12-24 10:39:30 -0800134constexpr std::size_t maxStrideB = 65536;
135
136void readAll(Fd& fd, function_view<std::span<std::byte>(size_t req)> resize)
137{
138 std::size_t strideB = 256;
139 std::size_t totalB = 0;
140 auto doRead = [&]() {
141 auto buf = resize(totalB + strideB);
142 auto r = fd.read(buf.subspan(totalB));
143 if (r.size() == 0)
144 {
145 throw exception::WouldBlock("readAll");
146 }
147 totalB += r.size();
148 };
149 auto validateSize = [&]() {
150 auto buf = resize(totalB);
151 if (totalB != buf.size())
152 {
153 throw exception::Incomplete(
154 std::format("readAll extra {}B", buf.size() - totalB));
155 }
156 };
157 try
158 {
159 while (strideB < maxStrideB)
160 {
161 doRead();
162 if (totalB >= strideB)
163 {
164 strideB = strideB << 1;
165 }
166 }
167 while (true)
168 {
169 doRead();
170 }
171 }
172 catch (const exception::Eof&)
173 {
174 validateSize();
175 return;
176 }
177 catch (const std::system_error&)
178 {
179 validateSize();
180 throw;
181 }
182}
183
William A. Kennington III4829c9d2023-12-24 10:39:43 -0800184std::span<std::byte> readAllFixed(Fd& fd, size_t align,
185 std::span<std::byte> buf)
186{
187 std::size_t totalB = 0;
188 auto validateSize = [&]() {
189 if (totalB % align != 0)
190 {
191 throw exception::Incomplete(std::format(
192 "readAllFixed partial {}B/{}B", totalB % align, align));
193 }
194 };
195 try
196 {
197 while (totalB < buf.size())
198 {
199 auto r = fd.read(
200 buf.subspan(totalB, std::min(maxStrideB, buf.size() - totalB)));
201 if (r.size() == 0)
202 {
203 throw exception::WouldBlock("readAllFixed");
204 }
205 totalB += r.size();
206 }
207 std::byte b;
208 auto r = fd.read(std::span(&b, 1));
209 if (r.size() == 0)
210 {
211 throw exception::WouldBlock("readAllFixed");
212 }
213 throw std::system_error(
214 std::make_error_code(std::errc::value_too_large),
215 "readAllFixed overflow");
216 }
217 catch (const exception::Eof& e)
218 {
219 validateSize();
220 return buf.subspan(0, totalB);
221 }
222 catch (const std::system_error& e)
223 {
224 validateSize();
225 throw;
226 }
227}
228
William A. Kennington III4aec6d12024-01-08 15:28:34 -0800229void verifyExact(size_t expected, size_t actual)
230{
231 if (expected != actual)
232 {
233 throw exception::WouldBlock("verifyExact");
234 }
235}
236
William A. Kennington IIIeac9d472020-08-03 13:57:14 -0700237} // namespace detail
238} // namespace fd
239} // namespace stdplus