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