| 240 | |
| 241 | |
| 242 | Future<size_t> PollSocketImpl::sendfile(int_fd fd, off_t offset, size_t size) |
| 243 | { |
| 244 | CHECK(size > 0); // TODO(benh): Just return 0 if `size` is 0? |
| 245 | |
| 246 | // Need to hold a copy of `this` so that the underlying socket |
| 247 | // doesn't end up getting reused before we return. |
| 248 | auto self = shared(this); |
| 249 | |
| 250 | return loop( |
| 251 | None(), |
| 252 | [self, fd, offset, size]() -> Future<Option<size_t>> { |
| 253 | while (true) { |
| 254 | Try<ssize_t, SocketError> length = os::sendfile( |
| 255 | self->get(), |
| 256 | fd, |
| 257 | offset, |
| 258 | size); |
| 259 | |
| 260 | if (length.isSome()) { |
| 261 | CHECK(length.get() >= 0); |
| 262 | return length.get(); |
| 263 | } |
| 264 | |
| 265 | if (net::is_restartable_error(length.error().code)) { |
| 266 | // Interrupted, try again now. |
| 267 | continue; |
| 268 | } else if (!net::is_retryable_error(length.error().code)) { |
| 269 | VLOG(1) << length.error().message; |
| 270 | return Failure(length.error()); |
| 271 | } |
| 272 | |
| 273 | return None(); |
| 274 | } |
| 275 | }, |
| 276 | [self](const Option<size_t>& length) -> Future<ControlFlow<size_t>> { |
| 277 | // Retry after we've polled if we don't yet have a result. |
| 278 | if (length.isNone()) { |
| 279 | return io::poll(self->get(), io::WRITE) |
| 280 | .then([](short event) -> ControlFlow<size_t> { |
| 281 | CHECK_EQ(io::WRITE, event); |
| 282 | return Continue(); |
| 283 | }); |
| 284 | } |
| 285 | return Break(length.get()); |
| 286 | }); |
| 287 | } |
| 288 | |
| 289 | } // namespace internal { |
| 290 | } // namespace network { |
no test coverage detected