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