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