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

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