]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/process/detail/windows/async_pipe.hpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / boost / process / detail / windows / 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_WINDOWS_ASYNC_PIPE_HPP_
7 #define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
8
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>
19 #include <atomic>
20 #include <system_error>
21 #include <string>
22
23 namespace boost { namespace process { namespace detail { namespace windows {
24
25 inline std::string make_pipe_name()
26 {
27 std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
28
29 auto pid = ::boost::winapi::GetCurrentProcessId();
30
31 static std::atomic_size_t cnt{0};
32 name += std::to_string(pid);
33 name += "_";
34 name += std::to_string(cnt++);
35
36 return name;
37 }
38
39 class async_pipe
40 {
41 ::boost::asio::windows::stream_handle _source;
42 ::boost::asio::windows::stream_handle _sink ;
43
44 inline async_pipe(boost::asio::io_context & ios_source,
45 boost::asio::io_context & ios_sink,
46 const std::string & name, bool private_);
47
48 public:
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;
52
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) {}
56
57 async_pipe(boost::asio::io_context & ios, const std::string & name)
58 : async_pipe(ios, ios, name, false) {}
59
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) {}
62
63
64
65 inline async_pipe(const async_pipe& rhs);
66 async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
67 {
68 }
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())
74 {
75 }
76
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)
80 {
81 }
82
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);
86
87 inline async_pipe& operator=(async_pipe&& rhs);
88
89 ~async_pipe()
90 {
91 boost::system::error_code ec;
92 close(ec);
93 }
94
95 template<class CharT, class Traits = std::char_traits<CharT>>
96 inline explicit operator basic_pipe<CharT, Traits>() const;
97
98 void cancel()
99 {
100 if (_sink.is_open())
101 _sink.cancel();
102 if (_source.is_open())
103 _source.cancel();
104 }
105
106 void close()
107 {
108 if (_sink.is_open())
109 {
110 _sink.close();
111 _sink = handle_type(_sink.get_executor());
112 }
113 if (_source.is_open())
114 {
115 _source.close();
116 _source = handle_type(_source.get_executor());
117 }
118 }
119 void close(boost::system::error_code & ec)
120 {
121 if (_sink.is_open())
122 {
123 _sink.close(ec);
124 _sink = handle_type(_sink.get_executor());
125 }
126 if (_source.is_open())
127 {
128 _source.close(ec);
129 _source = handle_type(_source.get_executor());
130 }
131 }
132
133 bool is_open() const
134 {
135 return _sink.is_open() || _source.is_open();
136 }
137 void async_close()
138 {
139 if (_sink.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();});
143 }
144
145 template<typename MutableBufferSequence>
146 std::size_t read_some(const MutableBufferSequence & buffers)
147 {
148 return _source.read_some(buffers);
149 }
150 template<typename MutableBufferSequence>
151 std::size_t write_some(const MutableBufferSequence & buffers)
152 {
153 return _sink.write_some(buffers);
154 }
155
156
157 template<typename MutableBufferSequence>
158 std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
159 {
160 return _source.read_some(buffers, ec);
161 }
162 template<typename MutableBufferSequence>
163 std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
164 {
165 return _sink.write_some(buffers, ec);
166 }
167
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();}
170
171 template<typename MutableBufferSequence,
172 typename ReadHandler>
173 BOOST_ASIO_INITFN_RESULT_TYPE(
174 ReadHandler, void(boost::system::error_code, std::size_t))
175 async_read_some(
176 const MutableBufferSequence & buffers,
177 ReadHandler &&handler)
178 {
179 return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
180 }
181
182 template<typename ConstBufferSequence,
183 typename WriteHandler>
184 BOOST_ASIO_INITFN_RESULT_TYPE(
185 WriteHandler, void(boost::system::error_code, std::size_t))
186 async_write_some(
187 const ConstBufferSequence & buffers,
188 WriteHandler && handler)
189 {
190 return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
191 }
192
193 const handle_type & sink () const & {return _sink;}
194 const handle_type & source() const & {return _source;}
195
196 handle_type && source() && { return std::move(_source); }
197 handle_type && sink() && { return std::move(_sink); }
198
199 handle_type source(::boost::asio::io_context& ios) &&
200 {
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);
204 return stolen;
205 }
206 handle_type sink (::boost::asio::io_context& ios) &&
207 {
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);
211 return stolen;
212 }
213
214 handle_type source(::boost::asio::io_context& ios) const &
215 {
216 auto proc = ::boost::winapi::GetCurrentProcess();
217
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");
227
228 return ::boost::asio::windows::stream_handle(ios.get_executor(), source);
229 }
230 handle_type sink (::boost::asio::io_context& ios) const &
231 {
232 auto proc = ::boost::winapi::GetCurrentProcess();
233
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");
243
244 return ::boost::asio::windows::stream_handle(ios.get_executor(), sink);
245 }
246 };
247
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())
251 {
252
253 auto proc = ::boost::winapi::GetCurrentProcess();
254
255 ::boost::winapi::HANDLE_ source;
256 ::boost::winapi::HANDLE_ sink;
257
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();
261
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");
269
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");
277
278 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
279 _source.assign(source);
280 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
281 _sink. assign(sink);
282 }
283
284
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)
288 {
289 static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
290
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(),
294 #else
295 name.c_str(),
296 #endif
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);
300
301
302 if (source == boost::winapi::INVALID_HANDLE_VALUE_)
303 ::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed");
304
305 _source.assign(source);
306
307 ::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
308 #if defined(BOOST_NO_ANSI_APIS)
309 ::boost::process::detail::convert(name).c_str(),
310 #else
311 name.c_str(),
312 #endif
313 ::boost::winapi::GENERIC_WRITE_, 0, nullptr,
314 ::boost::winapi::OPEN_EXISTING_,
315 FILE_FLAG_OVERLAPPED_, //to allow read
316 nullptr);
317
318 if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
319 ::boost::process::detail::throw_last_error("create_file() failed");
320
321 _sink.assign(sink);
322 }
323
324 template<class CharT, class Traits>
325 async_pipe& async_pipe::operator=(const basic_pipe<CharT, Traits> & p)
326 {
327 auto proc = ::boost::winapi::GetCurrentProcess();
328
329 ::boost::winapi::HANDLE_ source;
330 ::boost::winapi::HANDLE_ sink;
331
332 //cannot get the handle from a const object.
333 auto source_in = p.native_source();
334 auto sink_in = p.native_sink();
335
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");
343
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");
351
352 //so we also assign the io_context
353 if (source != ::boost::winapi::INVALID_HANDLE_VALUE_)
354 _source.assign(source);
355
356 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
357 _sink.assign(sink);
358
359 return *this;
360 }
361
362 async_pipe& async_pipe::operator=(const async_pipe & p)
363 {
364 auto proc = ::boost::winapi::GetCurrentProcess();
365
366 ::boost::winapi::HANDLE_ source;
367 ::boost::winapi::HANDLE_ sink;
368
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);
372
373 source_in.get_executor();
374
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");
382
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");
390
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);
394 else
395 _source = ::boost::asio::windows::stream_handle(source_in.get_executor());
396
397 if (sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
398 _sink = ::boost::asio::windows::stream_handle(source_in.get_executor(), sink);
399 else
400 _sink = ::boost::asio::windows::stream_handle(source_in.get_executor());
401
402 return *this;
403 }
404
405 async_pipe& async_pipe::operator=(async_pipe && rhs)
406 {
407 _source = std::move(rhs._source);
408 _sink = std::move(rhs._sink);
409 return *this;
410 }
411
412 template<class CharT, class Traits>
413 async_pipe::operator basic_pipe<CharT, Traits>() const
414 {
415 auto proc = ::boost::winapi::GetCurrentProcess();
416
417 ::boost::winapi::HANDLE_ source;
418 ::boost::winapi::HANDLE_ sink;
419
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();
423
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");
431
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");
439
440 return basic_pipe<CharT, Traits>{source, sink};
441 }
442
443 inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
444 {
445 return compare_handles(lhs.native_source(), rhs.native_source()) &&
446 compare_handles(lhs.native_sink(), rhs.native_sink());
447 }
448
449 inline bool operator!=(const async_pipe & lhs, const async_pipe & rhs)
450 {
451 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
452 !compare_handles(lhs.native_sink(), rhs.native_sink());
453 }
454
455 template<class Char, class Traits>
456 inline bool operator==(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
457 {
458 return compare_handles(lhs.native_source(), rhs.native_source()) &&
459 compare_handles(lhs.native_sink(), rhs.native_sink());
460 }
461
462 template<class Char, class Traits>
463 inline bool operator!=(const async_pipe & lhs, const basic_pipe<Char, Traits> & rhs)
464 {
465 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
466 !compare_handles(lhs.native_sink(), rhs.native_sink());
467 }
468
469 template<class Char, class Traits>
470 inline bool operator==(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
471 {
472 return compare_handles(lhs.native_source(), rhs.native_source()) &&
473 compare_handles(lhs.native_sink(), rhs.native_sink());
474 }
475
476 template<class Char, class Traits>
477 inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe & rhs)
478 {
479 return !compare_handles(lhs.native_source(), rhs.native_source()) ||
480 !compare_handles(lhs.native_sink(), rhs.native_sink());
481 }
482
483 }}}}
484
485 #endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */