1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
3 // Copyright (c) 2009 Boris Schaeling
4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 
10 
11 #ifndef BOOST_PROCESS_PIPE_HPP
12 #define BOOST_PROCESS_PIPE_HPP
13 
14 #include <boost/config.hpp>
15 #include <boost/process/detail/config.hpp>
16 #include <streambuf>
17 #include <istream>
18 #include <ostream>
19 #include <vector>
20 
21 #if defined(BOOST_POSIX_API)
22 #include <boost/process/detail/posix/basic_pipe.hpp>
23 #elif defined(BOOST_WINDOWS_API)
24 #include <boost/process/detail/windows/basic_pipe.hpp>
25 #endif
26 
27 namespace boost { namespace process {
28 
29 using ::boost::process::detail::api::basic_pipe;
30 
31 #if defined(BOOST_PROCESS_DOXYGEN)
32 /** Class implementation of a pipe.
33  *
34  */
35 template<class CharT, class Traits = std::char_traits<CharT>>
36 class basic_pipe
37 {
38 public:
39     typedef CharT                      char_type  ;
40     typedef          Traits            traits_type;
41     typedef typename Traits::int_type  int_type   ;
42     typedef typename Traits::pos_type  pos_type   ;
43     typedef typename Traits::off_type  off_type   ;
44     typedef ::boost::detail::winapi::HANDLE_ native_handle;
45 
46     /// Default construct the pipe. Will be opened.
47     basic_pipe();
48 
49     ///Construct a named pipe.
50     inline explicit basic_pipe(const std::string & name);
51     /** Copy construct the pipe.
52      *  \note Duplicated the handles.
53      */
54     inline basic_pipe(const basic_pipe& p);
55     /** Move construct the pipe. */
56     basic_pipe(basic_pipe&& lhs);
57     /** Copy assign the pipe.
58      *  \note Duplicated the handles.
59      */
60     inline basic_pipe& operator=(const basic_pipe& p);
61     /** Move assign the pipe. */
62     basic_pipe& operator=(basic_pipe&& lhs);
63     /** Destructor closes the handles. */
64     ~basic_pipe();
65     /** Get the native handle of the source. */
66     native_handle native_source() const;
67     /** Get the native handle of the sink. */
68     native_handle native_sink  () const;
69 
70     /** Assign a new value to the source */
71     void assign_source(native_handle h);
72     /** Assign a new value to the sink */
73     void assign_sink  (native_handle h);
74 
75 
76     ///Write data to the pipe.
77     int_type write(const char_type * data, int_type count);
78     ///Read data from the pipe.
79     int_type read(char_type * data, int_type count);
80     ///Check if the pipe is open.
81     bool is_open();
82     ///Close the pipe
83     void close();
84 };
85 
86 #endif
87 
88 
89 
90 typedef basic_pipe<char>     pipe;
91 typedef basic_pipe<wchar_t> wpipe;
92 
93 
94 /** Implementation of the stream buffer for a pipe.
95  */
96 template<
97     class CharT,
98     class Traits = std::char_traits<CharT>
99 >
100 struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
101 {
102     typedef basic_pipe<CharT, Traits> pipe_type;
103 
104     typedef           CharT            char_type  ;
105     typedef           Traits           traits_type;
106     typedef  typename Traits::int_type int_type   ;
107     typedef  typename Traits::pos_type pos_type   ;
108     typedef  typename Traits::off_type off_type   ;
109 
110     constexpr static int default_buffer_size = BOOST_PROCESS_PIPE_SIZE;
111 
112     ///Default constructor, will also construct the pipe.
basic_pipebufboost::process::basic_pipebuf113     basic_pipebuf() : _write(default_buffer_size), _read(default_buffer_size)
114     {
115         this->setg(_read.data(),  _read.data()+ 128,  _read.data() + 128);
116         this->setp(_write.data(), _write.data() + _write.size());
117     }
118     ///Copy Constructor.
119     basic_pipebuf(const basic_pipebuf & ) = default;
120     ///Move Constructor
121     basic_pipebuf(basic_pipebuf && ) = default;
122 
123     ///Destructor -> writes the frest of the data
~basic_pipebufboost::process::basic_pipebuf124     ~basic_pipebuf()
125     {
126         if (basic_pipebuf::is_open())
127             basic_pipebuf::overflow(Traits::eof());
128     }
129 
130     ///Move construct from a pipe.
basic_pipebufboost::process::basic_pipebuf131     basic_pipebuf(pipe_type && p) : _pipe(std::move(p)),
132                                     _write(default_buffer_size),
133                                     _read(default_buffer_size)
134     {
135         this->setg(_read.data(),  _read.data()+ 128,  _read.data() + 128);
136         this->setp(_write.data(), _write.data() + _write.size());
137     }
138     ///Construct from a pipe.
basic_pipebufboost::process::basic_pipebuf139     basic_pipebuf(const pipe_type & p) : _pipe(p),
140                                         _write(default_buffer_size),
141                                         _read(default_buffer_size)
142     {
143         this->setg(_read.data(),  _read.data()+ 128,  _read.data() + 128);
144         this->setp(_write.data(), _write.data() + _write.size());
145     }
146     ///Copy assign.
147     basic_pipebuf& operator=(const basic_pipebuf & ) = delete;
148     ///Move assign.
149     basic_pipebuf& operator=(basic_pipebuf && ) = default;
150     ///Move assign a pipe.
operator =boost::process::basic_pipebuf151     basic_pipebuf& operator=(pipe_type && p)
152     {
153         _pipe = std::move(p);
154         return *this;
155     }
156     ///Copy assign a pipe.
operator =boost::process::basic_pipebuf157     basic_pipebuf& operator=(const pipe_type & p)
158     {
159         _pipe = p;
160         return *this;
161     }
162     ///Writes characters to the associated output sequence from the put area
overflowboost::process::basic_pipebuf163     int_type overflow(int_type ch = traits_type::eof()) override
164     {
165         if (_pipe.is_open() && (ch != traits_type::eof()))
166         {
167             if (this->pptr() == this->epptr())
168             {
169                 bool wr = this->_write_impl();
170                 if (wr)
171                 {
172                     *this->pptr() = ch;
173                     this->pbump(1);
174                     return ch;
175                 }
176             }
177             else
178             {
179                 *this->pptr() = ch;
180                 this->pbump(1);
181                 if (this->_write_impl())
182                     return ch;
183             }
184         }
185         else if (ch == traits_type::eof())
186            this->sync();
187 
188         return traits_type::eof();
189     }
190     ///Synchronizes the buffers with the associated character sequence
syncboost::process::basic_pipebuf191     int sync() override { return this->_write_impl() ? 0 : -1; }
192 
193     ///Reads characters from the associated input sequence to the get area
underflowboost::process::basic_pipebuf194     int_type underflow() override
195     {
196         if (!_pipe.is_open())
197             return traits_type::eof();
198 
199         if (this->egptr() == &_read.back()) //ok, so we're at the end of the buffer
200             this->setg(_read.data(),  _read.data()+ 10,  _read.data() + 10);
201 
202 
203         auto len = &_read.back() - this->egptr() ;
204         auto res = _pipe.read(
205                         this->egptr(),
206                         static_cast<typename pipe_type::int_type>(len));
207         if (res == 0)
208             return traits_type::eof();
209 
210         this->setg(this->eback(), this->gptr(), this->egptr() + res);
211         auto val = *this->gptr();
212 
213         return traits_type::to_int_type(val);
214     }
215 
216 
217     ///Set the pipe of the streambuf.
pipeboost::process::basic_pipebuf218     void pipe(pipe_type&& p)      {_pipe = std::move(p); }
219     ///Set the pipe of the streambuf.
pipeboost::process::basic_pipebuf220     void pipe(const pipe_type& p) {_pipe = p; }
221     ///Get a reference to the pipe.
pipeboost::process::basic_pipebuf222     pipe_type &      pipe() &       {return _pipe;}
223     ///Get a const reference to the pipe.
pipeboost::process::basic_pipebuf224     const pipe_type &pipe() const & {return _pipe;}
225     ///Get a rvalue reference to the pipe. Qualified as rvalue.
pipeboost::process::basic_pipebuf226     pipe_type &&     pipe()  &&     {return std::move(_pipe);}
227 
228     ///Check if the pipe is open
is_openboost::process::basic_pipebuf229     bool is_open() const {return _pipe.is_open(); }
230 
231     ///Open a new pipe
openboost::process::basic_pipebuf232     basic_pipebuf<CharT, Traits>* open()
233     {
234         if (is_open())
235             return nullptr;
236         _pipe = pipe();
237         return this;
238     }
239 
240     ///Open a new named pipe
openboost::process::basic_pipebuf241     basic_pipebuf<CharT, Traits>* open(const std::string & name)
242     {
243         if (is_open())
244             return nullptr;
245         _pipe = pipe(name);
246         return this;
247     }
248 
249     ///Flush the buffer & close the pipe
closeboost::process::basic_pipebuf250     basic_pipebuf<CharT, Traits>* close()
251     {
252         if (!is_open())
253             return nullptr;
254         overflow(Traits::eof());
255         return this;
256     }
257 private:
258     pipe_type _pipe;
259     std::vector<char_type> _write;
260     std::vector<char_type> _read;
261 
_write_implboost::process::basic_pipebuf262     bool _write_impl()
263     {
264         if (!_pipe.is_open())
265             return false;
266 
267         auto base = this->pbase();
268 
269         if (base == this->pptr())
270             return true;
271 
272         std::ptrdiff_t wrt = _pipe.write(base,
273                 static_cast<typename pipe_type::int_type>(this->pptr() - base));
274 
275         std::ptrdiff_t diff = this->pptr() - base;
276 
277         if (wrt < diff)
278             std::move(base + wrt, base + diff, base);
279         else if (wrt == 0) //broken pipe
280             return false;
281 
282         this->pbump(static_cast<int>(-wrt));
283 
284         return true;
285     }
286 };
287 
288 typedef basic_pipebuf<char>     pipebuf;
289 typedef basic_pipebuf<wchar_t> wpipebuf;
290 
291 /** Implementation of a reading pipe stream.
292  *
293  */
294 template<
295     class CharT,
296     class Traits = std::char_traits<CharT>
297 >
298 class basic_ipstream : public std::basic_istream<CharT, Traits>
299 {
300     mutable basic_pipebuf<CharT, Traits> _buf;
301 public:
302 
303     typedef basic_pipe<CharT, Traits> pipe_type;
304 
305     typedef           CharT            char_type  ;
306     typedef           Traits           traits_type;
307     typedef  typename Traits::int_type int_type   ;
308     typedef  typename Traits::pos_type pos_type   ;
309     typedef  typename Traits::off_type off_type   ;
310 
311     ///Get access to the underlying stream_buf
rdbuf() const312     basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
313 
314     ///Default constructor.
basic_ipstream()315     basic_ipstream() : std::basic_istream<CharT, Traits>(nullptr)
316     {
317         std::basic_istream<CharT, Traits>::rdbuf(&_buf);
318     };
319     ///Copy constructor.
320     basic_ipstream(const basic_ipstream & ) = delete;
321     ///Move constructor.
basic_ipstream(basic_ipstream && lhs)322     basic_ipstream(basic_ipstream && lhs) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
323     {
324         std::basic_istream<CharT, Traits>::rdbuf(&_buf);
325     }
326 
327     ///Move construct from a pipe.
basic_ipstream(pipe_type && p)328     basic_ipstream(pipe_type && p)      : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(p))
329     {
330         std::basic_istream<CharT, Traits>::rdbuf(&_buf);
331     }
332 
333     ///Copy construct from a pipe.
basic_ipstream(const pipe_type & p)334     basic_ipstream(const pipe_type & p) : std::basic_istream<CharT, Traits>(nullptr), _buf(p)
335     {
336         std::basic_istream<CharT, Traits>::rdbuf(&_buf);
337     }
338 
339     ///Copy assignment.
340     basic_ipstream& operator=(const basic_ipstream & ) = delete;
341     ///Move assignment
operator =(basic_ipstream && lhs)342     basic_ipstream& operator=(basic_ipstream && lhs)
343     {
344         std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
345         _buf = std::move(lhs._buf);
346         std::basic_istream<CharT, Traits>::rdbuf(&_buf);
347         return *this;
348     };
349     ///Move assignment of a pipe.
operator =(pipe_type && p)350     basic_ipstream& operator=(pipe_type && p)
351     {
352         _buf = std::move(p);
353         return *this;
354     }
355     ///Copy assignment of a pipe.
operator =(const pipe_type & p)356     basic_ipstream& operator=(const pipe_type & p)
357     {
358         _buf = p;
359         return *this;
360     }
361     ///Set the pipe of the streambuf.
pipe(pipe_type && p)362     void pipe(pipe_type&& p)      {_buf.pipe(std::move(p)); }
363     ///Set the pipe of the streambuf.
pipe(const pipe_type & p)364     void pipe(const pipe_type& p) {_buf.pipe(p); }
365     ///Get a reference to the pipe.
pipe()366     pipe_type &      pipe() &       {return _buf.pipe();}
367     ///Get a const reference to the pipe.
pipe() const368     const pipe_type &pipe() const & {return _buf.pipe();}
369     ///Get a rvalue reference to the pipe. Qualified as rvalue.
pipe()370     pipe_type &&     pipe()  &&     {return std::move(_buf).pipe();}
371     ///Check if the pipe is open
is_open() const372     bool is_open() const {return _buf.is_open();}
373 
374     ///Open a new pipe
open()375     void open()
376     {
377         if (_buf.open() == nullptr)
378             this->setstate(std::ios_base::failbit);
379         else
380             this->clear();
381     }
382 
383     ///Open a new named pipe
open(const std::string & name)384     void open(const std::string & name)
385     {
386         if (_buf.open() == nullptr)
387             this->setstate(std::ios_base::failbit);
388         else
389             this->clear();
390     }
391 
392     ///Flush the buffer & close the pipe
close()393     void close()
394     {
395         if (_buf.close() == nullptr)
396             this->setstate(std::ios_base::failbit);
397     }
398 };
399 
400 typedef basic_ipstream<char>     ipstream;
401 typedef basic_ipstream<wchar_t> wipstream;
402 
403 /** Implementation of a write pipe stream.
404  *
405  */
406 template<
407     class CharT,
408     class Traits = std::char_traits<CharT>
409 >
410 class basic_opstream : public std::basic_ostream<CharT, Traits>
411 {
412     mutable basic_pipebuf<CharT, Traits> _buf;
413 public:
414     typedef basic_pipe<CharT, Traits> pipe_type;
415 
416     typedef           CharT            char_type  ;
417     typedef           Traits           traits_type;
418     typedef  typename Traits::int_type int_type   ;
419     typedef  typename Traits::pos_type pos_type   ;
420     typedef  typename Traits::off_type off_type   ;
421 
422 
423     ///Get access to the underlying stream_buf
rdbuf() const424     basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
425 
426     ///Default constructor.
basic_opstream()427     basic_opstream() : std::basic_ostream<CharT, Traits>(nullptr)
428     {
429         std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
430     };
431     ///Copy constructor.
432     basic_opstream(const basic_opstream & ) = delete;
433     ///Move constructor.
basic_opstream(basic_opstream && lhs)434     basic_opstream(basic_opstream && lhs) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
435     {
436         std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
437     }
438     ///Move construct from a pipe.
basic_opstream(pipe_type && p)439     basic_opstream(pipe_type && p)      : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(p))
440     {
441         std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
442     };
443     ///Copy construct from a pipe.
basic_opstream(const pipe_type & p)444     basic_opstream(const pipe_type & p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(p)
445     {
446         std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
447     };
448     ///Copy assignment.
449     basic_opstream& operator=(const basic_opstream & ) = delete;
450     ///Move assignment
operator =(basic_opstream && lhs)451     basic_opstream& operator=(basic_opstream && lhs)
452     {
453         std::basic_ostream<CharT, Traits>::operator=(std::move(lhs));
454         _buf = std::move(lhs._buf);
455         std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
456         return *this;
457     };
458 
459     ///Move assignment of a pipe.
operator =(pipe_type && p)460     basic_opstream& operator=(pipe_type && p)
461     {
462         _buf = std::move(p);
463         return *this;
464     }
465     ///Copy assignment of a pipe.
operator =(const pipe_type & p)466     basic_opstream& operator=(const pipe_type & p)
467     {
468         _buf = p;
469         return *this;
470     }
471     ///Set the pipe of the streambuf.
pipe(pipe_type && p)472     void pipe(pipe_type&& p)      {_buf.pipe(std::move(p)); }
473     ///Set the pipe of the streambuf.
pipe(const pipe_type & p)474     void pipe(const pipe_type& p) {_buf.pipe(p); }
475     ///Get a reference to the pipe.
pipe()476     pipe_type &      pipe() &       {return _buf.pipe();}
477     ///Get a const reference to the pipe.
pipe() const478     const pipe_type &pipe() const & {return _buf.pipe();}
479     ///Get a rvalue reference to the pipe. Qualified as rvalue.
pipe()480     pipe_type &&     pipe()  &&     {return std::move(_buf).pipe();}
481 
482     ///Open a new pipe
open()483     void open()
484     {
485         if (_buf.open() == nullptr)
486             this->setstate(std::ios_base::failbit);
487         else
488             this->clear();
489     }
490 
491     ///Open a new named pipe
open(const std::string & name)492     void open(const std::string & name)
493     {
494         if (_buf.open() == nullptr)
495             this->setstate(std::ios_base::failbit);
496         else
497             this->clear();
498     }
499 
500     ///Flush the buffer & close the pipe
close()501     void close()
502     {
503         if (_buf.close() == nullptr)
504             this->setstate(std::ios_base::failbit);
505     }
506 };
507 
508 typedef basic_opstream<char>     opstream;
509 typedef basic_opstream<wchar_t> wopstream;
510 
511 
512 /** Implementation of a read-write pipe stream.
513  *
514  */
515 template<
516     class CharT,
517     class Traits = std::char_traits<CharT>
518 >
519 class basic_pstream : public std::basic_iostream<CharT, Traits>
520 {
521     mutable basic_pipebuf<CharT, Traits> _buf;
522 public:
523     typedef basic_pipe<CharT, Traits> pipe_type;
524 
525     typedef           CharT            char_type  ;
526     typedef           Traits           traits_type;
527     typedef  typename Traits::int_type int_type   ;
528     typedef  typename Traits::pos_type pos_type   ;
529     typedef  typename Traits::off_type off_type   ;
530 
531 
532     ///Get access to the underlying stream_buf
rdbuf() const533     basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
534 
535     ///Default constructor.
basic_pstream()536     basic_pstream() : std::basic_iostream<CharT, Traits>(nullptr)
537     {
538         std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
539     };
540     ///Copy constructor.
541     basic_pstream(const basic_pstream & ) = delete;
542     ///Move constructor.
basic_pstream(basic_pstream && lhs)543     basic_pstream(basic_pstream && lhs) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
544     {
545         std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
546     }
547     ///Move construct from a pipe.
basic_pstream(pipe_type && p)548     basic_pstream(pipe_type && p)      : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(p))
549     {
550         std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
551     };
552     ///Copy construct from a pipe.
basic_pstream(const pipe_type & p)553     basic_pstream(const pipe_type & p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(p)
554     {
555         std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
556     };
557     ///Copy assignment.
558     basic_pstream& operator=(const basic_pstream & ) = delete;
559     ///Move assignment
operator =(basic_pstream && lhs)560     basic_pstream& operator=(basic_pstream && lhs)
561     {
562         std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
563         _buf = std::move(lhs._buf);
564         std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
565         return *this;
566     };
567     ///Move assignment of a pipe.
operator =(pipe_type && p)568     basic_pstream& operator=(pipe_type && p)
569     {
570         _buf = std::move(p);
571         return *this;
572     }
573     ///Copy assignment of a pipe.
operator =(const pipe_type & p)574     basic_pstream& operator=(const pipe_type & p)
575     {
576         _buf = p;
577         return *this;
578     }
579     ///Set the pipe of the streambuf.
pipe(pipe_type && p)580     void pipe(pipe_type&& p)      {_buf.pipe(std::move(p)); }
581     ///Set the pipe of the streambuf.
pipe(const pipe_type & p)582     void pipe(const pipe_type& p) {_buf.pipe(p); }
583     ///Get a reference to the pipe.
pipe()584     pipe_type &      pipe() &       {return _buf.pipe();}
585     ///Get a const reference to the pipe.
pipe() const586     const pipe_type &pipe() const & {return _buf.pipe();}
587     ///Get a rvalue reference to the pipe. Qualified as rvalue.
pipe()588     pipe_type &&     pipe()  &&     {return std::move(_buf).pipe();}
589 
590     ///Open a new pipe
open()591     void open()
592     {
593         if (_buf.open() == nullptr)
594             this->setstate(std::ios_base::failbit);
595         else
596             this->clear();
597     }
598 
599     ///Open a new named pipe
open(const std::string & name)600     void open(const std::string & name)
601     {
602         if (_buf.open() == nullptr)
603             this->setstate(std::ios_base::failbit);
604         else
605             this->clear();
606     }
607 
608     ///Flush the buffer & close the pipe
close()609     void close()
610     {
611         if (_buf.close() == nullptr)
612             this->setstate(std::ios_base::failbit);
613     }
614 };
615 
616 typedef basic_pstream<char>     pstream;
617 typedef basic_pstream<wchar_t> wpstream;
618 
619 
620 
621 }}
622 
623 
624 
625 #endif
626