blob: 92b390b4d1cccee54f106154b153fbfb50b9116a [file] [log] [blame]
Alexander Afanasyeve1e6f2a2014-04-25 11:28:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Shuo Chenba793e92014-03-17 17:17:16 -07002/**
Alexander Afanasyeve1e6f2a2014-04-25 11:28:12 -07003 * Copyright (c) 2014, Regents of the University of California.
4 *
5 * This file is part of NDN repo-ng (Next generation of NDN repository).
6 * See AUTHORS.md for complete list of repo-ng authors and contributors.
7 *
8 * repo-ng is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Shuo Chenba793e92014-03-17 17:17:16 -070018 */
19
Alexander Afanasyev39d98072014-05-04 12:46:29 -070020#ifndef REPO_REPO_COMMAND_RESPONSE_HPP
21#define REPO_REPO_COMMAND_RESPONSE_HPP
Shuo Chenba793e92014-03-17 17:17:16 -070022
Alexander Afanasyeve291caf2014-04-25 11:17:36 -070023#include <ndn-cxx/encoding/block.hpp>
Wentao Shang91fb4f22014-05-20 10:55:22 -070024#include <ndn-cxx/encoding/block-helpers.hpp>
Alexander Afanasyeve291caf2014-04-25 11:17:36 -070025#include <ndn-cxx/encoding/encoding-buffer.hpp>
26#include <ndn-cxx/encoding/tlv-nfd.hpp>
Shuo Chenba793e92014-03-17 17:17:16 -070027#include "repo-tlv.hpp"
28
29namespace repo {
30
31using ndn::Block;
32using ndn::EncodingImpl;
33using ndn::EncodingEstimator;
34using ndn::EncodingBuffer;
35
36/**
37* @brief Class defining abstraction of Response for NDN Repo Protocol
38* @sa link http://redmine.named-data.net/projects/repo-ng/wiki/Repo_Protocol_Specification#Repo-Command-Response
39*/
40class RepoCommandResponse
41{
42public:
43 class Error : public ndn::Tlv::Error
44 {
45 public:
46 explicit
47 Error(const std::string& what)
48 : ndn::Tlv::Error(what)
49 {
50 }
51 };
52
53 RepoCommandResponse()
54 : m_hasStartBlockId(false)
55 , m_hasEndBlockId(false)
56 , m_hasProcessId(false)
57 , m_hasInsertNum(false)
58 , m_hasDeleteNum(false)
59 , m_hasStatusCode(false)
60 {
61 }
62
63 explicit
64 RepoCommandResponse(const Block& block)
65 {
66 wireDecode(block);
67 }
68
69 uint64_t
70 getStartBlockId() const
71 {
72 return m_startBlockId;
73 }
74
75 RepoCommandResponse&
76 setStartBlockId(uint64_t startBlockId)
77 {
78 m_startBlockId = startBlockId;
79 m_hasStartBlockId = true;
80 m_wire.reset();
81 return *this;
82 }
83
84 bool
85 hasStartBlockId() const
86 {
87 return m_hasStartBlockId;
88 }
89
90 uint64_t
91 getEndBlockId() const
92 {
93 assert(hasEndBlockId());
94 return m_endBlockId;
95 }
96
97 RepoCommandResponse&
98 setEndBlockId(uint64_t endBlockId)
99 {
100 m_endBlockId = endBlockId;
101 m_hasEndBlockId = true;
102 m_wire.reset();
103 return *this;
104 }
105
106 bool
107 hasEndBlockId() const
108 {
109 return m_hasEndBlockId;
110 }
111
112
113 uint64_t
114 getProcessId() const
115 {
116 return m_processId;
117 }
118
119 RepoCommandResponse&
120 setProcessId(uint64_t processId)
121 {
122 m_processId = processId;
123 m_hasProcessId = true;
124 m_wire.reset();
125 return *this;
126 }
127
128 bool
129 hasProcessId() const
130 {
131 return m_hasProcessId;
132 }
133
134 uint64_t
135 getStatusCode() const
136 {
137 return m_statusCode;
138 }
139
140 RepoCommandResponse&
141 setStatusCode(uint64_t statusCode)
142 {
143 m_statusCode = statusCode;
144 m_hasStatusCode = true;
145 m_wire.reset();
146 return *this;
147 }
148
149 bool
150 hasStatusCode() const
151 {
152 return m_hasStatusCode;
153 }
154
155 uint64_t
156 getInsertNum() const
157 {
158 return m_insertNum;
159 }
160
161 RepoCommandResponse&
162 setInsertNum(uint64_t insertNum)
163 {
164 m_insertNum = insertNum;
165 m_hasInsertNum = true;
166 m_wire.reset();
167 return *this;
168 }
169
170 bool
171 hasInsertNum() const
172 {
173 return m_hasInsertNum;
174 }
175
176 uint64_t
177 getDeleteNum() const
178 {
179 return m_deleteNum;
180 }
181
182 RepoCommandResponse&
183 setDeleteNum(uint64_t deleteNum)
184 {
185 m_deleteNum = deleteNum;
186 m_hasDeleteNum = true;
187 m_wire.reset();
188 return *this;
189 }
190
191 bool
192 hasDeleteNum() const
193 {
194 return m_hasDeleteNum;
195 }
196
197 template<bool T>
198 size_t
199 wireEncode(EncodingImpl<T>& block) const;
200
201 const Block&
202 wireEncode() const;
203
204 void
205 wireDecode(const Block& wire);
206
207private:
208 uint64_t m_statusCode;
209 uint64_t m_startBlockId;
210 uint64_t m_endBlockId;
211 uint64_t m_processId;
212 uint64_t m_insertNum;
213 uint64_t m_deleteNum;
214
215 bool m_hasStartBlockId;
216 bool m_hasEndBlockId;
217 bool m_hasProcessId;
218 bool m_hasInsertNum;
219 bool m_hasDeleteNum;
220 bool m_hasStatusCode;
221
222 mutable Block m_wire;
223};
224
225template<bool T>
226inline size_t
227RepoCommandResponse::wireEncode(EncodingImpl<T>& encoder) const
228{
229 size_t totalLength = 0;
230 size_t variableLength = 0;
231
232 if (m_hasDeleteNum) {
233 variableLength = encoder.prependNonNegativeInteger(m_deleteNum);
234 totalLength += variableLength;
235 totalLength += encoder.prependVarNumber(variableLength);
236 totalLength += encoder.prependVarNumber(tlv::DeleteNum);
237 }
238
239 if (m_hasInsertNum) {
240 variableLength = encoder.prependNonNegativeInteger(m_insertNum);
241 totalLength += variableLength;
242 totalLength += encoder.prependVarNumber(variableLength);
243 totalLength += encoder.prependVarNumber(tlv::InsertNum);
244 }
245
246 if (m_hasEndBlockId) {
247 variableLength = encoder.prependNonNegativeInteger(m_endBlockId);
248 totalLength += variableLength;
249 totalLength += encoder.prependVarNumber(variableLength);
250 totalLength += encoder.prependVarNumber(tlv::EndBlockId);
251 }
252
253 if (m_hasStartBlockId) {
254 variableLength = encoder.prependNonNegativeInteger(m_startBlockId);
255 totalLength += variableLength;
256 totalLength += encoder.prependVarNumber(variableLength);
257 totalLength += encoder.prependVarNumber(repo::tlv::StartBlockId);
258 }
259
260 if (m_hasStatusCode) {
261 variableLength = encoder.prependNonNegativeInteger(m_statusCode);
262 totalLength += variableLength;
263 totalLength += encoder.prependVarNumber(variableLength);
264 totalLength += encoder.prependVarNumber(tlv::StatusCode);
265 } else {
266 throw Error("required field StatusCode is missing");
267 }
268
269 if (m_hasProcessId) {
270 variableLength = encoder.prependNonNegativeInteger(m_processId);
271 totalLength += variableLength;
272 totalLength += encoder.prependVarNumber(variableLength);
273 totalLength += encoder.prependVarNumber(tlv::ProcessId);
274 }
275
276 totalLength += encoder.prependVarNumber(totalLength);
277 totalLength += encoder.prependVarNumber(tlv::RepoCommandResponse);
278 return totalLength;
279}
280
281inline const Block&
282RepoCommandResponse::wireEncode() const
283{
284 if (m_wire.hasWire())
285 return m_wire;
286
287 EncodingEstimator estimator;
288 size_t estimatedSize = wireEncode(estimator);
289
290 EncodingBuffer buffer(estimatedSize, 0);
291 wireEncode(buffer);
292
293 m_wire = buffer.block();
294 return m_wire;
295}
296
297inline void
298RepoCommandResponse::wireDecode(const Block& wire)
299{
300 m_hasStartBlockId = false;
301 m_hasEndBlockId = false;
302 m_hasProcessId = false;
303 m_hasStatusCode = false;
304 m_hasInsertNum = false;
305 m_hasDeleteNum = false;
306
307 m_wire = wire;
308
309 m_wire.parse();
310
311 Block::element_const_iterator val;
312
313 if (m_wire.type() != tlv::RepoCommandResponse)
314 throw Error("RepoCommandResponse malformed");
315
316 // StartBlockId
317 val = m_wire.find(tlv::StartBlockId);
318 if (val != m_wire.elements_end())
319 {
320 m_hasStartBlockId = true;
321 m_startBlockId = readNonNegativeInteger(*val);
322 }
323
324 // EndBlockId
325 val = m_wire.find(tlv::EndBlockId);
326 if (val != m_wire.elements_end())
327 {
328 m_hasEndBlockId = true;
329 m_endBlockId = readNonNegativeInteger(*val);
330 }
331
332 // ProcessId
333 val = m_wire.find(tlv::ProcessId);
334 if (val != m_wire.elements_end())
335 {
336 m_hasProcessId = true;
337 m_processId = readNonNegativeInteger(*val);
338 }
339
340 // StatusCode
341 val = m_wire.find(tlv::StatusCode);
342 if (val != m_wire.elements_end())
343 {
344 m_hasStatusCode = true;
345 m_statusCode = readNonNegativeInteger(*val);
346
347 } else {
348 throw Error("required field StatusCode is missing");
349 }
350
351 // InsertNum
352 val = m_wire.find(tlv::InsertNum);
353 if (val != m_wire.elements_end())
354 {
355 m_hasInsertNum = true;
356 m_insertNum = readNonNegativeInteger(*val);
357 }
358
359 // DeleteNum
360 val = m_wire.find(tlv::DeleteNum);
361 if (val != m_wire.elements_end())
362 {
363 m_hasDeleteNum = true;
364 m_deleteNum = readNonNegativeInteger(*val);
365 }
366}
367
368inline std::ostream&
369operator<<(std::ostream& os, const RepoCommandResponse& repoCommandResponse)
370{
371 os << "RepoCommandResponse(";
372
373 if (repoCommandResponse.hasProcessId()) {
374 os << " ProcessId: " << repoCommandResponse.getProcessId();
375 }
376 if (repoCommandResponse.hasStatusCode()) {
377 os << " StatusCode: " << repoCommandResponse.getStatusCode();
378 }
379 if (repoCommandResponse.hasStartBlockId()) {
380 os << " StartBlockId: " << repoCommandResponse.getStartBlockId();
381 }
382 if (repoCommandResponse.hasEndBlockId()) {
383 os << " EndBlockId: " << repoCommandResponse.getEndBlockId();
384 }
385 if (repoCommandResponse.hasInsertNum()) {
386 os << " InsertNum: " << repoCommandResponse.getInsertNum();
387 }
388 if (repoCommandResponse.hasDeleteNum()) {
389 os << " DeleteNum: " << repoCommandResponse.getDeleteNum();
390
391 }
392 os << " )";
393 return os;
394}
Alexander Afanasyev39d98072014-05-04 12:46:29 -0700395
396} // namespace repo
397
398#endif // REPO_REPO_COMMAND_RESPONSE_HPP