PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/3rdparty/libprocess/src/io.cpp

https://gitlab.com/wilane/mesos
C++ | 608 lines | 396 code | 101 blank | 111 comment | 72 complexity | c701f52174e25df95613c0183b496123 MD5 | raw file
  1. // Licensed under the Apache License, Version 2.0 (the "License");
  2. // you may not use this file except in compliance with the License.
  3. // You may obtain a copy of the License at
  4. //
  5. // http://www.apache.org/licenses/LICENSE-2.0
  6. //
  7. // Unless required by applicable law or agreed to in writing, software
  8. // distributed under the License is distributed on an "AS IS" BASIS,
  9. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. // See the License for the specific language governing permissions and
  11. // limitations under the License
  12. #include <memory>
  13. #include <string>
  14. #include <boost/shared_array.hpp>
  15. #include <process/future.hpp>
  16. #include <process/io.hpp>
  17. #include <process/process.hpp> // For process::initialize.
  18. #include <stout/lambda.hpp>
  19. #include <stout/nothing.hpp>
  20. #include <stout/os.hpp>
  21. #include <stout/os/read.hpp>
  22. #include <stout/os/strerror.hpp>
  23. #include <stout/os/write.hpp>
  24. #include <stout/try.hpp>
  25. using std::string;
  26. namespace process {
  27. namespace io {
  28. namespace internal {
  29. enum ReadFlags
  30. {
  31. NONE = 0,
  32. PEEK
  33. };
  34. void read(
  35. int fd,
  36. void* data,
  37. size_t size,
  38. ReadFlags flags,
  39. const std::shared_ptr<Promise<size_t>>& promise,
  40. const Future<short>& future)
  41. {
  42. // Ignore this function if the read operation has been discarded.
  43. if (promise->future().hasDiscard()) {
  44. CHECK(!future.isPending());
  45. promise->discard();
  46. return;
  47. }
  48. if (size == 0) {
  49. promise->set(0);
  50. return;
  51. }
  52. if (future.isDiscarded()) {
  53. promise->fail("Failed to poll: discarded future");
  54. } else if (future.isFailed()) {
  55. promise->fail(future.failure());
  56. } else {
  57. ssize_t length;
  58. if (flags == NONE) {
  59. length = os::read(fd, data, size);
  60. } else { // PEEK.
  61. // In case 'fd' is not a socket ::recv() will fail with ENOTSOCK and the
  62. // error will be propagted out.
  63. // NOTE: We cast to `char*` here because the function prototypes on
  64. // Windows use `char*` instead of `void*`.
  65. length = ::recv(fd, (char*) data, size, MSG_PEEK);
  66. }
  67. #ifdef __WINDOWS__
  68. int error = WSAGetLastError();
  69. #else
  70. int error = errno;
  71. #endif // __WINDOWS__
  72. if (length < 0) {
  73. if (net::is_restartable_error(error) || net::is_retryable_error(error)) {
  74. // Restart the read operation.
  75. Future<short> future =
  76. io::poll(fd, process::io::READ).onAny(
  77. lambda::bind(&internal::read,
  78. fd,
  79. data,
  80. size,
  81. flags,
  82. promise,
  83. lambda::_1));
  84. // Stop polling if a discard occurs on our future.
  85. promise->future().onDiscard(
  86. lambda::bind(&process::internal::discard<short>,
  87. WeakFuture<short>(future)));
  88. } else {
  89. // Error occurred.
  90. promise->fail(os::strerror(errno));
  91. }
  92. } else {
  93. promise->set(length);
  94. }
  95. }
  96. }
  97. void write(
  98. int fd,
  99. const void* data,
  100. size_t size,
  101. const std::shared_ptr<Promise<size_t>>& promise,
  102. const Future<short>& future)
  103. {
  104. // Ignore this function if the write operation has been discarded.
  105. if (promise->future().hasDiscard()) {
  106. promise->discard();
  107. return;
  108. }
  109. if (size == 0) {
  110. promise->set(0);
  111. return;
  112. }
  113. if (future.isDiscarded()) {
  114. promise->fail("Failed to poll: discarded future");
  115. } else if (future.isFailed()) {
  116. promise->fail(future.failure());
  117. } else {
  118. ssize_t length = os::write(fd, data, size);
  119. #ifdef __WINDOWS__
  120. int error = WSAGetLastError();
  121. #else
  122. int error = errno;
  123. #endif // __WINDOWS__
  124. if (length < 0) {
  125. if (net::is_restartable_error(error) || net::is_retryable_error(error)) {
  126. // Restart the write operation.
  127. Future<short> future =
  128. io::poll(fd, process::io::WRITE).onAny(
  129. lambda::bind(&internal::write,
  130. fd,
  131. data,
  132. size,
  133. promise,
  134. lambda::_1));
  135. // Stop polling if a discard occurs on our future.
  136. promise->future().onDiscard(
  137. lambda::bind(&process::internal::discard<short>,
  138. WeakFuture<short>(future)));
  139. } else {
  140. // Error occurred.
  141. promise->fail(os::strerror(errno));
  142. }
  143. } else {
  144. // TODO(benh): Retry if 'length' is 0?
  145. promise->set(length);
  146. }
  147. }
  148. }
  149. } // namespace internal {
  150. Future<size_t> read(int fd, void* data, size_t size)
  151. {
  152. process::initialize();
  153. std::shared_ptr<Promise<size_t>> promise(new Promise<size_t>());
  154. // Check the file descriptor.
  155. Try<bool> nonblock = os::isNonblock(fd);
  156. if (nonblock.isError()) {
  157. // The file descriptor is not valid (e.g., has been closed).
  158. promise->fail(
  159. "Failed to check if file descriptor was non-blocking: " +
  160. nonblock.error());
  161. return promise->future();
  162. } else if (!nonblock.get()) {
  163. // The file descriptor is not non-blocking.
  164. promise->fail("Expected a non-blocking file descriptor");
  165. return promise->future();
  166. }
  167. // Because the file descriptor is non-blocking, we call read()
  168. // immediately. The read may in turn call poll if necessary,
  169. // avoiding unnecessary polling. We also observed that for some
  170. // combination of libev and Linux kernel versions, the poll would
  171. // block for non-deterministically long periods of time. This may be
  172. // fixed in a newer version of libev (we use 3.8 at the time of
  173. // writing this comment).
  174. internal::read(fd, data, size, internal::NONE, promise, io::READ);
  175. return promise->future();
  176. }
  177. Future<size_t> write(int fd, const void* data, size_t size)
  178. {
  179. process::initialize();
  180. std::shared_ptr<Promise<size_t>> promise(new Promise<size_t>());
  181. // Check the file descriptor.
  182. Try<bool> nonblock = os::isNonblock(fd);
  183. if (nonblock.isError()) {
  184. // The file descriptor is not valid (e.g., has been closed).
  185. promise->fail(
  186. "Failed to check if file descriptor was non-blocking: " +
  187. nonblock.error());
  188. return promise->future();
  189. } else if (!nonblock.get()) {
  190. // The file descriptor is not non-blocking.
  191. promise->fail("Expected a non-blocking file descriptor");
  192. return promise->future();
  193. }
  194. // Because the file descriptor is non-blocking, we call write()
  195. // immediately. The write may in turn call poll if necessary,
  196. // avoiding unnecessary polling. We also observed that for some
  197. // combination of libev and Linux kernel versions, the poll would
  198. // block for non-deterministically long periods of time. This may be
  199. // fixed in a newer version of libev (we use 3.8 at the time of
  200. // writing this comment).
  201. internal::write(fd, data, size, promise, io::WRITE);
  202. return promise->future();
  203. }
  204. Future<size_t> peek(int fd, void* data, size_t size, size_t limit)
  205. {
  206. process::initialize();
  207. // Make sure that the buffer is large enough.
  208. if (size < limit) {
  209. return Failure("Expected a large enough data buffer");
  210. }
  211. // Get our own copy of the file descriptor so that we're in control
  212. // of the lifetime and don't crash if/when someone by accidently
  213. // closes the file descriptor before discarding this future. We can
  214. // also make sure it's non-blocking and will close-on-exec. Start by
  215. // checking we've got a "valid" file descriptor before dup'ing.
  216. if (fd < 0) {
  217. return Failure(os::strerror(EBADF));
  218. }
  219. fd = dup(fd);
  220. if (fd == -1) {
  221. return Failure(ErrnoError("Failed to duplicate file descriptor"));
  222. }
  223. // Set the close-on-exec flag.
  224. Try<Nothing> cloexec = os::cloexec(fd);
  225. if (cloexec.isError()) {
  226. os::close(fd);
  227. return Failure(
  228. "Failed to set close-on-exec on duplicated file descriptor: " +
  229. cloexec.error());
  230. }
  231. // Make the file descriptor non-blocking.
  232. Try<Nothing> nonblock = os::nonblock(fd);
  233. if (nonblock.isError()) {
  234. os::close(fd);
  235. return Failure(
  236. "Failed to make duplicated file descriptor non-blocking: " +
  237. nonblock.error());
  238. }
  239. std::shared_ptr<Promise<size_t>> promise(new Promise<size_t>());
  240. // Because the file descriptor is non-blocking, we call read()
  241. // immediately. The read may in turn call poll if necessary,
  242. // avoiding unnecessary polling. We also observed that for some
  243. // combination of libev and Linux kernel versions, the poll would
  244. // block for non-deterministically long periods of time. This may be
  245. // fixed in a newer version of libev (we use 3.8 at the time of
  246. // writing this comment).
  247. internal::read(fd, data, limit, internal::PEEK, promise, io::READ);
  248. // NOTE: We wrap `os::close` in a lambda to disambiguate on Windows.
  249. promise->future().onAny([fd]() { os::close(fd); });
  250. return promise->future();
  251. }
  252. namespace internal {
  253. Future<string> _read(
  254. int fd,
  255. const std::shared_ptr<string>& buffer,
  256. const boost::shared_array<char>& data,
  257. size_t length)
  258. {
  259. return io::read(fd, data.get(), length)
  260. .then([=](size_t size) -> Future<string> {
  261. if (size == 0) { // EOF.
  262. return string(*buffer);
  263. }
  264. buffer->append(data.get(), size);
  265. return _read(fd, buffer, data, length);
  266. });
  267. }
  268. Future<Nothing> _write(
  269. int fd,
  270. Owned<string> data,
  271. size_t index)
  272. {
  273. return io::write(fd, data->data() + index, data->size() - index)
  274. .then([=](size_t length) -> Future<Nothing> {
  275. if (index + length == data->size()) {
  276. return Nothing();
  277. }
  278. return _write(fd, data, index + length);
  279. });
  280. }
  281. void _splice(
  282. int from,
  283. int to,
  284. size_t chunk,
  285. boost::shared_array<char> data,
  286. std::shared_ptr<Promise<Nothing>> promise)
  287. {
  288. // Stop splicing if a discard occurred on our future.
  289. if (promise->future().hasDiscard()) {
  290. // TODO(benh): Consider returning the number of bytes already
  291. // spliced on discarded, or a failure. Same for the 'onDiscarded'
  292. // callbacks below.
  293. promise->discard();
  294. return;
  295. }
  296. // Note that only one of io::read or io::write is outstanding at any
  297. // one point in time thus the reuse of 'data' for both operations.
  298. Future<size_t> read = io::read(from, data.get(), chunk);
  299. // Stop reading (or potentially indefinitely polling) if a discard
  300. // occcurs on our future.
  301. promise->future().onDiscard(
  302. lambda::bind(&process::internal::discard<size_t>,
  303. WeakFuture<size_t>(read)));
  304. read
  305. .onReady([=](size_t size) {
  306. if (size == 0) { // EOF.
  307. promise->set(Nothing());
  308. } else {
  309. // Note that we always try and complete the write, even if a
  310. // discard has occurred on our future, in order to provide
  311. // semantics where everything read is written. The promise
  312. // will eventually be discarded in the next read.
  313. io::write(to, string(data.get(), size))
  314. .onReady([=]() { _splice(from, to, chunk, data, promise); })
  315. .onFailed([=](const string& message) { promise->fail(message); })
  316. .onDiscarded([=]() { promise->discard(); });
  317. }
  318. })
  319. .onFailed([=](const string& message) { promise->fail(message); })
  320. .onDiscarded([=]() { promise->discard(); });
  321. }
  322. Future<Nothing> splice(int from, int to, size_t chunk)
  323. {
  324. boost::shared_array<char> data(new char[chunk]);
  325. // Rather than having internal::_splice return a future and
  326. // implementing internal::_splice as a chain of io::read and
  327. // io::write calls, we use an explicit promise that we pass around
  328. // so that we don't increase memory usage the longer that we splice.
  329. std::shared_ptr<Promise<Nothing>> promise(new Promise<Nothing>());
  330. Future<Nothing> future = promise->future();
  331. _splice(from, to, chunk, data, promise);
  332. return future;
  333. }
  334. } // namespace internal {
  335. Future<string> read(int fd)
  336. {
  337. process::initialize();
  338. // Get our own copy of the file descriptor so that we're in control
  339. // of the lifetime and don't crash if/when someone by accidently
  340. // closes the file descriptor before discarding this future. We can
  341. // also make sure it's non-blocking and will close-on-exec. Start by
  342. // checking we've got a "valid" file descriptor before dup'ing.
  343. if (fd < 0) {
  344. return Failure(os::strerror(EBADF));
  345. }
  346. fd = dup(fd);
  347. if (fd == -1) {
  348. return Failure(ErrnoError("Failed to duplicate file descriptor"));
  349. }
  350. // Set the close-on-exec flag.
  351. Try<Nothing> cloexec = os::cloexec(fd);
  352. if (cloexec.isError()) {
  353. os::close(fd);
  354. return Failure(
  355. "Failed to set close-on-exec on duplicated file descriptor: " +
  356. cloexec.error());
  357. }
  358. // Make the file descriptor non-blocking.
  359. Try<Nothing> nonblock = os::nonblock(fd);
  360. if (nonblock.isError()) {
  361. os::close(fd);
  362. return Failure(
  363. "Failed to make duplicated file descriptor non-blocking: " +
  364. nonblock.error());
  365. }
  366. // TODO(benh): Wrap up this data as a struct, use 'Owner'.
  367. // TODO(bmahler): For efficiency, use a rope for the buffer.
  368. std::shared_ptr<string> buffer(new string());
  369. boost::shared_array<char> data(new char[BUFFERED_READ_SIZE]);
  370. // NOTE: We wrap `os::close` in a lambda to disambiguate on Windows.
  371. return internal::_read(fd, buffer, data, BUFFERED_READ_SIZE)
  372. .onAny([fd]() { os::close(fd); });
  373. }
  374. #ifdef __WINDOWS__
  375. // NOTE: Ordinarily this would go in a Windows-specific header; we put it here
  376. // to avoid complex forward declarations.
  377. Future<string> read(HANDLE handle)
  378. {
  379. return read(_open_osfhandle(reinterpret_cast<intptr_t>(handle), O_RDONLY));
  380. }
  381. #endif // __WINDOWS__
  382. Future<Nothing> write(int fd, const string& data)
  383. {
  384. process::initialize();
  385. // Get our own copy of the file descriptor so that we're in control
  386. // of the lifetime and don't crash if/when someone by accidently
  387. // closes the file descriptor before discarding this future. We can
  388. // also make sure it's non-blocking and will close-on-exec. Start by
  389. // checking we've got a "valid" file descriptor before dup'ing.
  390. if (fd < 0) {
  391. return Failure(os::strerror(EBADF));
  392. }
  393. fd = dup(fd);
  394. if (fd == -1) {
  395. return Failure(ErrnoError("Failed to duplicate file descriptor"));
  396. }
  397. // Set the close-on-exec flag.
  398. Try<Nothing> cloexec = os::cloexec(fd);
  399. if (cloexec.isError()) {
  400. os::close(fd);
  401. return Failure(
  402. "Failed to set close-on-exec on duplicated file descriptor: " +
  403. cloexec.error());
  404. }
  405. // Make the file descriptor non-blocking.
  406. Try<Nothing> nonblock = os::nonblock(fd);
  407. if (nonblock.isError()) {
  408. os::close(fd);
  409. return Failure(
  410. "Failed to make duplicated file descriptor non-blocking: " +
  411. nonblock.error());
  412. }
  413. // NOTE: We wrap `os::close` in a lambda to disambiguate on Windows.
  414. return internal::_write(fd, Owned<string>(new string(data)), 0)
  415. .onAny([fd]() { os::close(fd); });
  416. }
  417. Future<Nothing> redirect(int from, Option<int> to, size_t chunk)
  418. {
  419. // Make sure we've got "valid" file descriptors.
  420. if (from < 0 || (to.isSome() && to.get() < 0)) {
  421. return Failure(os::strerror(EBADF));
  422. }
  423. if (to.isNone()) {
  424. // Open up /dev/null that we can splice into.
  425. Try<int> open = os::open("/dev/null", O_WRONLY | O_CLOEXEC);
  426. if (open.isError()) {
  427. return Failure("Failed to open /dev/null for writing: " + open.error());
  428. }
  429. to = open.get();
  430. } else {
  431. // Duplicate 'to' so that we're in control of its lifetime.
  432. int fd = dup(to.get());
  433. if (fd == -1) {
  434. return Failure(ErrnoError("Failed to duplicate 'to' file descriptor"));
  435. }
  436. to = fd;
  437. }
  438. CHECK_SOME(to);
  439. // Duplicate 'from' so that we're in control of its lifetime.
  440. from = dup(from);
  441. if (from == -1) {
  442. os::close(to.get());
  443. return Failure(ErrnoError("Failed to duplicate 'from' file descriptor"));
  444. }
  445. // Set the close-on-exec flag (no-op if already set).
  446. Try<Nothing> cloexec = os::cloexec(from);
  447. if (cloexec.isError()) {
  448. os::close(from);
  449. os::close(to.get());
  450. return Failure("Failed to set close-on-exec on 'from': " + cloexec.error());
  451. }
  452. cloexec = os::cloexec(to.get());
  453. if (cloexec.isError()) {
  454. os::close(from);
  455. os::close(to.get());
  456. return Failure("Failed to set close-on-exec on 'to': " + cloexec.error());
  457. }
  458. // Make the file descriptors non-blocking (no-op if already set).
  459. Try<Nothing> nonblock = os::nonblock(from);
  460. if (nonblock.isError()) {
  461. os::close(from);
  462. os::close(to.get());
  463. return Failure("Failed to make 'from' non-blocking: " + nonblock.error());
  464. }
  465. nonblock = os::nonblock(to.get());
  466. if (nonblock.isError()) {
  467. os::close(from);
  468. os::close(to.get());
  469. return Failure("Failed to make 'to' non-blocking: " + nonblock.error());
  470. }
  471. // NOTE: We wrap `os::close` in a lambda to disambiguate on Windows.
  472. return internal::splice(from, to.get(), chunk)
  473. .onAny([from]() { os::close(from); })
  474. .onAny([to]() { os::close(to.get()); });
  475. }
  476. #ifdef __WINDOWS__
  477. // NOTE: Ordinarily this would go in a Windows-specific header; we put it here
  478. // to avoid complex forward declarations.
  479. Future<Nothing> redirect(HANDLE from, Option<int> to, size_t chunk)
  480. {
  481. return redirect(
  482. _open_osfhandle(reinterpret_cast<intptr_t>(from), O_RDWR),
  483. to,
  484. chunk);
  485. }
  486. #endif // __WINDOWS__
  487. // TODO(hartem): Most of the boilerplate code here is the same as
  488. // in io::read, so this needs to be refactored.
  489. Future<string> peek(int fd, size_t limit)
  490. {
  491. process::initialize();
  492. if (limit > BUFFERED_READ_SIZE) {
  493. return Failure("Expected the number of bytes to be less than " +
  494. stringify(BUFFERED_READ_SIZE));
  495. }
  496. // TODO(benh): Wrap up this data as a struct, use 'Owner'.
  497. boost::shared_array<char> data(new char[BUFFERED_READ_SIZE]);
  498. return io::peek(fd, data.get(), BUFFERED_READ_SIZE, limit)
  499. .then([=](size_t length) -> Future<string> {
  500. // At this point we have to return whatever data we were able to
  501. // peek, because we can not rely on peeking across message
  502. // boundaries.
  503. return string(data.get(), length);
  504. });
  505. }
  506. } // namespace io {
  507. } // namespace process {