source: source/ariba/utility/transport/tcpip/protlib/ie.h@ 9633

Last change on this file since 9633 was 6922, checked in by mies, 15 years ago

replaced deprecated hash_map, hash_set classes with boost
added unsigned serialization
fixed more warnings
included -Wall to Makefile.am

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