blob: b7a45614531f0ab7259504a4bd21b7b216db306f [file] [log] [blame]
Yingdi Yu3168c302015-07-04 16:45:40 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#ifndef NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
23#define NDN_CXX_SECURITY_TRANSFORM_BASE_HPP
24
25#include "../../common.hpp"
Yingdi Yu38317e52015-07-22 13:58:02 -070026#include <vector>
Yingdi Yu3168c302015-07-04 16:45:40 -070027
28namespace ndn {
29namespace security {
30namespace transform {
31
32/**
33 * @file transform-base.hpp
34 *
35 * There are three types of module in a transformation chain: Source, Transform, and Sink.
36 * The ideal usage of the transformation would be:
37 *
38 * source(...) >> transform1(...) >> transform2(...) >> sink(...);
39 *
40 * When error happens in a module, the module will throw out a transform::Error, one
41 * can get the location of the module through the getIndex() method of transform::Error.
42 */
43
44/**
45 * @brief Base class of transformation error
46 */
47class Error : public std::runtime_error
48{
49public:
50 Error(size_t index, const std::string& what);
51
52 size_t
53 getIndex() const
54 {
55 return m_index;
56 }
57
58private:
59 size_t m_index;
60};
61
62/**
63 * @brief The downstream interface of a transformation module
64 *
65 * A module can accept input through this interface
66 */
67class Downstream
68{
69public:
Junxiao Shi1b0f4862016-09-10 17:45:04 +000070 virtual
71 ~Downstream() = default;
72
Yingdi Yu3168c302015-07-04 16:45:40 -070073 /**
74 * @brief Accept input data and perform transformation.
75 *
76 * An upstream module should call this method to write data into this module.
77 * The written data will be transformed and the result will be written into the next
78 * downstream module.
79 *
80 * An upstream module can keep calling this method to until end() is called, which
81 * indicates the end of input. After that, calling this method will cause Error.
82 *
83 * If a Downstream implementation expects structured input (e.g., hex decoding requires byte-pair),
84 * it should not return less than size if final portion of input is not a complete record.
85 *
86 * @return number of bytes that has been written into this module
87 * @throws Error if this module is closed or transformation error happens.
88 */
89 size_t
90 write(const uint8_t* buf, size_t size);
91
92 /**
93 * @brief Close the input interface of a module.
94 *
95 * This method will notify this module that there is no more input and that the module
96 * should finalize transformation.
97 *
98 * Although end() can be invoked multiple times, only the first invocation takes effect.
99 */
100 void
101 end();
102
103 /**
104 * @brief Check if the input interface of a module is closed.
105 */
106 bool
107 isEnd() const
108 {
109 return m_isEnd;
110 }
111
112 /**
113 * @brief Set the module index.
114 */
115 void
116 setIndex(size_t index)
117 {
118 m_index = index;
119 }
120
121 /**
122 * @brief Get the module index.
123 */
124 size_t
125 getIndex() const
126 {
127 return m_index;
128 }
129
130protected:
131 Downstream();
132
133private:
134 /**
135 * @brief Internal implementation of write method
136 */
137 virtual size_t
138 doWrite(const uint8_t* buf, size_t size) = 0;
139
140 /**
141 * @brief Internal implementation of end method
142 */
143 virtual void
144 doEnd() = 0;
145
146private:
147 bool m_isEnd;
148 size_t m_index;
149};
150
151/**
152 * @brief The upstream interface of a transformation module
153 *
154 * A module can construct subsequent transformation chain through this interface.
155 */
156class Upstream
157{
Junxiao Shi1b0f4862016-09-10 17:45:04 +0000158public:
159 virtual
160 ~Upstream() = default;
161
Yingdi Yu3168c302015-07-04 16:45:40 -0700162protected:
163 Upstream();
164
165protected:
166 /**
167 * @brief connect to next transformation module
168 */
169 void
170 appendChain(unique_ptr<Downstream> tail);
171
172 Downstream*
173 getNext()
174 {
175 return m_next.get();
176 }
177
178protected:
179 unique_ptr<Downstream> m_next;
180};
181
182/**
183 * @brief Abstraction of an intermediate transformation module
184 */
185class Transform : public Upstream,
186 public Downstream,
187 noncopyable
188{
Yingdi Yu38317e52015-07-22 13:58:02 -0700189protected:
190 typedef std::vector<uint8_t> OBuffer;
191
192 Transform();
193
194 /**
195 * @brief Read the content from output buffer and write it into next module.
Yingdi Yuae734272015-07-04 17:38:48 -0700196 *
197 * It is not guaranteed that all the content in output buffer will be flushed to next module.
Yingdi Yu38317e52015-07-22 13:58:02 -0700198 */
199 void
200 flushOutputBuffer();
201
202 /**
Yingdi Yuae734272015-07-04 17:38:48 -0700203 * @brief Read the all the content from output buffer and write it into next module.
204 * @post isOutputBufferEmpty() returns true.
205 */
206 void
207 flushAllOutput();
208
209 /**
Yingdi Yu38317e52015-07-22 13:58:02 -0700210 * @brief Set output buffer to @p buffer
211 */
212 void
213 setOutputBuffer(unique_ptr<OBuffer> buffer);
214
215 /**
216 * @brief Check if output buffer is empty
217 */
218 bool
219 isOutputBufferEmpty() const;
220
221private:
222
223 /**
224 * @brief Abstraction of data processing in an intermediate module
225 */
226 virtual size_t
227 doWrite(const uint8_t* data, size_t dataLen) final;
228
229 /**
230 * @brief Finalize transformation in this module
231 *
232 * This method will not return until all transformation result is written into next module
233 */
234 virtual void
235 doEnd() final;
236
237 /**
238 * @brief Process before transformation.
239 *
240 * @pre output buffer is empty.
241 *
242 * This method is invoked before every convert(...) invocation.
243 *
244 * This implementation does nothing. A subclass can override this method to perform
245 * specific pre-transformation procedure, e.g., read partial transformation results into
246 * output buffer.
247 */
248 virtual void
249 preTransform();
250
251 /**
252 * @brief Convert input @p data.
253 *
254 * @return The number of input bytes that have been accepted by the converter.
255 */
256 virtual size_t
257 convert(const uint8_t* data, size_t dataLen) = 0;
258
259 /**
260 * @brief Finalize the transformation.
261 *
262 * This implementation only flushes content in output buffer into next module.
263 * A subclass can override this method to perform specific finalization procedure, i.e.,
264 * finalize the transformation and flush the result into next module.
265 */
266 virtual void
267 finalize();
268
269private:
270 unique_ptr<OBuffer> m_oBuffer;
271 size_t m_outputOffset;
Yingdi Yu3168c302015-07-04 16:45:40 -0700272};
273
274/**
275 * @brief Abstraction of the transformation sink module
276 *
277 * This module does not have next module and can only accept input data
278 */
279class Sink : public Downstream,
280 noncopyable
281{
282};
283
284/**
285 * @brief Abstraction of the transformation source module
286 *
287 * This module can only accept input data from constructor
288 */
289class Source : public Upstream,
290 noncopyable
291{
292public:
293 /**
294 * @brief Connect to an intermediate transformation module.
295 */
296 Source&
297 operator>>(unique_ptr<Transform> transform);
298
299 /**
300 * @brief Connect to the last transformation module.
301 *
302 * This method will trigger the source to pump data into the transformation pipeline.
303 */
304 void
305 operator>>(unique_ptr<Sink> sink);
306
307protected:
308 Source();
309
310 /**
311 * @brief Pump all data into next transformation module.
312 */
313 void
314 pump();
315
316 /**
317 * @brief Get the source module index (should always be 0).
318 */
319 size_t
320 getIndex() const
321 {
322 return 0;
323 }
324
325private:
326 /**
327 * @brief Internal implementation of pump().
328 */
329 virtual void
330 doPump() = 0;
331
332private:
333 size_t m_nModules; // count of modules in the chain starting from this Source
334};
335
336} // namespace transform
337} // namespace security
338} // namespace ndn
339
340#endif // NDN_CXX_SECURITY_TRANSFORM_BASE_HPP