| 183 | |
| 184 | |
| 185 | Future<size_t> PollSocketImpl::send(const char* data, size_t size) |
| 186 | { |
| 187 | CHECK(size > 0); // TODO(benh): Just return 0 if `size` is 0? |
| 188 | |
| 189 | // Need to hold a copy of `this` so that the underlying socket |
| 190 | // doesn't end up getting reused before we return. |
| 191 | auto self = shared(this); |
| 192 | |
| 193 | // TODO(benh): Reuse `io::write`? Or is `net::send` and |
| 194 | // `MSG_NOSIGNAL` critical here? |
| 195 | return loop( |
| 196 | None(), |
| 197 | [self, data, size]() -> Future<Option<size_t>> { |
| 198 | while (true) { |
| 199 | ssize_t length = net::send(self->get(), data, size, MSG_NOSIGNAL); |
| 200 | |
| 201 | if (length < 0) { |
| 202 | #ifdef __WINDOWS__ |
| 203 | int error = WSAGetLastError(); |
| 204 | #else |
| 205 | int error = errno; |
| 206 | #endif // __WINDOWS__ |
| 207 | |
| 208 | if (net::is_restartable_error(error)) { |
| 209 | // Interrupted, try again now. |
| 210 | continue; |
| 211 | } else if (!net::is_retryable_error(error)) { |
| 212 | // TODO(benh): Confirm that `os::strerror` does the |
| 213 | // right thing for `error` on Windows. |
| 214 | VLOG(1) << "Socket error while sending: " << os::strerror(error); |
| 215 | return Failure(os::strerror(error)); |
| 216 | } |
| 217 | |
| 218 | return None(); |
| 219 | } |
| 220 | |
| 221 | return length; |
| 222 | } |
| 223 | }, |
| 224 | [self](const Option<size_t>& length) -> Future<ControlFlow<size_t>> { |
| 225 | // Retry after we've polled if we don't yet have a result. |
| 226 | if (length.isNone()) { |
| 227 | return io::poll(self->get(), io::WRITE) |
| 228 | .then([](short event) -> ControlFlow<size_t> { |
| 229 | CHECK_EQ(io::WRITE, event); |
| 230 | return Continue(); |
| 231 | }); |
| 232 | } |
| 233 | return Break(length.get()); |
| 234 | }); |
| 235 | } |
| 236 | |
| 237 | |
| 238 | Future<size_t> PollSocketImpl::sendfile(int_fd fd, off_t offset, size_t size) |