async_pipe.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // Copyright (c) 2016 Klemens D. Morgenstern
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
  6. #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
  7. #include <boost/process/detail/posix/basic_pipe.hpp>
  8. #include <boost/asio/posix/stream_descriptor.hpp>
  9. #include <boost/asio/post.hpp>
  10. #include <system_error>
  11. #include <string>
  12. #include <utility>
  13. namespace boost { namespace process { namespace detail { namespace posix {
  14. class async_pipe
  15. {
  16. ::boost::asio::posix::stream_descriptor _source;
  17. ::boost::asio::posix::stream_descriptor _sink ;
  18. public:
  19. typedef int native_handle_type;
  20. typedef ::boost::asio::posix::stream_descriptor handle_type;
  21. typedef typename handle_type::executor_type executor_type;
  22. inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
  23. inline async_pipe(boost::asio::io_context & ios_source,
  24. boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink)
  25. {
  26. int fds[2];
  27. if (::pipe(fds) == -1)
  28. boost::process::detail::throw_last_error("pipe(2) failed");
  29. _source.assign(fds[0]);
  30. _sink .assign(fds[1]);
  31. };
  32. inline async_pipe(boost::asio::io_context & ios, const std::string & name)
  33. : async_pipe(ios, ios, name) {}
  34. inline async_pipe(boost::asio::io_context & ios_source,
  35. boost::asio::io_context & io_sink, const std::string & name);
  36. inline async_pipe(const async_pipe& lhs);
  37. async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
  38. {
  39. lhs._source.assign (-1);
  40. lhs._sink .assign (-1);
  41. }
  42. template<class CharT, class Traits = std::char_traits<CharT>>
  43. explicit async_pipe(::boost::asio::io_context & ios_source,
  44. ::boost::asio::io_context & ios_sink,
  45. const basic_pipe<CharT, Traits> & p)
  46. : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
  47. {
  48. }
  49. template<class CharT, class Traits = std::char_traits<CharT>>
  50. explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
  51. : async_pipe(ios, ios, p)
  52. {
  53. }
  54. template<class CharT, class Traits = std::char_traits<CharT>>
  55. inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
  56. inline async_pipe& operator=(const async_pipe& rhs);
  57. inline async_pipe& operator=(async_pipe&& lhs);
  58. ~async_pipe()
  59. {
  60. if (_sink .native_handle() != -1)
  61. ::close(_sink.native_handle());
  62. if (_source.native_handle() != -1)
  63. ::close(_source.native_handle());
  64. }
  65. template<class CharT, class Traits = std::char_traits<CharT>>
  66. inline explicit operator basic_pipe<CharT, Traits>() const;
  67. void cancel()
  68. {
  69. if (_sink.is_open())
  70. _sink.cancel();
  71. if (_source.is_open())
  72. _source.cancel();
  73. }
  74. void close()
  75. {
  76. if (_sink.is_open())
  77. _sink.close();
  78. if (_source.is_open())
  79. _source.close();
  80. }
  81. void close(boost::system::error_code & ec)
  82. {
  83. if (_sink.is_open())
  84. _sink.close(ec);
  85. if (_source.is_open())
  86. _source.close(ec);
  87. }
  88. bool is_open() const
  89. {
  90. return _sink.is_open() || _source.is_open();
  91. }
  92. void async_close()
  93. {
  94. if (_sink.is_open())
  95. boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
  96. if (_source.is_open())
  97. boost::asio::post(_source.get_executor(), [this]{_source.close();});
  98. }
  99. template<typename MutableBufferSequence>
  100. std::size_t read_some(const MutableBufferSequence & buffers)
  101. {
  102. return _source.read_some(buffers);
  103. }
  104. template<typename MutableBufferSequence>
  105. std::size_t write_some(const MutableBufferSequence & buffers)
  106. {
  107. return _sink.write_some(buffers);
  108. }
  109. template<typename MutableBufferSequence>
  110. std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
  111. {
  112. return _source.read_some(buffers, ec);
  113. }
  114. template<typename MutableBufferSequence>
  115. std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
  116. {
  117. return _sink.write_some(buffers, ec);
  118. }
  119. native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();}
  120. native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
  121. template<typename MutableBufferSequence,
  122. typename ReadHandler>
  123. BOOST_ASIO_INITFN_RESULT_TYPE(
  124. ReadHandler, void(boost::system::error_code, std::size_t))
  125. async_read_some(
  126. const MutableBufferSequence & buffers,
  127. ReadHandler &&handler)
  128. {
  129. return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
  130. }
  131. template<typename ConstBufferSequence,
  132. typename WriteHandler>
  133. BOOST_ASIO_INITFN_RESULT_TYPE(
  134. WriteHandler, void(boost::system::error_code, std::size_t))
  135. async_write_some(
  136. const ConstBufferSequence & buffers,
  137. WriteHandler&& handler)
  138. {
  139. return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
  140. }
  141. const handle_type & sink () const & {return _sink;}
  142. const handle_type & source() const & {return _source;}
  143. handle_type && sink() && { return std::move(_sink); }
  144. handle_type && source()&& { return std::move(_source); }
  145. handle_type source(::boost::asio::io_context& ios) &&
  146. {
  147. ::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
  148. return stolen;
  149. }
  150. handle_type sink (::boost::asio::io_context& ios) &&
  151. {
  152. ::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
  153. return stolen;
  154. }
  155. handle_type source(::boost::asio::io_context& ios) const &
  156. {
  157. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
  158. return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
  159. }
  160. handle_type sink (::boost::asio::io_context& ios) const &
  161. {
  162. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
  163. return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
  164. }
  165. };
  166. async_pipe::async_pipe(boost::asio::io_context & ios_source,
  167. boost::asio::io_context & ios_sink,
  168. const std::string & name) : _source(ios_source), _sink(ios_sink)
  169. {
  170. auto fifo = mkfifo(name.c_str(), 0666 );
  171. if (fifo != 0)
  172. boost::process::detail::throw_last_error("mkfifo() failed");
  173. int read_fd = open(name.c_str(), O_RDWR);
  174. if (read_fd == -1)
  175. boost::process::detail::throw_last_error();
  176. int write_fd = dup(read_fd);
  177. if (write_fd == -1)
  178. boost::process::detail::throw_last_error();
  179. _source.assign(read_fd);
  180. _sink .assign(write_fd);
  181. }
  182. async_pipe::async_pipe(const async_pipe & p) :
  183. _source(const_cast<async_pipe&>(p)._source.get_executor()),
  184. _sink( const_cast<async_pipe&>(p)._sink.get_executor())
  185. {
  186. //cannot get the handle from a const object.
  187. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
  188. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
  189. if (source_in == -1)
  190. _source.assign(-1);
  191. else
  192. {
  193. _source.assign(::dup(source_in));
  194. if (_source.native_handle()== -1)
  195. ::boost::process::detail::throw_last_error("dup()");
  196. }
  197. if (sink_in == -1)
  198. _sink.assign(-1);
  199. else
  200. {
  201. _sink.assign(::dup(sink_in));
  202. if (_sink.native_handle() == -1)
  203. ::boost::process::detail::throw_last_error("dup()");
  204. }
  205. }
  206. async_pipe& async_pipe::operator=(const async_pipe & p)
  207. {
  208. int source;
  209. int sink;
  210. //cannot get the handle from a const object.
  211. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle();
  212. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle();
  213. if (source_in == -1)
  214. source = -1;
  215. else
  216. {
  217. source = ::dup(source_in);
  218. if (source == -1)
  219. ::boost::process::detail::throw_last_error("dup()");
  220. }
  221. if (sink_in == -1)
  222. sink = -1;
  223. else
  224. {
  225. sink = ::dup(sink_in);
  226. if (sink == -1)
  227. ::boost::process::detail::throw_last_error("dup()");
  228. }
  229. _source.assign(source);
  230. _sink. assign(sink);
  231. return *this;
  232. }
  233. async_pipe& async_pipe::operator=(async_pipe && lhs)
  234. {
  235. std::swap(_source, lhs._source);
  236. std::swap(_sink, lhs._sink);
  237. return *this;
  238. }
  239. template<class CharT, class Traits>
  240. async_pipe::operator basic_pipe<CharT, Traits>() const
  241. {
  242. int source;
  243. int sink;
  244. //cannot get the handle from a const object.
  245. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
  246. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
  247. if (source_in == -1)
  248. source = -1;
  249. else
  250. {
  251. source = ::dup(source_in);
  252. if (source == -1)
  253. ::boost::process::detail::throw_last_error("dup()");
  254. }
  255. if (sink_in == -1)
  256. sink = -1;
  257. else
  258. {
  259. sink = ::dup(sink_in);
  260. if (sink == -1)
  261. ::boost::process::detail::throw_last_error("dup()");
  262. }
  263. return basic_pipe<CharT, Traits>{source, sink};
  264. }
  265. inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
  266. {
  267. return compare_handles(lhs.native_source(), rhs.native_source()) &&
  268. compare_handles(lhs.native_sink(), rhs.native_sink());
  269. }
  270. inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
  271. {
  272. return !compare_handles(lhs.native_source(), rhs.native_source()) ||
  273. !compare_handles(lhs.native_sink(), rhs.native_sink());
  274. }
  275. template<class Char, class Traits>
  276. inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
  277. {
  278. return compare_handles(lhs.native_source(), rhs.native_source()) &&
  279. compare_handles(lhs.native_sink(), rhs.native_sink());
  280. }
  281. template<class Char, class Traits>
  282. inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
  283. {
  284. return !compare_handles(lhs.native_source(), rhs.native_source()) ||
  285. !compare_handles(lhs.native_sink(), rhs.native_sink());
  286. }
  287. template<class Char, class Traits>
  288. inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
  289. {
  290. return compare_handles(lhs.native_source(), rhs.native_source()) &&
  291. compare_handles(lhs.native_sink(), rhs.native_sink());
  292. }
  293. template<class Char, class Traits>
  294. inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
  295. {
  296. return !compare_handles(lhs.native_source(), rhs.native_source()) ||
  297. !compare_handles(lhs.native_sink(), rhs.native_sink());
  298. }
  299. }}}}
  300. #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */