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
6 #ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
7 #define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
8
9
10 #include <boost/process/detail/posix/basic_pipe.hpp>
11 #include <boost/asio/posix/stream_descriptor.hpp>
12 #include <boost/asio/post.hpp>
13 #include <system_error>
14 #include <string>
15 #include <utility>
16
17 namespace boost { namespace process { namespace detail { namespace posix {
18
19 class async_pipe
20 {
21 ::boost::asio::posix::stream_descriptor _source;
22 ::boost::asio::posix::stream_descriptor _sink ;
23 public:
24 typedef int native_handle_type;
25 typedef ::boost::asio::posix::stream_descriptor handle_type;
26 typedef typename handle_type::executor_type executor_type;
27
async_pipe(boost::asio::io_context & ios)28 inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
29
async_pipe(boost::asio::io_context & ios_source,boost::asio::io_context & ios_sink)30 inline async_pipe(boost::asio::io_context & ios_source,
31 boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink)
32 {
33 int fds[2];
34 if (::pipe(fds) == -1)
35 boost::process::detail::throw_last_error("pipe(2) failed");
36
37 _source.assign(fds[0]);
38 _sink .assign(fds[1]);
39 };
async_pipe(boost::asio::io_context & ios,const std::string & name)40 inline async_pipe(boost::asio::io_context & ios, const std::string & name)
41 : async_pipe(ios, ios, name) {}
42
43 inline async_pipe(boost::asio::io_context & ios_source,
44 boost::asio::io_context & io_sink, const std::string & name);
45 inline async_pipe(const async_pipe& lhs);
async_pipe(async_pipe && lhs)46 async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
47 {
48 lhs._source.assign (-1);
49 lhs._sink .assign (-1);
50 }
51
52 template<class CharT, class Traits = std::char_traits<CharT>>
async_pipe(::boost::asio::io_context & ios_source,::boost::asio::io_context & ios_sink,const basic_pipe<CharT,Traits> & p)53 explicit async_pipe(::boost::asio::io_context & ios_source,
54 ::boost::asio::io_context & ios_sink,
55 const basic_pipe<CharT, Traits> & p)
56 : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
57 {
58 }
59
60 template<class CharT, class Traits = std::char_traits<CharT>>
async_pipe(boost::asio::io_context & ios,const basic_pipe<CharT,Traits> & p)61 explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
62 : async_pipe(ios, ios, p)
63 {
64 }
65
66 template<class CharT, class Traits = std::char_traits<CharT>>
67 inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
68 inline async_pipe& operator=(const async_pipe& rhs);
69
70 inline async_pipe& operator=(async_pipe&& lhs);
71
~async_pipe()72 ~async_pipe()
73 {
74 boost::system::error_code ec;
75 close(ec);
76 }
77
78 template<class CharT, class Traits = std::char_traits<CharT>>
79 inline explicit operator basic_pipe<CharT, Traits>() const;
80
cancel()81 void cancel()
82 {
83 if (_sink.is_open())
84 _sink.cancel();
85 if (_source.is_open())
86 _source.cancel();
87 }
88
close()89 void close()
90 {
91 if (_sink.is_open())
92 _sink.close();
93 if (_source.is_open())
94 _source.close();
95 }
close(boost::system::error_code & ec)96 void close(boost::system::error_code & ec)
97 {
98 if (_sink.is_open())
99 _sink.close(ec);
100 if (_source.is_open())
101 _source.close(ec);
102 }
103
104
is_open() const105 bool is_open() const
106 {
107 return _sink.is_open() || _source.is_open();
108 }
async_close()109 void async_close()
110 {
111 if (_sink.is_open())
112 boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
113 if (_source.is_open())
114 boost::asio::post(_source.get_executor(), [this]{_source.close();});
115 }
116
117 template<typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers)118 std::size_t read_some(const MutableBufferSequence & buffers)
119 {
120 return _source.read_some(buffers);
121 }
122 template<typename MutableBufferSequence>
write_some(const MutableBufferSequence & buffers)123 std::size_t write_some(const MutableBufferSequence & buffers)
124 {
125 return _sink.write_some(buffers);
126 }
127
128 template<typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers,boost::system::error_code & ec)129 std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
130 {
131 return _source.read_some(buffers, ec);
132 }
133 template<typename MutableBufferSequence>
write_some(const MutableBufferSequence & buffers,boost::system::error_code & ec)134 std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
135 {
136 return _sink.write_some(buffers, ec);
137 }
138
139
native_source() const140 native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();}
native_sink() const141 native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
142
143 template<typename MutableBufferSequence,
144 typename ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,void (boost::system::error_code,std::size_t))145 BOOST_ASIO_INITFN_RESULT_TYPE(
146 ReadHandler, void(boost::system::error_code, std::size_t))
147 async_read_some(
148 const MutableBufferSequence & buffers,
149 ReadHandler &&handler)
150 {
151 return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
152 }
153
154 template<typename ConstBufferSequence,
155 typename WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,void (boost::system::error_code,std::size_t))156 BOOST_ASIO_INITFN_RESULT_TYPE(
157 WriteHandler, void(boost::system::error_code, std::size_t))
158 async_write_some(
159 const ConstBufferSequence & buffers,
160 WriteHandler&& handler)
161 {
162 return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
163 }
164
165
sink() const166 const handle_type & sink () const & {return _sink;}
source() const167 const handle_type & source() const & {return _source;}
168
sink()169 handle_type && sink() && { return std::move(_sink); }
source()170 handle_type && source()&& { return std::move(_source); }
171
source(::boost::asio::io_context & ios)172 handle_type source(::boost::asio::io_context& ios) &&
173 {
174 ::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
175 return stolen;
176 }
sink(::boost::asio::io_context & ios)177 handle_type sink (::boost::asio::io_context& ios) &&
178 {
179 ::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
180 return stolen;
181 }
182
source(::boost::asio::io_context & ios) const183 handle_type source(::boost::asio::io_context& ios) const &
184 {
185 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
186 return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
187 }
sink(::boost::asio::io_context & ios) const188 handle_type sink (::boost::asio::io_context& ios) const &
189 {
190 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
191 return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
192 }
193 };
194
195
async_pipe(boost::asio::io_context & ios_source,boost::asio::io_context & ios_sink,const std::string & name)196 async_pipe::async_pipe(boost::asio::io_context & ios_source,
197 boost::asio::io_context & ios_sink,
198 const std::string & name) : _source(ios_source), _sink(ios_sink)
199 {
200 auto fifo = mkfifo(name.c_str(), 0666 );
201
202 if (fifo != 0)
203 boost::process::detail::throw_last_error("mkfifo() failed");
204
205
206 int read_fd = open(name.c_str(), O_RDWR);
207
208 if (read_fd == -1)
209 boost::process::detail::throw_last_error();
210
211 int write_fd = dup(read_fd);
212
213 if (write_fd == -1)
214 boost::process::detail::throw_last_error();
215
216 _source.assign(read_fd);
217 _sink .assign(write_fd);
218 }
219
async_pipe(const async_pipe & p)220 async_pipe::async_pipe(const async_pipe & p) :
221 _source(const_cast<async_pipe&>(p)._source.get_executor()),
222 _sink( const_cast<async_pipe&>(p)._sink.get_executor())
223 {
224
225 //cannot get the handle from a const object.
226 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
227 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
228 if (source_in == -1)
229 _source.assign(-1);
230 else
231 {
232 _source.assign(::dup(source_in));
233 if (_source.native_handle()== -1)
234 ::boost::process::detail::throw_last_error("dup()");
235 }
236
237 if (sink_in == -1)
238 _sink.assign(-1);
239 else
240 {
241 _sink.assign(::dup(sink_in));
242 if (_sink.native_handle() == -1)
243 ::boost::process::detail::throw_last_error("dup()");
244 }
245 }
246
operator =(const async_pipe & p)247 async_pipe& async_pipe::operator=(const async_pipe & p)
248 {
249 int source;
250 int sink;
251
252 //cannot get the handle from a const object.
253 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._source).native_handle();
254 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._sink).native_handle();
255 if (source_in == -1)
256 source = -1;
257 else
258 {
259 source = ::dup(source_in);
260 if (source == -1)
261 ::boost::process::detail::throw_last_error("dup()");
262 }
263
264 if (sink_in == -1)
265 sink = -1;
266 else
267 {
268 sink = ::dup(sink_in);
269 if (sink == -1)
270 ::boost::process::detail::throw_last_error("dup()");
271 }
272 _source.assign(source);
273 _sink. assign(sink);
274
275 return *this;
276 }
277
operator =(async_pipe && lhs)278 async_pipe& async_pipe::operator=(async_pipe && lhs)
279 {
280 std::swap(_source, lhs._source);
281 std::swap(_sink, lhs._sink);
282 return *this;
283 }
284
285 template<class CharT, class Traits>
operator basic_pipe<CharT,Traits>() const286 async_pipe::operator basic_pipe<CharT, Traits>() const
287 {
288 int source;
289 int sink;
290
291 //cannot get the handle from a const object.
292 auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
293 auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
294
295
296 if (source_in == -1)
297 source = -1;
298 else
299 {
300 source = ::dup(source_in);
301 if (source == -1)
302 ::boost::process::detail::throw_last_error("dup()");
303 }
304
305 if (sink_in == -1)
306 sink = -1;
307 else
308 {
309 sink = ::dup(sink_in);
310 if (sink == -1)
311 ::boost::process::detail::throw_last_error("dup()");
312 }
313
314 return basic_pipe<CharT, Traits>{source, sink};
315 }
316
317
operator ==(const async_pipe & lhs,const async_pipe & rhs)318 inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
319 {
320 return compare_handles(lhs.native_source(), rhs.native_source()) &&
321 compare_handles(lhs.native_sink(), rhs.native_sink());
322 }
323
operator !=(const async_pipe & lhs,const async_pipe & rhs)324 inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
325 {
326 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
327 !compare_handles(lhs.native_sink(), rhs.native_sink());
328 }
329
330 template<class Char, class Traits>
operator ==(const async_pipe & lhs,const basic_pipe<Char,Traits> & rhs)331 inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
332 {
333 return compare_handles(lhs.native_source(), rhs.native_source()) &&
334 compare_handles(lhs.native_sink(), rhs.native_sink());
335 }
336
337 template<class Char, class Traits>
operator !=(const async_pipe & lhs,const basic_pipe<Char,Traits> & rhs)338 inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
339 {
340 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
341 !compare_handles(lhs.native_sink(), rhs.native_sink());
342 }
343
344 template<class Char, class Traits>
operator ==(const basic_pipe<Char,Traits> & lhs,const async_pipe & rhs)345 inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
346 {
347 return compare_handles(lhs.native_source(), rhs.native_source()) &&
348 compare_handles(lhs.native_sink(), rhs.native_sink());
349 }
350
351 template<class Char, class Traits>
operator !=(const basic_pipe<Char,Traits> & lhs,const async_pipe & rhs)352 inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
353 {
354 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
355 !compare_handles(lhs.native_sink(), rhs.native_sink());
356 }
357
358 }}}}
359
360 #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
361