An Overlay-based
Virtual Network Substrate
SpoVNet

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

Last change on this file since 5641 was 5641, checked in by Christoph Mayer, 14 years ago
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 <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.