1 // Copyright (c) 2016 Klemens D. Morgenstern
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)
6 #ifndef BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
7 #define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
9 #include <boost/winapi/basic_types.hpp>
10 #include <boost/winapi/pipes.hpp>
11 #include <boost/winapi/handles.hpp>
12 #include <boost/winapi/file_management.hpp>
13 #include <boost/winapi/get_last_error.hpp>
14 #include <boost/winapi/access_rights.hpp>
15 #include <boost/winapi/process.hpp>
16 #include <boost/process/detail/windows/basic_pipe.hpp>
17 #include <boost/asio/post.hpp>
18 #include <boost/asio/windows/stream_handle.hpp>
20 #include <system_error>
23 namespace boost { namespace process { namespace detail { namespace windows {
25 inline std::string make_pipe_name()
27 std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
29 auto pid = ::boost::winapi::GetCurrentProcessId();
31 static std::atomic_size_t cnt{0};
32 name += std::to_string(pid);
34 name += std::to_string(cnt++);
41 ::boost::asio::windows::stream_handle _source;
42 ::boost::asio::windows::stream_handle _sink ;
44 inline async_pipe(boost::asio::io_context & ios_source,
45 boost::asio::io_context & ios_sink,
46 const std::string & name, bool private_);
49 typedef ::boost::winapi::HANDLE_ native_handle_type;
50 typedef ::boost::asio::windows::stream_handle handle_type;
51 typedef typename handle_type::executor_type executor_type;
53 async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
54 async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
55 : async_pipe(ios_source, ios_sink, make_pipe_name(), true) {}
57 async_pipe(boost::asio::io_context & ios, const std::string & name)
58 : async_pipe(ios, ios, name, false) {}
60 async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
61 : async_pipe(ios_source, ios_sink, name, false) {}
65 inline async_pipe(const async_pipe& rhs);
66 async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
69 template<class CharT, class Traits = std::char_traits<CharT>>
70 explicit async_pipe(::boost::asio::io_context & ios_source,
71 ::boost::asio::io_context & ios_sink,
72 const basic_pipe<CharT, Traits> & p)
73 : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
77 template<class CharT, class Traits = std::char_traits<CharT>>
78 explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
79 : async_pipe(ios, ios, p)
83 template<class CharT, class Traits = std::char_traits<CharT>>
84 inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
85 inline async_pipe& operator=(const async_pipe& rhs);
87 inline async_pipe& operator=(async_pipe&& rhs);
91 boost::system::error_code ec;
95 template<class CharT, class Traits = std::char_traits<CharT>>
96 inline explicit operator basic_pipe<CharT, Traits>() const;
102 if (_source.is_open())
111 _sink = handle_type(_sink.get_executor());
113 if (_source.is_open())
116 _source = handle_type(_source.get_executor());
119 void close(boost::system::error_code & ec)
124 _sink = handle_type(_sink.get_executor());
126 if (_source.is_open())
129 _source = handle_type(_source.get_executor());
135 return _sink.is_open() || _source.is_open();
140 boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
141 if (_source.is_open())
142 boost::asio::post(_source.get_executor(), [this]{_source.close();});
145 template<typename MutableBufferSequence>
146 std::size_t read_some(const MutableBufferSequence & buffers)
148 return _source.read_some(buffers);
150 template<typename MutableBufferSequence>
151 std::size_t write_some(const MutableBufferSequence & buffers)
153 return _sink.write_some(buffers);
157 template<typename MutableBufferSequence>
158 std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
160 return _source.read_some(buffers, ec);
162 template<typename MutableBufferSequence>
163 std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
165 return _sink.write_some(buffers, ec);
168 native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native_handle();}
169 native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native_handle();}
171 template<typename MutableBufferSequence,
172 typename ReadHandler>
173 BOOST_ASIO_INITFN_RESULT_TYPE(
174 ReadHandler, void(boost::system::error_code, std::size_t))
176 const MutableBufferSequence & buffers,
177 ReadHandler &&handler)
179 return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
182 template<typename ConstBufferSequence,
183 typename WriteHandler>
184 BOOST_ASIO_INITFN_RESULT_TYPE(
185 WriteHandler, void(boost::system::error_code, std::size_t))
187 const ConstBufferSequence & buffers,
188 WriteHandler && handler)
190 return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
193 const handle_type & sink () const & {return _sink;}
194 const handle_type & source() const & {return _source;}
196 handle_type && source() && { return std::move(_source); }
197 handle_type && sink() && { return std::move(_sink); }
199 handle_type source(::boost::asio::io_context& ios) &&
201 ::boost::asio::windows::stream_handle stolen(ios.get_executor(), _source.native_handle());
202 boost::system::error_code ec;
203 _source.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
206 handle_type sink (::boost::asio::io_context& ios) &&
208 ::boost::asio::windows::stream_handle stolen(ios.get_executor(), _sink.native_handle());
209 boost::system::error_code ec;
210 _sink.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
214 handle_type source(::boost::asio::io_context& ios) const &
216 auto proc = ::boost::winapi::GetCurrentProcess();
218 ::boost::winapi::HANDLE_ source;
219 auto source_in = const_cast<handle_type&>(_source).native_handle();
220 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
221 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
222 else if (!::boost::winapi::DuplicateHandle(
223 proc, source_in, proc, &source, 0,
224 static_cast<::boost::winapi::BOOL_>(true),
225 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
226 throw_last_error("Duplicate Pipe Failed");
228 return ::boost::asio::windows::stream_handle(ios.get_executor(), source);
230 handle_type sink (::boost::asio::io_context& ios) const &
232 auto proc = ::boost::winapi::GetCurrentProcess();
234 ::boost::winapi::HANDLE_ sink;
235 auto sink_in = const_cast<handle_type&>(_sink).native_handle();
236 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
237 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
238 else if (!::boost::winapi::DuplicateHandle(
239 proc, sink_in, proc, &sink, 0,
240 static_cast<::boost::winapi::BOOL_>(true),
241 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
242 throw_last_error("Duplicate Pipe Failed");
244 return ::boost::asio::windows::stream_handle(ios.get_executor(), sink);
248 async_pipe::async_pipe(const async_pipe& p) :
249 _source(const_cast<handle_type&>(p._source).get_executor()),
250 _sink (const_cast<handle_type&>(p._sink).get_executor())
253 auto proc = ::boost::winapi::GetCurrentProcess();
255 ::boost::winapi::HANDLE_ source;
256 ::boost::winapi::HANDLE_ sink;
258 //cannot get the handle from a const object.
259 auto source_in = const_cast<handle_type&>(p._source).native_handle();
260 auto sink_in = const_cast<handle_type&>(p._sink).native_handle();
262 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
263 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
264 else if (!::boost::winapi::DuplicateHandle(
265 proc, source_in, proc, &source, 0,
266 static_cast<::boost::winapi::BOOL_>(true),
267 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
268 throw_last_error("Duplicate Pipe Failed");
270 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
271 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
272 else if (!::boost::winapi::DuplicateHandle(
273 proc, sink_in, proc, &sink, 0,
274 static_cast<::boost::winapi::BOOL_>(true),
275 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
276 throw_last_error("Duplicate Pipe Failed");
278 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
279 _source.assign(source);
280 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
285 async_pipe::async_pipe(boost::asio::io_context & ios_source,
286 boost::asio::io_context & ios_sink,
287 const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink)
289 static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
291 ::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
292 #if defined(BOOST_NO_ANSI_APIS)
293 ::boost::process::detail::convert(name).c_str(),
297 ::boost::winapi::PIPE_ACCESS_INBOUND_
298 | FILE_FLAG_OVERLAPPED_, //write flag
299 0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
302 if (source == boost::winapi::INVALID_HANDLE_VALUE_)
303 ::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed");
305 _source.assign(source);
307 ::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
308 #if defined(BOOST_NO_ANSI_APIS)
309 ::boost::process::detail::convert(name).c_str(),
313 ::boost::winapi::GENERIC_WRITE_, 0, nullptr,
314 ::boost::winapi::OPEN_EXISTING_,
315 FILE_FLAG_OVERLAPPED_, //to allow read
318 if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
319 ::boost::process::detail::throw_last_error("create_file() failed");
324 template<class CharT, class Traits>
325 async_pipe& async_pipe::operator=(const basic_pipe<CharT, Traits> & p)
327 auto proc = ::boost::winapi::GetCurrentProcess();
329 ::boost::winapi::HANDLE_ source;
330 ::boost::winapi::HANDLE_ sink;
332 //cannot get the handle from a const object.
333 auto source_in = p.native_source();
334 auto sink_in = p.native_sink();
336 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
337 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
338 else if (!::boost::winapi::DuplicateHandle(
339 proc, source_in.native_handle(), proc, &source, 0,
340 static_cast<::boost::winapi::BOOL_>(true),
341 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
342 throw_last_error("Duplicate Pipe Failed");
344 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
345 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
346 else if (!::boost::winapi::DuplicateHandle(
347 proc, sink_in.native_handle(), proc, &sink, 0,
348 static_cast<::boost::winapi::BOOL_>(true),
349 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
350 throw_last_error("Duplicate Pipe Failed");
352 //so we also assign the io_context
353 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
354 _source.assign(source);
356 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
362 async_pipe& async_pipe::operator=(const async_pipe & p)
364 auto proc = ::boost::winapi::GetCurrentProcess();
366 ::boost::winapi::HANDLE_ source;
367 ::boost::winapi::HANDLE_ sink;
369 //cannot get the handle from a const object.
370 auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
371 auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
373 source_in.get_executor();
375 if (source_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
376 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
377 else if (!::boost::winapi::DuplicateHandle(
378 proc, source_in.native_handle(), proc, &source, 0,
379 static_cast<::boost::winapi::BOOL_>(true),
380 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
381 throw_last_error("Duplicate Pipe Failed");
383 if (sink_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
384 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
385 else if (!::boost::winapi::DuplicateHandle(
386 proc, sink_in.native_handle(), proc, &sink, 0,
387 static_cast<::boost::winapi::BOOL_>(true),
388 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
389 throw_last_error("Duplicate Pipe Failed");
391 //so we also assign the io_context
392 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
393 _source = ::boost::asio::windows::stream_handle(source_in.get_executor(), source);
395 _source = ::boost::asio::windows::stream_handle(source_in.get_executor());
397 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
398 _sink = ::boost::asio::windows::stream_handle(source_in.get_executor(), sink);
400 _sink = ::boost::asio::windows::stream_handle(source_in.get_executor());
405 async_pipe& async_pipe::operator=(async_pipe && rhs)
407 _source = std::move(rhs._source);
408 _sink = std::move(rhs._sink);
412 template<class CharT, class Traits>
413 async_pipe::operator basic_pipe<CharT, Traits>() const
415 auto proc = ::boost::winapi::GetCurrentProcess();
417 ::boost::winapi::HANDLE_ source;
418 ::boost::winapi::HANDLE_ sink;
420 //cannot get the handle from a const object.
421 auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native_handle();
422 auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native_handle();
424 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
425 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
426 else if (!::boost::winapi::DuplicateHandle(
427 proc, source_in, proc, &source, 0,
428 static_cast<::boost::winapi::BOOL_>(true),
429 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
430 throw_last_error("Duplicate Pipe Failed");
432 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
433 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
434 else if (!::boost::winapi::DuplicateHandle(
435 proc, sink_in, proc, &sink, 0,
436 static_cast<::boost::winapi::BOOL_>(true),
437 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
438 throw_last_error("Duplicate Pipe Failed");
440 return basic_pipe<CharT, Traits>{source, sink};
443 inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
445 return compare_handles(lhs.native_source(), rhs.native_source()) &&
446 compare_handles(lhs.native_sink(), rhs.native_sink());
449 inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
451 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
452 !compare_handles(lhs.native_sink(), rhs.native_sink());
455 template<class Char, class Traits>
456 inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
458 return compare_handles(lhs.native_source(), rhs.native_source()) &&
459 compare_handles(lhs.native_sink(), rhs.native_sink());
462 template<class Char, class Traits>
463 inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
465 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
466 !compare_handles(lhs.native_sink(), rhs.native_sink());
469 template<class Char, class Traits>
470 inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
472 return compare_handles(lhs.native_source(), rhs.native_source()) &&
473 compare_handles(lhs.native_sink(), rhs.native_sink());
476 template<class Char, class Traits>
477 inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
479 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
480 !compare_handles(lhs.native_sink(), rhs.native_sink());
485 #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */