File indexing completed on 2025-01-18 09:50:07
0001
0002
0003
0004
0005
0006 #ifndef BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
0007 #define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
0008
0009 #include <boost/winapi/basic_types.hpp>
0010 #include <boost/winapi/pipes.hpp>
0011 #include <boost/winapi/handles.hpp>
0012 #include <boost/winapi/file_management.hpp>
0013 #include <boost/winapi/get_last_error.hpp>
0014 #include <boost/winapi/access_rights.hpp>
0015 #include <boost/winapi/process.hpp>
0016 #include <boost/process/detail/windows/basic_pipe.hpp>
0017 #include <boost/asio/post.hpp>
0018 #include <boost/asio/windows/stream_handle.hpp>
0019 #include <atomic>
0020 #include <system_error>
0021 #include <string>
0022
0023 namespace boost { namespace process { namespace detail { namespace windows {
0024
0025 inline std::string make_pipe_name()
0026 {
0027 std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
0028
0029 auto pid = ::boost::winapi::GetCurrentProcessId();
0030
0031 static std::atomic_size_t cnt{0};
0032 name += std::to_string(pid);
0033 name += "_";
0034 name += std::to_string(cnt++);
0035
0036 return name;
0037 }
0038
0039 class async_pipe
0040 {
0041 ::boost::asio::windows::stream_handle _source;
0042 ::boost::asio::windows::stream_handle _sink ;
0043
0044 inline async_pipe(boost::asio::io_context & ios_source,
0045 boost::asio::io_context & ios_sink,
0046 const std::string & name, bool private_);
0047
0048 public:
0049 typedef ::boost::winapi::HANDLE_ native_handle_type;
0050 typedef ::boost::asio::windows::stream_handle handle_type;
0051 typedef typename handle_type::executor_type executor_type;
0052
0053 async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
0054 async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
0055 : async_pipe(ios_source, ios_sink, make_pipe_name(), true) {}
0056
0057 async_pipe(boost::asio::io_context & ios, const std::string & name)
0058 : async_pipe(ios, ios, name, false) {}
0059
0060 async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink, const std::string & name)
0061 : async_pipe(ios_source, ios_sink, name, false) {}
0062
0063
0064
0065 inline async_pipe(const async_pipe& rhs);
0066 async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
0067 {
0068 }
0069 template<class CharT, class Traits = std::char_traits<CharT>>
0070 explicit async_pipe(::boost::asio::io_context & ios_source,
0071 ::boost::asio::io_context & ios_sink,
0072 const basic_pipe<CharT, Traits> & p)
0073 : _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
0074 {
0075 }
0076
0077 template<class CharT, class Traits = std::char_traits<CharT>>
0078 explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
0079 : async_pipe(ios, ios, p)
0080 {
0081 }
0082
0083 template<class CharT, class Traits = std::char_traits<CharT>>
0084 inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
0085 inline async_pipe& operator=(const async_pipe& rhs);
0086
0087 inline async_pipe& operator=(async_pipe&& rhs);
0088
0089 ~async_pipe()
0090 {
0091 boost::system::error_code ec;
0092 close(ec);
0093 }
0094
0095 template<class CharT, class Traits = std::char_traits<CharT>>
0096 inline explicit operator basic_pipe<CharT, Traits>() const;
0097
0098 void cancel()
0099 {
0100 if (_sink.is_open())
0101 _sink.cancel();
0102 if (_source.is_open())
0103 _source.cancel();
0104 }
0105
0106 void close()
0107 {
0108 if (_sink.is_open())
0109 {
0110 _sink.close();
0111 _sink = handle_type(_sink.get_executor());
0112 }
0113 if (_source.is_open())
0114 {
0115 _source.close();
0116 _source = handle_type(_source.get_executor());
0117 }
0118 }
0119 void close(boost::system::error_code & ec)
0120 {
0121 if (_sink.is_open())
0122 {
0123 _sink.close(ec);
0124 _sink = handle_type(_sink.get_executor());
0125 }
0126 if (_source.is_open())
0127 {
0128 _source.close(ec);
0129 _source = handle_type(_source.get_executor());
0130 }
0131 }
0132
0133 bool is_open() const
0134 {
0135 return _sink.is_open() || _source.is_open();
0136 }
0137 void async_close()
0138 {
0139 if (_sink.is_open())
0140 boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
0141 if (_source.is_open())
0142 boost::asio::post(_source.get_executor(), [this]{_source.close();});
0143 }
0144
0145 template<typename MutableBufferSequence>
0146 std::size_t read_some(const MutableBufferSequence & buffers)
0147 {
0148 return _source.read_some(buffers);
0149 }
0150 template<typename MutableBufferSequence>
0151 std::size_t write_some(const MutableBufferSequence & buffers)
0152 {
0153 return _sink.write_some(buffers);
0154 }
0155
0156
0157 template<typename MutableBufferSequence>
0158 std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
0159 {
0160 return _source.read_some(buffers, ec);
0161 }
0162 template<typename MutableBufferSequence>
0163 std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
0164 {
0165 return _sink.write_some(buffers, ec);
0166 }
0167
0168 native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native_handle();}
0169 native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native_handle();}
0170
0171 template<typename MutableBufferSequence,
0172 typename ReadHandler>
0173 BOOST_ASIO_INITFN_RESULT_TYPE(
0174 ReadHandler, void(boost::system::error_code, std::size_t))
0175 async_read_some(
0176 const MutableBufferSequence & buffers,
0177 ReadHandler &&handler)
0178 {
0179 return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
0180 }
0181
0182 template<typename ConstBufferSequence,
0183 typename WriteHandler>
0184 BOOST_ASIO_INITFN_RESULT_TYPE(
0185 WriteHandler, void(boost::system::error_code, std::size_t))
0186 async_write_some(
0187 const ConstBufferSequence & buffers,
0188 WriteHandler && handler)
0189 {
0190 return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
0191 }
0192
0193 const handle_type & sink () const & {return _sink;}
0194 const handle_type & source() const & {return _source;}
0195
0196 handle_type && source() && { return std::move(_source); }
0197 handle_type && sink() && { return std::move(_sink); }
0198
0199 handle_type source(::boost::asio::io_context& ios) &&
0200 {
0201 ::boost::asio::windows::stream_handle stolen(ios.get_executor(), _source.native_handle());
0202 boost::system::error_code ec;
0203 _source.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
0204 return stolen;
0205 }
0206 handle_type sink (::boost::asio::io_context& ios) &&
0207 {
0208 ::boost::asio::windows::stream_handle stolen(ios.get_executor(), _sink.native_handle());
0209 boost::system::error_code ec;
0210 _sink.assign(::boost::winapi::INVALID_HANDLE_VALUE_, ec);
0211 return stolen;
0212 }
0213
0214 handle_type source(::boost::asio::io_context& ios) const &
0215 {
0216 auto proc = ::boost::winapi::GetCurrentProcess();
0217
0218 ::boost::winapi::HANDLE_ source;
0219 auto source_in = const_cast<handle_type&>(_source).native_handle();
0220 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0221 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
0222 else if (!::boost::winapi::DuplicateHandle(
0223 proc, source_in, proc, &source, 0,
0224 static_cast<::boost::winapi::BOOL_>(true),
0225 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0226 throw_last_error("Duplicate Pipe Failed");
0227
0228 return ::boost::asio::windows::stream_handle(ios.get_executor(), source);
0229 }
0230 handle_type sink (::boost::asio::io_context& ios) const &
0231 {
0232 auto proc = ::boost::winapi::GetCurrentProcess();
0233
0234 ::boost::winapi::HANDLE_ sink;
0235 auto sink_in = const_cast<handle_type&>(_sink).native_handle();
0236 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0237 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
0238 else if (!::boost::winapi::DuplicateHandle(
0239 proc, sink_in, proc, &sink, 0,
0240 static_cast<::boost::winapi::BOOL_>(true),
0241 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0242 throw_last_error("Duplicate Pipe Failed");
0243
0244 return ::boost::asio::windows::stream_handle(ios.get_executor(), sink);
0245 }
0246 };
0247
0248 async_pipe::async_pipe(const async_pipe& p) :
0249 _source(const_cast<handle_type&>(p._source).get_executor()),
0250 _sink (const_cast<handle_type&>(p._sink).get_executor())
0251 {
0252
0253 auto proc = ::boost::winapi::GetCurrentProcess();
0254
0255 ::boost::winapi::HANDLE_ source;
0256 ::boost::winapi::HANDLE_ sink;
0257
0258
0259 auto source_in = const_cast<handle_type&>(p._source).native_handle();
0260 auto sink_in = const_cast<handle_type&>(p._sink).native_handle();
0261
0262 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0263 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
0264 else if (!::boost::winapi::DuplicateHandle(
0265 proc, source_in, proc, &source, 0,
0266 static_cast<::boost::winapi::BOOL_>(true),
0267 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0268 throw_last_error("Duplicate Pipe Failed");
0269
0270 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0271 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
0272 else if (!::boost::winapi::DuplicateHandle(
0273 proc, sink_in, proc, &sink, 0,
0274 static_cast<::boost::winapi::BOOL_>(true),
0275 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0276 throw_last_error("Duplicate Pipe Failed");
0277
0278 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
0279 _source.assign(source);
0280 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
0281 _sink. assign(sink);
0282 }
0283
0284
0285 async_pipe::async_pipe(boost::asio::io_context & ios_source,
0286 boost::asio::io_context & ios_sink,
0287 const std::string & name, bool private_) : _source(ios_source), _sink(ios_sink)
0288 {
0289 static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000;
0290
0291 ::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
0292 #if defined(BOOST_NO_ANSI_APIS)
0293 ::boost::process::detail::convert(name).c_str(),
0294 #else
0295 name.c_str(),
0296 #endif
0297 ::boost::winapi::PIPE_ACCESS_INBOUND_
0298 | FILE_FLAG_OVERLAPPED_,
0299 0, private_ ? 1 : ::boost::winapi::PIPE_UNLIMITED_INSTANCES_, 8192, 8192, 0, nullptr);
0300
0301
0302 if (source == boost::winapi::INVALID_HANDLE_VALUE_)
0303 ::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed");
0304
0305 _source.assign(source);
0306
0307 ::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
0308 #if defined(BOOST_NO_ANSI_APIS)
0309 ::boost::process::detail::convert(name).c_str(),
0310 #else
0311 name.c_str(),
0312 #endif
0313 ::boost::winapi::GENERIC_WRITE_, 0, nullptr,
0314 ::boost::winapi::OPEN_EXISTING_,
0315 FILE_FLAG_OVERLAPPED_,
0316 nullptr);
0317
0318 if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
0319 ::boost::process::detail::throw_last_error("create_file() failed");
0320
0321 _sink.assign(sink);
0322 }
0323
0324 template<class CharT, class Traits>
0325 async_pipe& async_pipe::operator=(const basic_pipe<CharT, Traits> & p)
0326 {
0327 auto proc = ::boost::winapi::GetCurrentProcess();
0328
0329 ::boost::winapi::HANDLE_ source;
0330 ::boost::winapi::HANDLE_ sink;
0331
0332
0333 auto source_in = p.native_source();
0334 auto sink_in = p.native_sink();
0335
0336 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0337 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
0338 else if (!::boost::winapi::DuplicateHandle(
0339 proc, source_in.native_handle(), proc, &source, 0,
0340 static_cast<::boost::winapi::BOOL_>(true),
0341 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0342 throw_last_error("Duplicate Pipe Failed");
0343
0344 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0345 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
0346 else if (!::boost::winapi::DuplicateHandle(
0347 proc, sink_in.native_handle(), proc, &sink, 0,
0348 static_cast<::boost::winapi::BOOL_>(true),
0349 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0350 throw_last_error("Duplicate Pipe Failed");
0351
0352
0353 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
0354 _source.assign(source);
0355
0356 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
0357 _sink.assign(sink);
0358
0359 return *this;
0360 }
0361
0362 async_pipe& async_pipe::operator=(const async_pipe & p)
0363 {
0364 auto proc = ::boost::winapi::GetCurrentProcess();
0365
0366 ::boost::winapi::HANDLE_ source;
0367 ::boost::winapi::HANDLE_ sink;
0368
0369
0370 auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
0371 auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
0372
0373 source_in.get_executor();
0374
0375 if (source_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
0376 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
0377 else if (!::boost::winapi::DuplicateHandle(
0378 proc, source_in.native_handle(), proc, &source, 0,
0379 static_cast<::boost::winapi::BOOL_>(true),
0380 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0381 throw_last_error("Duplicate Pipe Failed");
0382
0383 if (sink_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
0384 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
0385 else if (!::boost::winapi::DuplicateHandle(
0386 proc, sink_in.native_handle(), proc, &sink, 0,
0387 static_cast<::boost::winapi::BOOL_>(true),
0388 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0389 throw_last_error("Duplicate Pipe Failed");
0390
0391
0392 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
0393 _source = ::boost::asio::windows::stream_handle(source_in.get_executor(), source);
0394 else
0395 _source = ::boost::asio::windows::stream_handle(source_in.get_executor());
0396
0397 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
0398 _sink = ::boost::asio::windows::stream_handle(source_in.get_executor(), sink);
0399 else
0400 _sink = ::boost::asio::windows::stream_handle(source_in.get_executor());
0401
0402 return *this;
0403 }
0404
0405 async_pipe& async_pipe::operator=(async_pipe && rhs)
0406 {
0407 _source = std::move(rhs._source);
0408 _sink = std::move(rhs._sink);
0409 return *this;
0410 }
0411
0412 template<class CharT, class Traits>
0413 async_pipe::operator basic_pipe<CharT, Traits>() const
0414 {
0415 auto proc = ::boost::winapi::GetCurrentProcess();
0416
0417 ::boost::winapi::HANDLE_ source;
0418 ::boost::winapi::HANDLE_ sink;
0419
0420
0421 auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native_handle();
0422 auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native_handle();
0423
0424 if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0425 source = ::boost::winapi::INVALID_HANDLE_VALUE_;
0426 else if (!::boost::winapi::DuplicateHandle(
0427 proc, source_in, proc, &source, 0,
0428 static_cast<::boost::winapi::BOOL_>(true),
0429 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0430 throw_last_error("Duplicate Pipe Failed");
0431
0432 if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
0433 sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
0434 else if (!::boost::winapi::DuplicateHandle(
0435 proc, sink_in, proc, &sink, 0,
0436 static_cast<::boost::winapi::BOOL_>(true),
0437 ::boost::winapi::DUPLICATE_SAME_ACCESS_))
0438 throw_last_error("Duplicate Pipe Failed");
0439
0440 return basic_pipe<CharT, Traits>{source, sink};
0441 }
0442
0443 inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
0444 {
0445 return compare_handles(lhs.native_source(), rhs.native_source()) &&
0446 compare_handles(lhs.native_sink(), rhs.native_sink());
0447 }
0448
0449 inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
0450 {
0451 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
0452 !compare_handles(lhs.native_sink(), rhs.native_sink());
0453 }
0454
0455 template<class Char, class Traits>
0456 inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
0457 {
0458 return compare_handles(lhs.native_source(), rhs.native_source()) &&
0459 compare_handles(lhs.native_sink(), rhs.native_sink());
0460 }
0461
0462 template<class Char, class Traits>
0463 inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
0464 {
0465 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
0466 !compare_handles(lhs.native_sink(), rhs.native_sink());
0467 }
0468
0469 template<class Char, class Traits>
0470 inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
0471 {
0472 return compare_handles(lhs.native_source(), rhs.native_source()) &&
0473 compare_handles(lhs.native_sink(), rhs.native_sink());
0474 }
0475
0476 template<class Char, class Traits>
0477 inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
0478 {
0479 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
0480 !compare_handles(lhs.native_sink(), rhs.native_sink());
0481 }
0482
0483 }}}}
0484
0485 #endif