async_pipe.hpp 11 KB

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