blob: aca3a00d63315d126d1de83f0113835ec67dd367 [file] [log] [blame]
Yingdi Yu3168c302015-07-04 16:45:40 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoba4fbbe2017-07-03 01:06:30 -04002/*
3 * Copyright (c) 2013-2017 Regents of the University of California.
Yingdi Yu3168c302015-07-04 16:45:40 -07004 *
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/**
Davide Pesaventoba4fbbe2017-07-03 01:06:30 -040033 * @file
Yingdi Yu3168c302015-07-04 16:45:40 -070034 *
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:
Yingdi Yu38317e52015-07-22 13:58:02 -0700222 /**
223 * @brief Abstraction of data processing in an intermediate module
224 */
Davide Pesavento57c07df2016-12-11 18:41:45 -0500225 size_t
Yingdi Yu38317e52015-07-22 13:58:02 -0700226 doWrite(const uint8_t* data, size_t dataLen) final;
227
228 /**
229 * @brief Finalize transformation in this module
230 *
231 * This method will not return until all transformation result is written into next module
232 */
Davide Pesavento57c07df2016-12-11 18:41:45 -0500233 void
Yingdi Yu38317e52015-07-22 13:58:02 -0700234 doEnd() final;
235
236 /**
237 * @brief Process before transformation.
238 *
239 * @pre output buffer is empty.
240 *
241 * This method is invoked before every convert(...) invocation.
242 *
243 * This implementation does nothing. A subclass can override this method to perform
244 * specific pre-transformation procedure, e.g., read partial transformation results into
245 * output buffer.
246 */
247 virtual void
248 preTransform();
249
250 /**
251 * @brief Convert input @p data.
252 *
253 * @return The number of input bytes that have been accepted by the converter.
254 */
255 virtual size_t
256 convert(const uint8_t* data, size_t dataLen) = 0;
257
258 /**
259 * @brief Finalize the transformation.
260 *
261 * This implementation only flushes content in output buffer into next module.
262 * A subclass can override this method to perform specific finalization procedure, i.e.,
263 * finalize the transformation and flush the result into next module.
264 */
265 virtual void
266 finalize();
267
268private:
269 unique_ptr<OBuffer> m_oBuffer;
270 size_t m_outputOffset;
Yingdi Yu3168c302015-07-04 16:45:40 -0700271};
272
273/**
274 * @brief Abstraction of the transformation sink module
275 *
276 * This module does not have next module and can only accept input data
277 */
278class Sink : public Downstream,
279 noncopyable
280{
281};
282
283/**
284 * @brief Abstraction of the transformation source module
285 *
286 * This module can only accept input data from constructor
287 */
288class Source : public Upstream,
289 noncopyable
290{
291public:
292 /**
293 * @brief Connect to an intermediate transformation module.
294 */
295 Source&
296 operator>>(unique_ptr<Transform> transform);
297
298 /**
299 * @brief Connect to the last transformation module.
300 *
301 * This method will trigger the source to pump data into the transformation pipeline.
302 */
303 void
304 operator>>(unique_ptr<Sink> sink);
305
306protected:
307 Source();
308
309 /**
310 * @brief Pump all data into next transformation module.
311 */
312 void
313 pump();
314
315 /**
316 * @brief Get the source module index (should always be 0).
317 */
318 size_t
319 getIndex() const
320 {
321 return 0;
322 }
323
324private:
325 /**
326 * @brief Internal implementation of pump().
327 */
328 virtual void
329 doPump() = 0;
330
331private:
332 size_t m_nModules; // count of modules in the chain starting from this Source
333};
334
335} // namespace transform
336} // namespace security
337} // namespace ndn
338
339#endif // NDN_CXX_SECURITY_TRANSFORM_BASE_HPP