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 #ifndef BOOST_PROCESS_POSIX_PIPE_HPP
11 #define BOOST_PROCESS_POSIX_PIPE_HPP
12 
13 
14 #include <boost/filesystem.hpp>
15 #include <boost/process/detail/posix/compare_handles.hpp>
16 #include <system_error>
17 #include <array>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <memory>
21 
22 namespace boost { namespace process { namespace detail { namespace posix {
23 
24 
25 template<class CharT, class Traits = std::char_traits<CharT>>
26 class basic_pipe
27 {
28     int _source = -1;
29     int _sink   = -1;
30 public:
basic_pipe(int source,int sink)31     explicit basic_pipe(int source, int sink) : _source(source), _sink(sink) {}
basic_pipe(int source,int sink,const std::string &)32     explicit basic_pipe(int source, int sink, const std::string&) : _source(source), _sink(sink) {}
33     typedef CharT                      char_type  ;
34     typedef          Traits            traits_type;
35     typedef typename Traits::int_type  int_type   ;
36     typedef typename Traits::pos_type  pos_type   ;
37     typedef typename Traits::off_type  off_type   ;
38     typedef          int               native_handle_type;
39 
basic_pipe()40     basic_pipe()
41     {
42         int fds[2];
43         if (::pipe(fds) == -1)
44             boost::process::detail::throw_last_error("pipe(2) failed");
45 
46         _source = fds[0];
47         _sink   = fds[1];
48     }
49     inline basic_pipe(const basic_pipe& rhs);
50     explicit inline basic_pipe(const std::string& name);
basic_pipe(basic_pipe && lhs)51     basic_pipe(basic_pipe&& lhs)  : _source(lhs._source), _sink(lhs._sink)
52     {
53         lhs._source = -1;
54         lhs._sink   = -1;
55     }
56     inline basic_pipe& operator=(const basic_pipe& );
operator =(basic_pipe && lhs)57     basic_pipe& operator=(basic_pipe&& lhs)
58     {
59         _source = lhs._source;
60         _sink   = lhs._sink ;
61 
62         lhs._source = -1;
63         lhs._sink   = -1;
64 
65         return *this;
66     }
~basic_pipe()67     ~basic_pipe()
68     {
69         if (_sink   != -1)
70             ::close(_sink);
71         if (_source != -1)
72             ::close(_source);
73     }
native_source() const74     native_handle_type native_source() const {return _source;}
native_sink() const75     native_handle_type native_sink  () const {return _sink;}
76 
assign_source(native_handle_type h)77     void assign_source(native_handle_type h) { _source = h;}
assign_sink(native_handle_type h)78     void assign_sink  (native_handle_type h) { _sink = h;}
79 
80 
81 
82 
write(const char_type * data,int_type count)83     int_type write(const char_type * data, int_type count)
84     {
85         int_type write_len;
86         while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
87         {
88             //Try again if interrupted
89             auto err = errno;
90             if (err != EINTR)
91                 ::boost::process::detail::throw_last_error();
92         }
93         return write_len;
94     }
read(char_type * data,int_type count)95     int_type read(char_type * data, int_type count)
96     {
97         int_type read_len;
98         while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
99         {
100             //Try again if interrupted
101             auto err = errno;
102             if (err != EINTR)
103                 ::boost::process::detail::throw_last_error();
104         }
105         return read_len;
106     }
107 
is_open() const108     bool is_open() const
109     {
110         return (_source != -1) ||
111                (_sink   != -1);
112     }
113 
close()114     void close()
115     {
116         if (_source != -1)
117             ::close(_source);
118         if (_sink != -1)
119             ::close(_sink);
120         _source = -1;
121         _sink   = -1;
122     }
123 };
124 
125 template<class CharT, class Traits>
basic_pipe(const basic_pipe & rhs)126 basic_pipe<CharT, Traits>::basic_pipe(const basic_pipe & rhs)
127 {
128        if (rhs._source != -1)
129        {
130            _source = ::dup(rhs._source);
131            if (_source == -1)
132                ::boost::process::detail::throw_last_error("dup() failed");
133        }
134     if (rhs._sink != -1)
135     {
136         _sink = ::dup(rhs._sink);
137         if (_sink == -1)
138             ::boost::process::detail::throw_last_error("dup() failed");
139 
140     }
141 }
142 
143 template<class CharT, class Traits>
operator =(const basic_pipe & rhs)144 basic_pipe<CharT, Traits> &basic_pipe<CharT, Traits>::operator=(const basic_pipe & rhs)
145 {
146        if (rhs._source != -1)
147        {
148            _source = ::dup(rhs._source);
149            if (_source == -1)
150                ::boost::process::detail::throw_last_error("dup() failed");
151        }
152     if (rhs._sink != -1)
153     {
154         _sink = ::dup(rhs._sink);
155         if (_sink == -1)
156             ::boost::process::detail::throw_last_error("dup() failed");
157 
158     }
159     return *this;
160 }
161 
162 
163 template<class CharT, class Traits>
basic_pipe(const std::string & name)164 basic_pipe<CharT, Traits>::basic_pipe(const std::string & name)
165 {
166     auto fifo = mkfifo(name.c_str(), 0666 );
167 
168     if (fifo != 0)
169         boost::process::detail::throw_last_error("mkfifo() failed");
170 
171 
172     int  read_fd = open(name.c_str(), O_RDWR);
173 
174     if (read_fd == -1)
175         boost::process::detail::throw_last_error();
176 
177     int write_fd = dup(read_fd);
178 
179     if (write_fd == -1)
180         boost::process::detail::throw_last_error();
181 
182     _sink = write_fd;
183     _source = read_fd;
184     ::unlink(name.c_str());
185 }
186 
187 template<class Char, class Traits>
operator ==(const basic_pipe<Char,Traits> & lhs,const basic_pipe<Char,Traits> & rhs)188 inline bool operator==(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
189 {
190     return compare_handles(lhs.native_source(), rhs.native_source()) &&
191            compare_handles(lhs.native_sink(),   rhs.native_sink());
192 }
193 
194 template<class Char, class Traits>
operator !=(const basic_pipe<Char,Traits> & lhs,const basic_pipe<Char,Traits> & rhs)195 inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Char, Traits> & rhs)
196 {
197     return !compare_handles(lhs.native_source(), rhs.native_source()) ||
198            !compare_handles(lhs.native_sink(),   rhs.native_sink());
199 }
200 
201 }}}}
202 
203 #endif
204