async_pipe.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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. boost::system::error_code ec;
  61. close(ec);
  62. }
  63. template<class CharT, class Traits = std::char_traits<CharT>>
  64. inline explicit operator basic_pipe<CharT, Traits>() const;
  65. void cancel()
  66. {
  67. if (_sink.is_open())
  68. _sink.cancel();
  69. if (_source.is_open())
  70. _source.cancel();
  71. }
  72. void close()
  73. {
  74. if (_sink.is_open())
  75. _sink.close();
  76. if (_source.is_open())
  77. _source.close();
  78. }
  79. void close(boost::system::error_code & ec)
  80. {
  81. if (_sink.is_open())
  82. _sink.close(ec);
  83. if (_source.is_open())
  84. _source.close(ec);
  85. }
  86. bool is_open() const
  87. {
  88. return _sink.is_open() || _source.is_open();
  89. }
  90. void async_close()
  91. {
  92. if (_sink.is_open())
  93. boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
  94. if (_source.is_open())
  95. boost::asio::post(_source.get_executor(), [this]{_source.close();});
  96. }
  97. template<typename MutableBufferSequence>
  98. std::size_t read_some(const MutableBufferSequence & buffers)
  99. {
  100. return _source.read_some(buffers);
  101. }
  102. template<typename MutableBufferSequence>
  103. std::size_t write_some(const MutableBufferSequence & buffers)
  104. {
  105. return _sink.write_some(buffers);
  106. }
  107. template<typename MutableBufferSequence>
  108. std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
  109. {
  110. return _source.read_some(buffers, ec);
  111. }
  112. template<typename MutableBufferSequence>
  113. std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
  114. {
  115. return _sink.write_some(buffers, ec);
  116. }
  117. native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();}
  118. native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
  119. template<typename MutableBufferSequence,
  120. typename ReadHandler>
  121. BOOST_ASIO_INITFN_RESULT_TYPE(
  122. ReadHandler, void(boost::system::error_code, std::size_t))
  123. async_read_some(
  124. const MutableBufferSequence & buffers,
  125. ReadHandler &&handler)
  126. {
  127. return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
  128. }
  129. template<typename ConstBufferSequence,
  130. typename WriteHandler>
  131. BOOST_ASIO_INITFN_RESULT_TYPE(
  132. WriteHandler, void(boost::system::error_code, std::size_t))
  133. async_write_some(
  134. const ConstBufferSequence & buffers,
  135. WriteHandler&& handler)
  136. {
  137. return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
  138. }
  139. const handle_type & sink () const & {return _sink;}
  140. const handle_type & source() const & {return _source;}
  141. handle_type && sink() && { return std::move(_sink); }
  142. handle_type && source()&& { return std::move(_source); }
  143. handle_type source(::boost::asio::io_context& ios) &&
  144. {
  145. ::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
  146. return stolen;
  147. }
  148. handle_type sink (::boost::asio::io_context& ios) &&
  149. {
  150. ::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
  151. return stolen;
  152. }
  153. handle_type source(::boost::asio::io_context& ios) const &
  154. {
  155. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
  156. return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
  157. }
  158. handle_type sink (::boost::asio::io_context& ios) const &
  159. {
  160. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
  161. return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
  162. }
  163. };
  164. async_pipe::async_pipe(boost::asio::io_context & ios_source,
  165. boost::asio::io_context & ios_sink,
  166. const std::string & name) : _source(ios_source), _sink(ios_sink)
  167. {
  168. auto fifo = mkfifo(name.c_str(), 0666 );
  169. if (fifo != 0)
  170. boost::process::detail::throw_last_error("mkfifo() failed");
  171. int read_fd = open(name.c_str(), O_RDWR);
  172. if (read_fd == -1)
  173. boost::process::detail::throw_last_error();
  174. int write_fd = dup(read_fd);
  175. if (write_fd == -1)
  176. boost::process::detail::throw_last_error();
  177. _source.assign(read_fd);
  178. _sink .assign(write_fd);
  179. }
  180. async_pipe::async_pipe(const async_pipe & p) :
  181. _source(const_cast<async_pipe&>(p)._source.get_executor()),
  182. _sink( const_cast<async_pipe&>(p)._sink.get_executor())
  183. {
  184. //cannot get the handle from a const object.
  185. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
  186. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
  187. if (source_in == -1)
  188. _source.assign(-1);
  189. else
  190. {
  191. _source.assign(::dup(source_in));
  192. if (_source.native_handle()== -1)
  193. ::boost::process::detail::throw_last_error("dup()");
  194. }
  195. if (sink_in == -1)
  196. _sink.assign(-1);
  197. else
  198. {
  199. _sink.assign(::dup(sink_in));
  200. if (_sink.native_handle() == -1)
  201. ::boost::process::detail::throw_last_error("dup()");
  202. }
  203. }
  204. async_pipe& async_pipe::operator=(const async_pipe & p)
  205. {
  206. int source;
  207. int sink;
  208. //cannot get the handle from a const object.
  209. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle();
  210. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle();
  211. if (source_in == -1)
  212. source = -1;
  213. else
  214. {
  215. source = ::dup(source_in);
  216. if (source == -1)
  217. ::boost::process::detail::throw_last_error("dup()");
  218. }
  219. if (sink_in == -1)
  220. sink = -1;
  221. else
  222. {
  223. sink = ::dup(sink_in);
  224. if (sink == -1)
  225. ::boost::process::detail::throw_last_error("dup()");
  226. }
  227. _source.assign(source);
  228. _sink. assign(sink);
  229. return *this;
  230. }
  231. async_pipe& async_pipe::operator=(async_pipe && lhs)
  232. {
  233. std::swap(_source, lhs._source);
  234. std::swap(_sink, lhs._sink);
  235. return *this;
  236. }
  237. template<class CharT, class Traits>
  238. async_pipe::operator basic_pipe<CharT, Traits>() const
  239. {
  240. int source;
  241. int sink;
  242. //cannot get the handle from a const object.
  243. auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
  244. auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
  245. if (source_in == -1)
  246. source = -1;
  247. else
  248. {
  249. source = ::dup(source_in);
  250. if (source == -1)
  251. ::boost::process::detail::throw_last_error("dup()");
  252. }
  253. if (sink_in == -1)
  254. sink = -1;
  255. else
  256. {
  257. sink = ::dup(sink_in);
  258. if (sink == -1)
  259. ::boost::process::detail::throw_last_error("dup()");
  260. }
  261. return basic_pipe<CharT, Traits>{source, sink};
  262. }
  263. inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
  264. {
  265. return compare_handles(lhs.native_source(), rhs.native_source()) &&
  266. compare_handles(lhs.native_sink(), rhs.native_sink());
  267. }
  268. inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
  269. {
  270. return !compare_handles(lhs.native_source(), rhs.native_source()) ||
  271. !compare_handles(lhs.native_sink(), rhs.native_sink());
  272. }
  273. template<class Char, class Traits>
  274. inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
  275. {
  276. return compare_handles(lhs.native_source(), rhs.native_source()) &&
  277. compare_handles(lhs.native_sink(), rhs.native_sink());
  278. }
  279. template<class Char, class Traits>
  280. inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
  281. {
  282. return !compare_handles(lhs.native_source(), rhs.native_source()) ||
  283. !compare_handles(lhs.native_sink(), rhs.native_sink());
  284. }
  285. template<class Char, class Traits>
  286. inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
  287. {
  288. return compare_handles(lhs.native_source(), rhs.native_source()) &&
  289. compare_handles(lhs.native_sink(), rhs.native_sink());
  290. }
  291. template<class Char, class Traits>
  292. inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
  293. {
  294. return !compare_handles(lhs.native_source(), rhs.native_source()) ||
  295. !compare_handles(lhs.native_sink(), rhs.native_sink());
  296. }
  297. }}}}
  298. #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */