Botan  2.7.0
Crypto and TLS for C++11
pipe.cpp
Go to the documentation of this file.
1 /*
2 * Pipe
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/pipe.h>
9 #include <botan/internal/out_buf.h>
10 #include <botan/secqueue.h>
11 
12 namespace Botan {
13 
14 namespace {
15 
16 /*
17 * A Filter that does nothing
18 */
19 class Null_Filter final : public Filter
20  {
21  public:
22  void write(const uint8_t input[], size_t length) override
23  { send(input, length); }
24 
25  std::string name() const override { return "Null"; }
26  };
27 
28 }
29 
30 /*
31 * Pipe Constructor
32 */
33 Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) :
34  Pipe({f1,f2,f3,f4})
35  {
36  }
37 
38 /*
39 * Pipe Constructor
40 */
41 Pipe::Pipe(std::initializer_list<Filter*> args)
42  {
43  m_outputs.reset(new Output_Buffers);
44  m_pipe = nullptr;
45  m_default_read = 0;
46  m_inside_msg = false;
47 
48  for(auto i = args.begin(); i != args.end(); ++i)
49  do_append(*i);
50  }
51 
52 /*
53 * Pipe Destructor
54 */
56  {
57  destruct(m_pipe);
58  }
59 
60 /*
61 * Reset the Pipe
62 */
64  {
65  destruct(m_pipe);
66  m_pipe = nullptr;
67  m_inside_msg = false;
68  }
69 
70 /*
71 * Destroy the Pipe
72 */
73 void Pipe::destruct(Filter* to_kill)
74  {
75  if(!to_kill || dynamic_cast<SecureQueue*>(to_kill))
76  return;
77  for(size_t j = 0; j != to_kill->total_ports(); ++j)
78  destruct(to_kill->m_next[j]);
79  delete to_kill;
80  }
81 
82 /*
83 * Test if the Pipe has any data in it
84 */
85 bool Pipe::end_of_data() const
86  {
87  return (remaining() == 0);
88  }
89 
90 /*
91 * Set the default read message
92 */
94  {
95  if(msg >= message_count())
96  throw Invalid_Argument("Pipe::set_default_msg: msg number is too high");
97  m_default_read = msg;
98  }
99 
100 /*
101 * Process a full message at once
102 */
103 void Pipe::process_msg(const uint8_t input[], size_t length)
104  {
105  start_msg();
106  write(input, length);
107  end_msg();
108  }
109 
110 /*
111 * Process a full message at once
112 */
114  {
115  process_msg(input.data(), input.size());
116  }
117 
118 void Pipe::process_msg(const std::vector<uint8_t>& input)
119  {
120  process_msg(input.data(), input.size());
121  }
122 
123 /*
124 * Process a full message at once
125 */
126 void Pipe::process_msg(const std::string& input)
127  {
128  process_msg(cast_char_ptr_to_uint8(input.data()), input.length());
129  }
130 
131 /*
132 * Process a full message at once
133 */
135  {
136  start_msg();
137  write(input);
138  end_msg();
139  }
140 
141 /*
142 * Start a new message
143 */
145  {
146  if(m_inside_msg)
147  throw Invalid_State("Pipe::start_msg: Message was already started");
148  if(m_pipe == nullptr)
149  m_pipe = new Null_Filter;
150  find_endpoints(m_pipe);
151  m_pipe->new_msg();
152  m_inside_msg = true;
153  }
154 
155 /*
156 * End the current message
157 */
159  {
160  if(!m_inside_msg)
161  throw Invalid_State("Pipe::end_msg: Message was already ended");
162  m_pipe->finish_msg();
163  clear_endpoints(m_pipe);
164  if(dynamic_cast<Null_Filter*>(m_pipe))
165  {
166  delete m_pipe;
167  m_pipe = nullptr;
168  }
169  m_inside_msg = false;
170 
171  m_outputs->retire();
172  }
173 
174 /*
175 * Find the endpoints of the Pipe
176 */
177 void Pipe::find_endpoints(Filter* f)
178  {
179  for(size_t j = 0; j != f->total_ports(); ++j)
180  if(f->m_next[j] && !dynamic_cast<SecureQueue*>(f->m_next[j]))
181  find_endpoints(f->m_next[j]);
182  else
183  {
184  SecureQueue* q = new SecureQueue;
185  f->m_next[j] = q;
186  m_outputs->add(q);
187  }
188  }
189 
190 /*
191 * Remove the SecureQueues attached to the Filter
192 */
193 void Pipe::clear_endpoints(Filter* f)
194  {
195  if(!f) return;
196  for(size_t j = 0; j != f->total_ports(); ++j)
197  {
198  if(f->m_next[j] && dynamic_cast<SecureQueue*>(f->m_next[j]))
199  f->m_next[j] = nullptr;
200  clear_endpoints(f->m_next[j]);
201  }
202  }
203 
204 void Pipe::append(Filter* filter)
205  {
206  do_append(filter);
207  }
208 
210  {
211  if(m_outputs->message_count() != 0)
212  throw Invalid_State("Cannot call Pipe::append_filter after start_msg");
213 
214  do_append(filter);
215  }
216 
217 void Pipe::prepend(Filter* filter)
218  {
219  do_prepend(filter);
220  }
221 
223  {
224  if(m_outputs->message_count() != 0)
225  throw Invalid_State("Cannot call Pipe::prepend_filter after start_msg");
226 
227  do_prepend(filter);
228  }
229 
230 /*
231 * Append a Filter to the Pipe
232 */
233 void Pipe::do_append(Filter* filter)
234  {
235  if(!filter)
236  return;
237  if(dynamic_cast<SecureQueue*>(filter))
238  throw Invalid_Argument("Pipe::append: SecureQueue cannot be used");
239  if(filter->m_owned)
240  throw Invalid_Argument("Filters cannot be shared among multiple Pipes");
241 
242  if(m_inside_msg)
243  throw Invalid_State("Cannot append to a Pipe while it is processing");
244 
245  filter->m_owned = true;
246 
247  if(!m_pipe) m_pipe = filter;
248  else m_pipe->attach(filter);
249  }
250 
251 /*
252 * Prepend a Filter to the Pipe
253 */
254 void Pipe::do_prepend(Filter* filter)
255  {
256  if(m_inside_msg)
257  throw Invalid_State("Cannot prepend to a Pipe while it is processing");
258  if(!filter)
259  return;
260  if(dynamic_cast<SecureQueue*>(filter))
261  throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used");
262  if(filter->m_owned)
263  throw Invalid_Argument("Filters cannot be shared among multiple Pipes");
264 
265  filter->m_owned = true;
266 
267  if(m_pipe) filter->attach(m_pipe);
268  m_pipe = filter;
269  }
270 
271 /*
272 * Pop a Filter off the Pipe
273 */
274 void Pipe::pop()
275  {
276  if(m_inside_msg)
277  throw Invalid_State("Cannot pop off a Pipe while it is processing");
278 
279  if(!m_pipe)
280  return;
281 
282  if(m_pipe->total_ports() > 1)
283  throw Invalid_State("Cannot pop off a Filter with multiple ports");
284 
285  size_t to_remove = m_pipe->owns() + 1;
286 
287  while(to_remove--)
288  {
289  std::unique_ptr<Filter> to_destroy(m_pipe);
290  m_pipe = m_pipe->m_next[0];
291  }
292  }
293 
294 /*
295 * Return the number of messages in this Pipe
296 */
298  {
299  return m_outputs->message_count();
300  }
301 
302 /*
303 * Static Member Variables
304 */
306  static_cast<Pipe::message_id>(-2);
307 
309  static_cast<Pipe::message_id>(-1);
310 
311 }
void start_msg()
Definition: pipe.cpp:144
void append(Filter *filt)
Definition: pipe.cpp:204
size_t remaining(message_id msg=DEFAULT_MESSAGE) const BOTAN_WARN_UNUSED_RESULT
Definition: pipe_rw.cpp:131
void prepend_filter(Filter *filt)
Definition: pipe.cpp:222
size_t message_id
Definition: pipe.h:35
const uint8_t * cast_char_ptr_to_uint8(const char *s)
Definition: mem_ops.h:131
void reset()
Definition: pipe.cpp:63
static const message_id DEFAULT_MESSAGE
Definition: pipe.h:62
void end_msg()
Definition: pipe.cpp:158
static const message_id LAST_MESSAGE
Definition: pipe.h:57
Pipe(Filter *=nullptr, Filter *=nullptr, Filter *=nullptr, Filter *=nullptr)
Definition: pipe.cpp:33
void process_msg(const uint8_t in[], size_t length)
Definition: pipe.cpp:103
Definition: alg_id.cpp:13
message_id message_count() const
Definition: pipe.cpp:297
void append_filter(Filter *filt)
Definition: pipe.cpp:209
void pop()
Definition: pipe.cpp:274
void set_default_msg(message_id msg)
Definition: pipe.cpp:93
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
void process_msg(const std::vector< uint8_t > &in)
Definition: pipe.cpp:118
bool end_of_data() const override
Definition: pipe.cpp:85
void prepend(Filter *filt)
Definition: pipe.cpp:217
void write(const uint8_t in[], size_t length)
Definition: pipe_rw.cpp:35