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