source: trash/old-modules/transport/protlib/ie.h@ 7045

Last change on this file since 7045 was 5641, checked in by Christoph Mayer, 15 years ago
File size: 13.8 KB
RevLine 
[5641]1/// ----------------------------------------*- mode: C++; -*--
2/// @file ie.h
3/// Basic information elements (PDUs and PDU objects)
4/// ----------------------------------------------------------
5/// $Id: ie.h 2549 2007-04-02 22:17:37Z bless $
6/// $HeadURL: https://svn.ipv6.tm.uka.de/nsis/protlib/trunk/include/ie.h $
7// ===========================================================
8//
9// Copyright (C) 2005-2007, all rights reserved by
10// - Institute of Telematics, Universitaet Karlsruhe (TH)
11//
12// More information and contact:
13// https://projekte.tm.uka.de/trac/NSIS
14//
15// This program is free software; you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation; version 2 of the License
18//
19// This program is distributed in the hope that it will be useful,
20// but WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22// GNU General Public License for more details.
23//
24// You should have received a copy of the GNU General Public License along
25// with this program; if not, write to the Free Software Foundation, Inc.,
26// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27//
28// ===========================================================
29
30/** @ingroup ie
31 * @todo Use objectpool by deriving classes from class poolobject and
32 * linking executables against objectpool.o or including objectpool.o into
33 * libie.a.
34 *
35 * This header file defines the base class of all information elements, the
36 * information elements for the protocol and an IE manager object.
37 *
38 * For performance only pointers are exchanged. The copy member function is
39 * the way to duplicate an IE. It does much the same as a copy constructor
40 * but returns not the IE but a pointer to it. If the IE contains pointers,
41 * their target objects are copied too.
42 */
43
44#ifndef _PROTLIB__IE_H_
45#define _PROTLIB__IE_H_
46
47#include <ext/hash_map>
48#include <deque>
49#include <string>
50#include <iostream>
51#include <map>
52
53#include "protlib_types.h"
54#include "network_message.h"
55
56namespace protlib {
57
58
59
60/** @addtogroup ie Information Elements
61 * @{
62 */
63
64/// Catch bad_alloc and call throw_nomem_error
65#define catch_bad_alloc(x) try { x; } catch(bad_alloc) { throw_nomem_error(); }
66
67// forward declarations
68class IEManager;
69class IEErrorList;
70class IEError;
71
72/** Abstract Information Element (IE) interface
73 */
74class IE {
75public:
76 virtual ~IE() { }
77
78 friend class IEManager;
79 /// IE coding sheme
80 /** All coding shemes have to be listed here. Each IE should support at
81 * least one listed coding sheme. This is used when serializing or
82 * deserializing from a NetMsg object to (de)code the IE in the right way.
83 * Note that coding schemes and protocol version are not the same.
84 * There could also be a coding sheme to (de)code IEs e.g. for router
85 * configuration.
86 */
87 enum coding_t {
88 nslp_v1 = 1,
89 protocol_v1 = 1,
90 protocol_v2 = 2,
91 nslp_v2 = 3,
92 nslp_v2_yoda = 4
93 }; // end coding_t
94protected:
95 /// contructor
96 IE(uint16 category);
97 /// copy constructor
98 IE(const IE& n);
99public:
100 /// get a new instance of the IE
101 virtual IE* new_instance() const = 0;
102 /// copy an IE
103 virtual IE* copy() const = 0;
104 /// deserialization
105 virtual IE* deserialize(NetMsg& msg, coding_t coding, IEErrorList& errorlist, uint32& bread, bool skip = true) = 0;
106 /// serialize
107 virtual void serialize(NetMsg& msg, coding_t coding, uint32& wbytes) const = 0;
108protected:
109 /// check arguments for deserialization
110 bool check_deser_args(coding_t cod, IEErrorList& errorlist, uint32 &bread) const;
111 /// check arguments for serialization
112 void check_ser_args(coding_t cod, uint32 &wbytes) const;
113public:
114 /// IE consistency check
115 virtual bool check() const = 0;
116 /// check if IE supports coding sheme
117 virtual bool supports_coding(coding_t c) const = 0;
118 /// IE serialized size
119 virtual size_t get_serialized_size(coding_t coding) const = 0;
120 /// get category
121 uint16 get_category() const;
122 /// equality
123 virtual bool operator==(const IE& ie) const = 0;
124 /// not equal
125 inline bool operator!=(const IE& ie) const { return (!(*this==ie)); }
126 /// get IE name
127 /** This is mainly for error reporting. */
128 virtual const char* get_ie_name() const = 0;
129 /// print to a ostream
130 virtual ostream& print(ostream& os, uint32 level, const uint32 indent, const char* name = NULL) const;
131 /// get a string representing the IE content
132 string to_string(const char* name = 0) const;
133 /// input from an istream
134 /** Attention: No checking, no warnings. This is ONLY for testing. */
135 virtual istream& input(istream& is, bool istty, uint32 level, const uint32 indent, const char* name = NULL);
136 /// clear all pointer fields
137 virtual void clear_pointers();
138protected:
139 /// register this IE
140 virtual void register_ie(IEManager *iem) const = 0;
141 /// IE category
142 const uint16 category;
143 /// throw a NO_MEM exception
144 void throw_nomem_error() const;
145}; // end class IE
146
147
148
149/**
150 * IE Error base class.
151 *
152 * This is the base for all exceptions thrown during serialize() and
153 * deserialize().
154 *
155 * @warning New code should use the exceptions derived from this class.
156 * This class should be abstract but isn't for compatibility reasons.
157 */
158class IEError : public ProtLibException {
159 public:
160 /// IE error code - common parsing errors
161 enum error_t {
162 ERROR_REGISTER,
163 ERROR_CODING,
164 ERROR_CATEGORY,
165 ERROR_NO_IEMANAGER,
166 ERROR_MSG_TOO_SHORT,
167 ERROR_INVALID_STATE,
168 ERROR_WRONG_TYPE,
169 ERROR_WRONG_SUBTYPE,
170 ERROR_WRONG_LENGTH,
171 ERROR_NO_MEM,
172 ERROR_TOO_BIG_FOR_IMPL,
173 ERROR_UNKNOWN_ERRORCODE,
174 ERROR_WRONG_VERSION,
175 ERROR_UNEXPECTED_OBJECT,
176 ERROR_PDU_SYNTAX,
177 ERROR_OBJ_SET_FAILED,
178 ERROR_PROT_SPECIFIC
179 }; // end error_t
180
181 const error_t err;
182
183 IEError(error_t e);
184 virtual ~IEError() throw ();
185
186 virtual const char *getstr() const;
187
188 protected:
189 IEError(std::string msg) throw ();
190
191 private:
192 static const char* err_str[];
193};
194
195
196/**
197 * Syntax error during deserialization.
198 *
199 * This exception is thrown if a syntax error is detected during
200 * deserialization.
201 */
202class PDUSyntaxError : public IEError {
203 public:
204 PDUSyntaxError(const char* msg); // deprecated!
205 PDUSyntaxError(IE::coding_t coding, uint16 category, uint16 type,
206 uint16 subtype, uint32 pos, const char *msg = "");
207 virtual ~PDUSyntaxError() throw () { }
208
209 const IE::coding_t coding;
210 const uint16 category;
211 const uint16 type;
212 const uint16 subtype;
213 const uint32 errorpos;
214 const string message;
215};
216
217
218/**
219 * NetMsg is too short to serialize/deserialize.
220 *
221 * This exception is typically thrown if a NetMsg ended unexpectedly
222 * which indicates a truncated message. It may also be thrown if a
223 * NetMsg is too short to hold a serialized IE object.
224 */
225class IEMsgTooShort : public IEError {
226 public:
227 IEMsgTooShort(IE::coding_t coding, uint16 category, uint32 pos);
228 virtual ~IEMsgTooShort() throw () { }
229
230 const IE::coding_t coding;
231 const uint16 category;
232 const uint32 errorpos;
233};
234
235
236/**
237 * Wrong protocol version.
238 *
239 * This exception is thrown in case of a version conflict, like a
240 * deserialize() method not being able to handle a coding.
241 */
242class IEWrongVersion : public IEError {
243 public:
244 IEWrongVersion(IE::coding_t coding, uint16 category, uint32 pos);
245 virtual ~IEWrongVersion() throw () { }
246
247 const IE::coding_t coding;
248 const uint16 category;
249 const uint32 errorpos;
250};
251
252
253/**
254 * Invalid IE type.
255 *
256 * Typically thrown if deserialize() fails because there is no matching IE
257 * registered with the IEManager.
258 */
259class IEWrongType : public IEError {
260 public:
261 // The first constructor is deprecated!
262 IEWrongType(IE::coding_t coding, uint16 category, uint32 pos);
263 IEWrongType(IE::coding_t coding, uint16 category, uint16 type,
264 uint32 pos);
265 virtual ~IEWrongType() throw () { }
266
267 const IE::coding_t coding;
268 const uint16 category;
269 const uint16 type;
270 const uint32 errorpos;
271};
272
273
274/**
275 * Invalid IE subtype.
276 *
277 * Typically thrown if deserialize() fails because there is no matching IE
278 * registered with the IEManager.
279 */
280class IEWrongSubtype : public IEError {
281 public:
282 // The first constructor is deprecated!
283 IEWrongSubtype(IE::coding_t coding, uint16 category, uint16 type,
284 uint32 pos);
285 IEWrongSubtype(IE::coding_t coding, uint16 category, uint16 type,
286 uint16 subtype, uint32 pos);
287 virtual ~IEWrongSubtype() throw () { }
288
289 const IE::coding_t coding;
290 const uint16 category;
291 const uint16 type;
292 const uint16 subtype;
293 const uint32 errorpos;
294};
295
296
297/**
298 * An invalid length field was read.
299 *
300 * This exception is thrown if a length field inside a NetMsg has a wrong
301 * length (either too long or too short, but makes no sense). Note that
302 * this overlaps with IEMsgTooShort in some cases.
303 */
304class IEWrongLength : public IEError {
305 public:
306 IEWrongLength(IE::coding_t coding, uint16 category, uint16 type,
307 uint16 subtype, uint32 pos);
308 virtual ~IEWrongLength() throw () { }
309
310 const IE::coding_t coding;
311 const uint16 category;
312 const uint16 type;
313 const uint16 subtype;
314 const uint32 errorpos;
315};
316
317
318/**
319 * Some entity is too big for this implementation.
320 *
321 * This exception is thrown if an operation can't be performed because
322 * of some implementation limit.
323 */
324class IETooBigForImpl : public IEError {
325 public:
326 IETooBigForImpl(IE::coding_t coding, uint16 category, uint32 pos);
327 virtual ~IETooBigForImpl() throw () { }
328
329 const IE::coding_t coding;
330 const uint16 category;
331 const uint32 errorpos;
332};
333
334
335/**
336 * Protocol Specific Error
337 *
338 * This exception is thrown if a protocol specific error
339 * occurred.
340 */
341class IEProtocolSpecific : public IEError {
342 public:
343 IEProtocolSpecific(IE::coding_t coding, uint16 category, uint32 pos);
344 virtual ~IEProtocolSpecific() throw () { }
345
346 const IE::coding_t coding;
347 const uint16 category;
348 const uint32 errorpos;
349};
350
351
352/// IE error list
353/** This represents a list of IE errors. */
354class IEErrorList {
355public:
356 /// put an IEError on the list
357 void put(IEError* iee);
358 /// get and remove next IEError
359 IEError* get();
360 /// is list empty
361 bool is_empty() const;
362 /// clear list
363 void clear();
364 /// destructor
365 ~IEErrorList();
366private:
367 /// internal queue type
368 typedef deque<IEError*> queue_t;
369 /// queue iterator type
370 typedef queue_t::iterator queueit_t;
371 /// IEError storage
372 queue_t queue;
373}; // end IEErrorList
374
375
376/**
377 * Represents a (category, type, subtype) tuple.
378 *
379 * Used internally by IEManager.
380 */
381class IE_Key {
382 public:
383 inline IE_Key(uint16 category, uint16 type, uint16 subtype)
384 : category(category), type(type), subtype(subtype) { }
385
386 inline bool operator==(const IE_Key &other) const {
387 return category == other.category && type == other.type
388 && subtype == other.subtype;
389 }
390
391 inline uint16 get_category() const { return category; }
392 inline uint16 get_type() const { return type; }
393 inline uint16 get_subtype() const { return subtype; }
394
395 private:
396 uint16 category;
397 uint16 type;
398 uint16 subtype;
399};
400
401struct hash_IE_Key {
402 inline size_t operator()(const protlib::IE_Key &k) const {
403 return (k.get_category() << 16)
404 | ( k.get_type() ^ k.get_subtype() );
405 }
406};
407
408
409/**
410 * A registry and factory for IEs.
411 *
412 * Each IE has to register at the IE Manager. The IEManager then provides
413 * methods to deserialize IEs from or serialize IEs to a NetMsg object.
414 * IEManager is abstract and thus can't be instantiated.
415 *
416 * In contrast to earlier implementations, IEManager itself is no longer a
417 * singleton. Inheriting from singletons is a tricky business in C++ (and
418 * much easier in Java) because static methods can't be virtual. Because
419 * of this, multiple badly implemented child classes were unable to coexist
420 * in a single program.
421 *
422 * The following has to be done in each protocol to use IEManager and
423 * create a protocol-specific singleton (called PROT_IEManager):
424 *
425 * - Inherit from IEManager.
426 * - Make the constructor private.
427 * - Provide a "private: static PROT_IEManager *inst" attribute.
428 * - Provide a "public: static PROT_IEManager *instance()" method.
429 * - Provide a "public: static void clear()" method.
430 * - Define your own category_t with categories appropriate for your protocol.
431 *
432 * An example implementation can be found in the QSPEC code. Please note that
433 * old code (r286 and earlier) won't compile because of interface changes.
434 * The ability to register "default" IEs that are returned if no more specific
435 * IE is found has been removed because it depended on coding_t. If derived
436 * IEManagers need this functionality, they have to override lookup_ie().
437 *
438 */
439class IEManager {
440
441 public:
442 virtual ~IEManager();
443
444 virtual void register_ie(const IE *ie);
445 virtual void register_ie(uint16 category, uint16 type, uint16 subtype,
446 const IE *ie);
447
448 virtual IE *new_instance(uint16 category, uint16 type, uint16 subtype);
449
450 virtual void serialize(IE &ie, NetMsg &msg, IE::coding_t coding,
451 uint32 &bytes_written) const;
452
453 virtual IE *deserialize(NetMsg &msg, uint16 category,
454 IE::coding_t coding, IEErrorList& errorlist,
455 uint32 &bytes_read, bool skip = true) = 0;
456
457 protected:
458 IEManager();
459
460 virtual IE *lookup_ie(uint16 category, uint16 type, uint16 subtype);
461
462 virtual void throw_nomem_error() const;
463
464 private:
465 typedef hash_map<IE_Key, IE *, hash_IE_Key> category_map_t;
466
467 category_map_t registry;
468};
469
470
471/** This mainly calls the serialize member function of the given IE.
472 * @param ie pointer to an IE
473 * @param msg NetMsg object that will hold the serialized IE.
474 * @param coding IE coding sheme
475 * @param wbytes number of output bytes
476 */
477inline
478void IEManager::serialize(IE& ie, NetMsg& msg, IE::coding_t coding, uint32& wbytes) const {
479 ie.serialize(msg,coding,wbytes);
480} // end serialize
481
482
483/// print an IE to an ostream
484ostream& operator<<(ostream& os, const IE& ie);
485
486/// input operator
487istream& operator>>(istream& is, IE& ie);
488
489/// round uint32 up
490/** Adds up the given uint32 to fit a 32-bit or 4-byte border. */
491inline uint32 round_up4(uint32 i) {
492 if (i%4) i = i-(i%4)+4;
493 return i;
494} // end round_up4
495
496//@}
497
498} // end namespace protlib
499
500#endif // _PROTLIB__IE_H_
Note: See TracBrowser for help on using the repository browser.