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