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