An Overlay-based
Virtual Network Substrate
SpoVNet

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

Last change on this file since 5641 was 5641, checked in by Christoph Mayer, 14 years ago
File size: 18.2 KB
Line 
1/// ----------------------------------------*- mode: C++; -*--
2/// @file ie.cpp
3/// information elements for the protocol, IE manager singleton
4/// ----------------------------------------------------------
5/// $Id: ie.cpp 2549 2007-04-02 22:17:37Z bless $
6/// $HeadURL: https://svn.ipv6.tm.uka.de/nsis/protlib/trunk/src/ie.cpp $
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 * This file defines the base class of all information elements, the
32 * information elements for the GIST protocol and an IE manager singleton
33 * object.
34 * Although the IEs are closely related to the structure of GIST messages,
35 * they may be used in other contexts as well because of the coding shemes.
36 */
37
38#include "ie.h"
39#include "logfile.h"
40
41#include <unistd.h>
42#include <stdio.h>
43#include <string.h>
44#include <sstream>
45#include <iomanip>
46
47namespace protlib {
48  using namespace log;
49
50
51
52/** @addtogroup ie Information Elements
53 * @{
54 */
55
56/***** class IE *****/
57
58/** Constructor. Sets category of IE. */
59IE::IE(uint16 category) : category(category) {}
60
61IE::IE(const IE& n) : category(n.category) {}
62
63/** Get the category of the IE. */
64uint16 IE::get_category() const {
65        return category;
66} // end get_category
67
68/** Check arguments of IE deserialization member functions.
69 * Additionally, bread is set to 0.
70 */ 
71bool IE::check_deser_args(coding_t cod, IEErrorList& errorlist, uint32 &bread) const {
72        bread = 0;
73        // check coding
74        if (!supports_coding(cod)) {
75          Log(ERROR_LOG,LOG_NORMAL, "IE", "IE::check_deser_args(): IE " << get_ie_name() << " does not support coding " << cod );
76          catch_bad_alloc(errorlist.put(new IEError(IEError::ERROR_CODING)));
77          return false;
78        } // end if cod
79        return true;
80} // end check_deser_args()
81
82/** Check arguments of IE serialization member functions.
83 * Additionally, wbytes is set to 0.
84 */ 
85void IE::check_ser_args(coding_t cod, uint32 &wbytes) const {
86        wbytes = 0;
87        // check IE state
88        if (!check()) {
89                IEError err(IEError::ERROR_INVALID_STATE);
90                Log(ERROR_LOG,LOG_NORMAL, "IE", "IE::check_ser_args() for IE " << get_ie_name() << ", error: " << err.getstr());
91                throw err;
92        } // end if !check()
93        // check coding
94        if (!supports_coding(cod)) {
95                IEError err(IEError::ERROR_CODING);
96                Log(ERROR_LOG,LOG_NORMAL, "IE", "IE::check_ser_args() for IE " << get_ie_name() << ", error: " << err.getstr() << ", coding: " << cod);
97                throw err;
98        } // end if cod
99        return;
100} // end check_ser_args()
101
102
103/** Print the content of the IE, default behaviour is to print its name.
104 * Level and indent control how much space is inserted after a newline.
105 * If name points to a string, this string is printed before the
106* get_ie_name().
107 */
108ostream& IE::print(ostream& os, uint32 level, const uint32 indent, const char* name) const {
109        os<<setw(level*indent)<<"";
110        if (name && (*name!=0)) os<<name<<" ";
111        os<<"<"<<get_ie_name()<<">";
112        return os;
113} // end print
114
115istream& IE::input(istream& is, bool istty, uint32 level, const uint32 indent, const char* name) {
116  Log(ERROR_LOG,LOG_NORMAL, "IE", "IE " << get_ie_name() << "::input not yet implemented");
117  if (istty) {
118    cout<<setw(level*indent)<<"";
119    if (name && (*name!=0)) cout<<name<<" ";
120    cout<<"<"<<get_ie_name()<<">: Input not yet implemented."<<endl;
121  } // end if istty
122  return is;
123} // end input
124
125/** Print the IE to a string using print() and stringstream. */
126string IE::to_string(const char* name) const {
127        ostringstream os;
128        print(os,0,3,name);
129        return os.str();
130} // end to_string
131
132/** Log and throw a nomem_error */
133void IE::throw_nomem_error() const {
134        try {
135          Log(ERROR_LOG,LOG_CRIT, "IE", "Not enough memory for IE " << get_ie_name());
136        } catch(...) {}
137        throw IEError(IEError::ERROR_NO_MEM);
138} // end throw_nomem_error
139
140/** Set all pointers to external data to NULL.
141 * By default this does nothing because there are no pointers.
142 */
143void IE::clear_pointers() {}
144
145
146/***** class IEError *****/
147
148/// IEError strings
149const char* IEError::err_str[] = {
150        "Error while registering IE. Either pointer to IE is NULL or registered IE already.",
151        "IE coding scheme is not supported by this function.",
152        "IE category is not supported by this function or in the applied coding scheme.",
153        "IE Manager instance does not exist (possible mem alloc problem?)",
154        "NetMsg too short for (de)serialization.",
155        "IE is in invalid state.",
156        "Wrong/unexpected IE type.",
157        "Wrong/unexpected IE subtype.",
158        "Wrong IE length.",
159        "Not enough memory to allocate IE.",
160        "Too big for this protocol implementation.",
161        "Unknown error code for this error class.",
162        "Wrong or unknown protocol version.",
163        "Unexpected object",
164        "PDU syntax error",
165        "PDU Object set failed (wrong index)",
166        "Protocol Specific Error"
167};
168
169
170/**
171 * Constructor.
172 *
173 * Initialize an IEError object by setting the error code.
174 *
175 * @warning Don't instantiate IEError. Use a child class instead!
176 *
177 * @param error the kind of error this exception represents
178 */
179IEError::IEError(error_t error) : ProtLibException(err_str[error]), err(error) {
180        // nothing to do
181}
182
183
184IEError::IEError(std::string msg) throw ()
185                : ProtLibException(msg), err(ERROR_UNKNOWN_ERRORCODE) {
186
187        // nothing to do
188}
189
190
191/**
192 * Destructor.
193 *
194 * This has only been defined to prevent compiler warnings.
195 */
196IEError::~IEError() throw () {
197        // nothing to do
198}
199
200
201/**
202 * Returns an error message.
203 *
204 * Note: what() returns more useful messages.
205 *
206 * @return the error message
207 */
208const char* IEError::getstr() const {
209        return err_str[err];
210}
211
212
213/***** class PDUSyntaxError *****/
214
215/**
216 * Constructor.
217 *
218 * @deprecated This constructor shouldn't be used for new code.
219 *
220 * @param msg an error message describing the problem
221 */
222PDUSyntaxError::PDUSyntaxError(const char* msg)
223                : IEError(IEError::ERROR_PDU_SYNTAX),
224                  coding(coding), category(0), type(0), subtype(0),
225                  errorpos(0), message(msg) {
226
227        ostringstream ost;
228        ost << "[coding " << coding << ", cat " << category << ", type " << type
229                << ", subtype " << subtype << "] " << message;
230
231        error_msg = ost.str();
232}
233
234
235/**
236 * Constructor.
237 *
238 * @param coding the protocol version
239 * @param category the IE's category
240 * @param type the IE's type
241 * @param subtype the IE's subtype
242 * @param pos the position in the NetMsg at which the problem was discovered
243 * @param msg a message describing the problem
244 */
245PDUSyntaxError::PDUSyntaxError(IE::coding_t coding, uint16 category,
246                uint16 type, uint16 subtype, uint32 pos, const char *msg)
247                : IEError(IEError::ERROR_PDU_SYNTAX),
248                  coding(coding), category(category), type(type),
249                  subtype(subtype), errorpos(pos), message(msg) {
250
251        ostringstream ost;
252        ost << "[coding " << coding << ", cat " << category << ", type " << type
253                << ", subtype " << subtype << "] " << message;
254
255        error_msg = ost.str();
256}
257
258
259/***** class IEMsgTooShort *****/
260
261/**
262 * Constructor.
263 *
264 * @param coding the protocol version
265 * @param category the IE's category
266 * @param pos the position in the NetMsg at which the problem was discovered
267 */
268IEMsgTooShort::IEMsgTooShort(IE::coding_t coding, uint16 category, uint32 pos) 
269                : IEError(ERROR_MSG_TOO_SHORT),
270                  coding(coding), category(category), errorpos(pos) {
271
272        ostringstream ost;
273        ost << "[coding " << coding << ", cat " << category
274                << ", pos" << errorpos << IEError::getstr();
275
276        error_msg = ost.str();
277}
278
279
280/***** class IEWrongVersion *****/
281
282/**
283 * Constructor.
284 *
285 * @param coding the protocol version
286 * @param category the IE's category
287 * @param pos the position in the NetMsg at which the problem was discovered
288 */
289IEWrongVersion::IEWrongVersion(IE::coding_t coding, uint16 category, uint32 pos)
290                : IEError(ERROR_WRONG_VERSION),
291                  coding(coding), category(category), errorpos(pos) {
292
293        ostringstream ost;
294        ost << "[coding " << coding << ", cat " << category
295                << ", pos" << errorpos << IEError::getstr();
296
297        error_msg = ost.str();
298}
299
300
301/***** class IEWrongType *****/
302
303/**
304 * Constructor.
305 *
306 * @deprecated This constructor should not be used for new code.
307 *
308 * @param coding the protocol version
309 * @param category the IE's category
310 * @param pos the position in the NetMsg at which the problem was discovered
311 */
312IEWrongType::IEWrongType(IE::coding_t coding, uint16 category, uint32 pos) 
313                : IEError(ERROR_WRONG_TYPE), coding(coding),
314                  category(category), type(0), errorpos(pos) {
315
316        ostringstream ost;
317        ost << "[coding " << coding << ", cat " << category << ", type " << type
318                << ", pos" << errorpos << IEError::getstr();
319
320        error_msg = ost.str();
321}
322
323
324/**
325 * Constructor.
326 *
327 * @param coding the protocol version
328 * @param category the IE's category
329 * @param type the IE's type
330 * @param pos the position in the NetMsg at which the problem was discovered
331 */
332IEWrongType::IEWrongType(IE::coding_t coding, uint16 category, uint16 type,
333                uint32 pos) 
334                : IEError(ERROR_WRONG_TYPE), coding(coding),
335                  category(category), type(type), errorpos(pos) {
336
337        ostringstream ost;
338        ost << "[coding " << coding << ", cat " << category << ", type " << type
339                << ", pos" << errorpos << IEError::getstr();
340
341        error_msg = ost.str();
342}
343
344
345/***** class IEWrongSubtype *****/
346
347/**
348 * Constructor.
349 *
350 * @deprecated This constructor should not be used for new code.
351 *
352 * @param coding the protocol version
353 * @param category the IE's category
354 * @param type the IE's type
355 * @param pos the position in the NetMsg at which the problem was discovered
356 */
357IEWrongSubtype::IEWrongSubtype(IE::coding_t coding, uint16 category,
358                uint16 type, uint32 pos) 
359                : IEError(ERROR_WRONG_SUBTYPE), coding(coding),
360                  category(category), type(type), subtype(0), errorpos(pos) {
361
362        ostringstream ost;
363        ost << "[coding " << coding << ", cat " << category << ", type " << type
364                << ", subtype " << subtype << ", pos" << errorpos
365                << IEError::getstr();
366
367        error_msg = ost.str();
368}
369
370
371/**
372 * Constructor.
373 *
374 * @param coding the protocol version
375 * @param category the IE's category
376 * @param type the IE's type
377 * @param subtype the IE's subtype
378 * @param pos the position in the NetMsg at which the problem was discovered
379 */
380IEWrongSubtype::IEWrongSubtype(IE::coding_t coding, uint16 category,
381                uint16 type, uint16 subtype, uint32 pos) 
382                : IEError(ERROR_WRONG_SUBTYPE),
383                  coding(coding), category(category), type(type),
384                  subtype(subtype), errorpos(pos) {
385
386        ostringstream ost;
387        ost << "[coding " << coding << ", cat " << category << ", type " << type
388                << ", subtype " << subtype << ", pos" << errorpos
389                << IEError::getstr();
390
391        error_msg = ost.str();
392}
393
394
395/***** class IEWrongLength *****/
396
397/**
398 * Constructor.
399 *
400 * The category, type and subtype parameters refer to the IE throwing the
401 * exception.
402 *
403 * @param coding the protocol version
404 * @param category the IE's category
405 * @param type the IE's type
406 * @param subtype the IE's subtype
407 * @param pos the position in the NetMsg at which the problem was discovered
408 */
409IEWrongLength::IEWrongLength(IE::coding_t coding, uint16 category, uint16 type,
410                uint16 subtype, uint32 pos) 
411                : IEError(ERROR_WRONG_LENGTH),
412                  coding(coding), category(category), type(type),
413                  subtype(subtype), errorpos(pos) {
414
415        ostringstream ost;
416        ost << "[coding " << coding << ", cat " << category << ", type " << type
417                << ", subtype " << subtype << ", pos" << errorpos
418                << IEError::getstr();
419
420        error_msg = ost.str();
421}
422
423
424/***** class IETooBigForImpl *****/
425
426/**
427 * Constructor.
428 *
429 * @param coding the protocol version
430 * @param category the IE's category
431 * @param pos the position in the NetMsg at which the problem was discovered
432 */
433IETooBigForImpl::IETooBigForImpl(IE::coding_t coding, uint16 category,
434                uint32 pos) 
435                : IEError(ERROR_TOO_BIG_FOR_IMPL),
436                  coding(coding), category(category), errorpos(pos) {
437
438        ostringstream ost;
439        ost << "[coding " << coding << ", cat " << category
440                << ", pos" << errorpos << IEError::getstr();
441
442        error_msg = ost.str();
443}
444
445
446/***** class IEProtocol *****/
447
448/**
449 * Constructor.
450 *
451 * @param coding the protocol version
452 * @param category the IE's category
453 * @param pos the position in the NetMsg at which the problem was discovered
454 */
455IEProtocolSpecific::IEProtocolSpecific(IE::coding_t coding, uint16 category,
456                uint32 pos) 
457                : IEError(ERROR_PROT_SPECIFIC),
458                  coding(coding), category(category), errorpos(pos) {
459
460        ostringstream ost;
461        ost << "[coding " << coding << ", cat " << category
462                << ", pos" << errorpos << IEError::getstr();
463
464        error_msg = ost.str();
465}
466
467
468/***** class IEErrorList *****/
469
470/** Insert IE Error into list. */
471void IEErrorList::put(IEError* iee) {
472        if (iee) queue.push_front(iee);
473} // end put
474
475/** Get and remove IE Error from the list.
476 * Returns NULL if list is empty.
477 */
478IEError* IEErrorList::get() {
479        register IEError* iee;
480        if (queue.empty()) return NULL;
481        else {
482                iee = queue.back();
483                queue.pop_back();
484                return iee;
485        } // end if
486} // end get
487
488/** Is the IE error list empty? */
489bool IEErrorList::is_empty() const {
490        return queue.empty();
491} // end is_empty
492
493/** clear IE error list and destroy all stored IE error objects. */
494void IEErrorList::clear() {
495        queueit_t qit;
496        // delete IEError objects in queue
497        for (qit=queue.begin();qit!=queue.end();++qit)
498                if (*qit) delete *qit;
499        // clear queue
500        queue.clear();         
501} // end clear
502
503/** Destroy IEError list and all IEError objects in it. */
504IEErrorList::~IEErrorList() {
505        if (!queue.empty()) {
506          Log(DEBUG_LOG,LOG_CRIT, "IE", "Destroying non-empty IEErrorList, deleting IEError objects.");
507          clear();
508        } // end if not empty
509} // end ~IEErrorList
510
511
512/***** class IEManager *****/
513
514
515/**
516 * Constructor.
517 */
518IEManager::IEManager() {
519        // nothing to do
520}
521
522
523/**
524 * Destructor.
525 *
526 * All registered IEs are deleted.
527 */
528IEManager::~IEManager() {
529        // iterator shortcuts
530        typedef category_map_t::const_iterator c_iter;
531
532        /*
533         * Walk through all registered IEs and delete them.
534         */
535        int num_deleted = 0;
536
537        for (c_iter i = registry.begin(); i != registry.end(); i++) {
538                IE *ie = i->second;
539
540                if ( ie != NULL ) {
541                        delete ie;
542                        num_deleted++;
543                }
544        }
545
546        DLog("IEManager", "Deleted " << num_deleted << " IEs");
547}
548
549
550/**
551 * Register an Information Element.
552 *
553 * Make the IE object passed as the argument register itself with this
554 * IEManager. See IE's register_ie() method for the rules.
555 *
556 * This method exists for convenience only, please see the other register_ie()
557 * method for details.
558 *
559 * @param ie pointer to IE (NULL is not allowed)
560 */
561void IEManager::register_ie(const IE* ie) {
562        if ( ie == NULL )
563                throw IEError(IEError::ERROR_REGISTER);
564
565        return ie->register_ie(this);
566}
567
568
569/**
570 * Register an Information Element.
571 *
572 * Register an IE for the given category, type and subtype. It is not allowed
573 * to register more than one IE for a (category, type, subtype) triple.
574 *
575 * It is @em very important that each IE instance is registered only once.
576 * If a class can handle multiple (category, type, subtype) triples, one
577 * instance per triple has to be registered.
578 *
579 * There is no way to unregister an IE. All registered IEs will be deleted
580 * by IEManager's destructor.
581 *
582 * @param category category of the IE
583 * @param type IE type
584 * @param subtype IE subtype
585 * @param ie the IE to register (NULL is not allowed)
586 */
587void IEManager::register_ie(uint16 category, uint16 type, uint16 subtype,
588                const IE* ie) {
589
590        // for logging
591        ostringstream triple;
592        triple << "(" << category << ", " << type << ", " << subtype << ")";
593
594        if ( ie == NULL )
595                throw IEError(IEError::ERROR_REGISTER);
596
597        IE_Key key(category, type, subtype);
598
599        // don't allow overwriting
600        if ( registry[key] != NULL ) {
601                ERRLog("IEManager",
602                        "An IE is already " << "registered for " << triple);
603                return;
604        }
605
606
607        try {
608                registry[key] = const_cast<IE *>(ie);
609        }
610        catch ( ... ) {
611                ERRLog("IEManager", "Cannot register IE for " << triple);
612
613                throw IEError(IEError::ERROR_REGISTER);
614        }
615
616        // We made it so far, this means success.
617        DLog("IEManager",
618                "Registered IE " << ie->get_ie_name() << " for " << triple);
619}
620
621
622/**
623 * Create a new instance.
624 *
625 * Creates a new instance using the appropriate registered IE. The definition
626 * of @em appropriate depends on lookup_ie().
627 *
628 * Note that some old IEManager child classes called this method lookup().
629 * This old lookup() method should not be confused with lookup_ie().
630 *
631 * @param category category of the IE
632 * @param type IE type
633 * @param subtype IE subtype
634 * @return a new instance, or NULL if no matching IE is found
635 */
636IE *IEManager::new_instance(uint16 category, uint16 type, uint16 subtype) {
637        IE *ie = lookup_ie(category, type, subtype);
638
639        if ( ie )
640                return ie->copy();
641        else
642                return NULL;
643}
644
645
646/**
647 * Return a registered IE.
648 *
649 * Returns a registered IE instance. It does @em not create a new instance,
650 * it is really an instance you registered earlier. Use new_instance() if
651 * you need new instances!
652 *
653 * This method is an extension point that can be used, for example, to return
654 * "default" IEs if no matching IE is found in the registry.
655 *
656 * @param category category of the IE
657 * @param type IE type
658 * @param subtype IE subtype
659 * @return a registered instance, or NULL if no matching IE is found
660 */
661IE *IEManager::lookup_ie(uint16 category, uint16 type, uint16 subtype) {
662        return registry[IE_Key(category, type, subtype)];
663}
664
665
666/**
667 * Throw an exception and log it.
668 */
669void IEManager::throw_nomem_error() const {
670        try {
671                ERRLog("IEManager", "Out of memory.");
672        }
673        catch ( ... ) {
674                // There's no way to handle this!
675        }
676
677        throw IEError(IEError::ERROR_NO_MEM);
678}
679
680
681/***** operator<< and >> *****/
682
683/** Print the given IE to the ostream using level=0 and indent=3. */
684ostream& operator<<(ostream& os, const IE& ie) {
685        ie.print(os,0,3);
686        return os;
687} // end operator<<
688
689istream& operator>>(istream& is, IE& ie) {
690        ie.input(is,isatty(0),0,3);
691        return is;
692} // end operator>>
693
694//@}
695
696} // end namespace protlib
Note: See TracBrowser for help on using the repository browser.