Remove dynamic exceptions
[anna.git] / source / diameter / stack / Dictionary.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 // Local
10 #include <anna/diameter/stack/Dictionary.hpp>
11 #include <anna/diameter/stack/Engine.hpp>
12
13 #include <anna/config/defines.hpp>
14 #include <anna/core/tracing/Logger.hpp>
15 #include <anna/xml/xml.hpp>
16 #include <anna/core/functions.hpp>
17
18 #include <anna/config/defines.hpp>
19 #include <anna/core/functions.hpp>
20 #include <anna/diameter/codec/Format.hpp>
21
22 // STL
23 #include <string>
24
25
26 using namespace anna::diameter::stack;
27 using namespace anna;
28
29
30 //------------------------------------------------------------------------------
31 //---------------------------------------------------------------------- #define
32 //------------------------------------------------------------------------------
33 #define ITEM_OVERWRITE(item_n,item,pool,poolNames)\
34 LOGNOTICE(\
35    std::string trace = "\n   Updated ";\
36    trace += item_n;\
37    trace += ":\n";\
38    trace += anna::functions::tab(found->asString(), 6);\
39    trace += "\n   New content:\n";\
40    trace += anna::functions::tab(item.asString(), 6);\
41    trace += "\n";\
42    anna::Logger::notice(trace, ANNA_FILE_LOCATION);\
43 );\
44 std::string name = found->getName();\
45 pool.erase(pool.find(found->getId()));\
46 poolNames.erase(poolNames.find(name));
47
48
49 //------------------------------------------------------------------------------
50 //----------------------------------------------------- Dictionary::Dictionary()
51 //------------------------------------------------------------------------------
52 Dictionary::Dictionary(void) {
53   a_dtd = (Engine::instantiate()).getDictionariesDTD();
54   a_allowUpdates = false;
55   initialize();
56 }
57
58 //------------------------------------------------------------------------------
59 //----------------------------------------------------- Dictionary::initialize()
60 //------------------------------------------------------------------------------
61 void Dictionary::initialize() {
62   a_formats.clear();
63   a_vendors.clear();
64   a_avps.clear();
65   a_commands.clear();
66   a_vendorNames.clear();
67   a_avpNames.clear();
68   a_commandNames.clear();
69   a_dtd = (Engine::instantiate()).getDictionariesDTD();
70   // RFC3588 Diameter Formats harcoding:
71   // Basic diameter types
72   Format OctetString(this), Integer32(this), Integer64(this), Unsigned32(this), Unsigned64(this), Float32(this), Float64(this), Grouped(this);
73   OctetString.setRFC3588(codec::Format::OctetString);
74   Integer32.setRFC3588(codec::Format::Integer32);
75   Integer64.setRFC3588(codec::Format::Integer64);
76   Unsigned32.setRFC3588(codec::Format::Unsigned32);
77   Unsigned64.setRFC3588(codec::Format::Unsigned64);
78   Float32.setRFC3588(codec::Format::Float32);
79   Float64.setRFC3588(codec::Format::Float64);
80   Grouped.setRFC3588(codec::Format::Grouped);
81   addFormat(OctetString);
82   addFormat(Integer32);
83   addFormat(Integer64);
84   addFormat(Unsigned32);
85   addFormat(Unsigned64);
86   addFormat(Float32);
87   addFormat(Float64);
88   addFormat(Grouped);
89   // Derived diameter types
90   Format Address(this), Time(this), UTF8String(this), DiameterIdentity(this), DiameterURI(this), Enumerated(this), IPFilterRule(this), QoSFilterRule(this);
91   Address.setRFC3588(codec::Format::Address);                     Address.setParentName(OctetString.getName());
92   Time.setRFC3588(codec::Format::Time);                           Time.setParentName(OctetString.getName());
93   UTF8String.setRFC3588(codec::Format::UTF8String);               UTF8String.setParentName(OctetString.getName());
94   DiameterIdentity.setRFC3588(codec::Format::DiameterIdentity);   DiameterIdentity.setParentName(OctetString.getName());
95   DiameterURI.setRFC3588(codec::Format::DiameterURI);             DiameterURI.setParentName(OctetString.getName());
96   Enumerated.setRFC3588(codec::Format::Enumerated);               Enumerated.setParentName(Integer32.getName());
97   IPFilterRule.setRFC3588(codec::Format::IPFilterRule);           IPFilterRule.setParentName(OctetString.getName());
98   QoSFilterRule.setRFC3588(codec::Format::QoSFilterRule);         QoSFilterRule.setParentName(OctetString.getName());
99   addFormat(Address);
100   addFormat(Time);
101   addFormat(UTF8String);
102   addFormat(DiameterIdentity);
103   addFormat(DiameterURI);
104   addFormat(Enumerated);
105   addFormat(IPFilterRule);
106   addFormat(QoSFilterRule);
107   // Generic AVP hardcoding:
108   Avp genericAvp(this);
109   genericAvp.setCode(0);
110   genericAvp.setVendorId(0/*Vendor::Code::Ietf*/);
111   genericAvp.setName("AVP");
112   Format Any(this);
113   Any.setRFC3588(codec::Format::Any);
114   addFormat(Any, true /*reserved*/);
115   genericAvp.setFormatName(Any.getName());
116   genericAvp.setVbit(Avp::FlagRule::mustnot);
117   genericAvp.setMbit(Avp::FlagRule::may);
118   genericAvp.setPbit(Avp::FlagRule::may);
119   genericAvp.setMayEncrypt(false);
120   addAvp(genericAvp);
121 }
122
123
124 //------------------------------------------------------------------------------
125 //------------------------------------------------------ Dictionary::addFormat()
126 //------------------------------------------------------------------------------
127 void Dictionary::addFormat(const Format & format, bool reserved) noexcept(false) {
128   if(!reserved && format.isReserved()) {
129     std::string s_ex = anna::functions::asString("Format type '%s' is reserved for internal use", format.getName().c_str());
130     throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
131   }
132
133   const Format * found = getFormat(format.getName());
134   if(found) {
135     if(!a_allowUpdates) {
136       std::string s_ex = "Cannot add a format with an existing type name: ";
137       //s_ex += format.getName();
138       s_ex += format.asString();
139       s_ex += "'";
140       throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
141     }
142
143     LOGNOTICE(
144       std::string trace = "\n   Updated format:\n";
145       trace += anna::functions::tab(found->asString(), 6);
146       trace += "\n   New content:\n";
147       trace += anna::functions::tab(format.asString(), 6);
148       trace += "\n";
149       anna::Logger::notice(trace, ANNA_FILE_LOCATION);
150     );
151   }
152
153   a_formats[format.getName()] = format;
154 }
155
156
157 //------------------------------------------------------------------------------
158 //------------------------------------------------------ Dictionary::addVendor()
159 //------------------------------------------------------------------------------
160 void Dictionary::addVendor(const Vendor & vendor) noexcept(false) {
161
162   const Vendor * found = getVendor(vendor.getId());
163   if(found) {
164     if(!a_allowUpdates) {
165       std::string s_ex = "Cannot add a vendor with an existing code: ";
166       s_ex += vendor.asString();
167       throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
168     }
169
170     ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
171   }
172
173   found = getVendor(vendor.getName());
174   if(found) {
175     if(!a_allowUpdates) {
176       std::string s_ex = "Cannot add a vendor with an existing name: ";
177       s_ex += vendor.asString();
178       throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
179     }
180
181     ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
182   }
183
184   a_vendors[vendor.getId()] = vendor;
185   a_vendorNames[vendor.getName()] = getVendor(vendor.getId());
186 }
187
188
189 //------------------------------------------------------------------------------
190 //--------------------------------------------------------- Dictionary::addAvp()
191 //------------------------------------------------------------------------------
192 void Dictionary::addAvp(const Avp & avp) noexcept(false) {
193
194   const Avp * found = getAvp(avp.getId());
195   if (found) {
196     if(!a_allowUpdates) {
197       std::string s_ex = "Cannot add an avp with an existing identifier (code,vendor):\n";
198       s_ex += avp.asString();
199       throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
200     }
201
202     ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
203   }
204
205   if((found = getAvp(avp.getName()))) {
206     if(!a_allowUpdates) {
207       std::string s_ex = "Cannot add an avp with an existing name:\n";
208       s_ex += avp.asString();
209       throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
210     }
211
212     ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
213   }
214
215   a_avps[avp.getId()] = avp;
216   a_avpNames[avp.getName()] = getAvp(avp.getId());
217 }
218
219
220 //------------------------------------------------------------------------------
221 //----------------------------------------------------- Dictionary::addCommand()
222 //------------------------------------------------------------------------------
223 void Dictionary::addCommand(const Command & command) noexcept(false) {
224   
225   const Command * found = getCommand(command.getId());
226   if(found) {
227     if(!a_allowUpdates) {
228       std::string s_ex = "Cannot add a command with an existing identifier:\n";
229       s_ex += command.asString();
230       throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
231     }
232
233     ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
234   }
235
236   
237   found = getCommand(command.getName());
238   if(found) {
239     if(!a_allowUpdates) {
240       std::string s_ex = "Cannot add a command with an existing name:\n";
241       s_ex += command.asString();
242       throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
243     }
244
245     ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
246   }
247
248   a_commands[command.getId()] = command;
249   a_commandNames[command.getName()] = getCommand(command.getId());
250 }
251
252
253 // public
254
255 //------------------------------------------------------------------------------
256 //------------------------------------------------------ Dictionary::getFormat()
257 //------------------------------------------------------------------------------
258 const Format * Dictionary::getFormat(const std::string & formatName) const {
259   const_format_iterator it = a_formats.find(formatName);
260
261   if(it != format_end()) return ((const Format *) & ((*it).second));
262
263   return (NULL);
264 }
265
266
267 //------------------------------------------------------------------------------
268 //------------------------------------------------------ Dictionary::getVendor()
269 //------------------------------------------------------------------------------
270 const Vendor * Dictionary::getVendor(S32 vendorId) const {
271   const_vendor_iterator it = a_vendors.find(vendorId);
272
273   if(it != vendor_end()) return ((const Vendor *) & ((*it).second));
274
275   return (NULL);
276 }
277
278
279 //------------------------------------------------------------------------------
280 //------------------------------------------------------ Dictionary::getVendor()
281 //------------------------------------------------------------------------------
282 const Vendor * Dictionary::getVendor(const std::string & vendorName) const {
283   const_vendorNames_iterator v_it = a_vendorNames.find(vendorName);
284
285   if(v_it != a_vendorNames.end()) return ((*v_it).second);
286
287   return (NULL);
288 }
289
290
291 //------------------------------------------------------------------------------
292 //--------------------------------------------------------- Dictionary::getAvp()
293 //------------------------------------------------------------------------------
294 const Avp * Dictionary::getAvp(const AvpId & avpId) const {
295   const_avp_iterator it = a_avps.find(avpId);
296
297   if(it != avp_end()) return ((const Avp *) & ((*it).second));
298
299   return (NULL);
300 }
301
302
303 //------------------------------------------------------------------------------
304 //--------------------------------------------------------- Dictionary::getAvp()
305 //------------------------------------------------------------------------------
306 const Avp * Dictionary::getAvp(const std::string & avpName) const {
307   const_avpNames_iterator a_it = a_avpNames.find(avpName);
308
309   if(a_it != a_avpNames.end()) return ((*a_it).second);
310
311   return (NULL);
312 }
313
314
315 //------------------------------------------------------------------------------
316 //----------------------------------------------------- Dictionary::getCommand()
317 //------------------------------------------------------------------------------
318 const Command * Dictionary::getCommand(const CommandId & commandId) const {
319   const_command_iterator it = a_commands.find(commandId);
320
321   if(it != command_end()) return ((const Command *) & ((*it).second));
322
323   return (NULL);
324 }
325
326
327 //------------------------------------------------------------------------------
328 //----------------------------------------------------- Dictionary::getCommand()
329 //------------------------------------------------------------------------------
330 const Command * Dictionary::getCommand(const std::string & commandName) const {
331   const_commandNames_iterator c_it = a_commandNames.find(commandName);
332
333   if(c_it != a_commandNames.end()) return ((*c_it).second);
334
335   return (NULL);
336 }
337
338
339 //------------------------------------------------------------------------------
340 //------------------------------------------------------- Dictionary::asString()
341 //------------------------------------------------------------------------------
342 std::string Dictionary::asString(void) const {
343   std::string trace, title;
344   trace += "\n";
345   anna::functions::TextHighlightMode::_v thm = anna::functions::TextHighlightMode::LeftAndRightline;
346   trace += anna::functions::highlight("Name", thm);
347   trace += a_name; trace += "\n";
348   const_format_iterator f_it;
349   const_vendor_iterator v_it;
350   const_avp_iterator a_it;
351   const_command_iterator c_it;
352   trace += "\n";
353   // Formats
354   title = "Formats";
355   //title = "Formats (";
356   //title += anna::functions::entriesAsString(format_size());
357   //title += ")";
358   trace += anna::functions::highlight(title, thm);
359
360   for(f_it = format_begin(); f_it != format_end(); f_it++) {
361     if((*f_it).second.isReserved()) continue;
362
363     if((*f_it).second.isRFC3588())
364       trace += "(Diameter RFC-3588 type)    ";
365     else
366       trace += "(Application-specific type) ";
367
368     trace += (*f_it).second.asString();
369     trace += "\n";
370   }
371
372   trace += "\n";
373   // Vendors
374   title = "Vendors (";
375   title += anna::functions::entriesAsString(vendor_size());
376   title += ")";
377   trace += anna::functions::highlight(title, thm);
378
379   for(v_it = vendor_begin(); v_it != vendor_end(); v_it++) {
380     trace += (*v_it).second.asString();
381     trace += "\n";
382   }
383
384   trace += "\n";
385   // Avps
386   title = "Avps (";
387   title += anna::functions::entriesAsString(avp_size());
388   title += ")";
389   trace += anna::functions::highlight(title, thm);
390
391   for(a_it = avp_begin(); a_it != avp_end(); a_it++) {
392     trace += (*a_it).second.asString();
393     trace += "\n";
394   }
395
396   trace += "\n";
397   // Commands
398   title = "Commands (";
399   title += anna::functions::entriesAsString(command_size());
400   title += ")";
401   trace += anna::functions::highlight(title, thm);
402
403   for(c_it = command_begin(); c_it != command_end(); c_it++) {
404     trace += (*c_it).second.asString();
405     trace += "\n";
406   }
407
408   trace += "\n";
409   return (trace);
410 }
411
412
413 //------------------------------------------------------------------------------
414 //---------------------------------------------------------- Dictionary::asXML()
415 //------------------------------------------------------------------------------
416 anna::xml::Node* Dictionary::asXML(anna::xml::Node* parent) const {
417 //   <!ELEMENT dictionary (format*, vendor*, avp*, command*)>
418 //   <!ATTLIST dictionary name CDATA #REQUIRED>
419   anna::xml::Node* result = parent->createChild("dictionary");
420   result->createAttribute("name", a_name);
421
422   // Formats
423   for(const_format_iterator it = format_begin(); it != format_end(); it++) {
424     if((*it).second.isReserved()) continue;
425
426     if((*it).second.isRFC3588()) continue;
427
428     (*it).second.asXML(result);
429   }
430
431   // Vendors
432   for(const_vendor_iterator it = vendor_begin(); it != vendor_end(); it++)
433     (*it).second.asXML(result);
434
435   // Avps
436   for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
437     if((*it).second.getFormat()->isAny()) continue;  // Generic AVP not shown
438
439     (*it).second.asXML(result);
440   }
441
442   // Commands
443   for(const_command_iterator it = command_begin(); it != command_end(); it++)
444     (*it).second.asXML(result);
445
446   return result;
447 }
448
449
450
451 //------------------------------------------------------------------------------
452 //---------------------------------------------------- Dictionary::asXMLString()
453 //------------------------------------------------------------------------------
454 std::string Dictionary::asXMLString() const {
455   anna::xml::Node root("root");
456   return anna::xml::Compiler().apply(asXML(&root));
457 }
458
459
460
461 ////------------------------------------------------------------------------------
462 ////----------------------------------------- Dictionary::checkUniqueIdentifiers()
463 ////------------------------------------------------------------------------------
464 //void Dictionary::checkUniqueIdentifiers(const anna::xml::Node *rootNode) const noexcept(false) {
465 //   std::map < std::string/*xml ref*/, int/*dummy*/ > formats;
466 //   std::map < std::string/*xml ref*/, int/*dummy*/ > vendors;
467 //   std::map < std::string/*xml ref*/, int/*dummy*/ > avps;
468 //   std::map < std::string/*xml ref*/, int/*dummy*/ > commands;
469 //   std::string nodeName, ref;
470 //
471 //   for (anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
472 //      nodeName = (*it)->getName();
473 //
474 //      if (nodeName == "format") {
475 //         ref = (*it)->getAttribute("name")->getValue();
476 //         int refs_i = formats.size(); formats[ref] = 0;
477 //
478 //         if (formats.size() == refs_i) {
479 //            std::string s_ex = anna::functions::asString("Repeated format name reference '%s' not allowed within the same xml dictionary", ref.c_str());
480 //            throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
481 //         }
482 //      } else if (nodeName == "vendor") {
483 //         ref = (*it)->getAttribute("name")->getValue();
484 //         int refs_i = vendors.size(); vendors[ref] = 0;
485 //
486 //         if (vendors.size() == refs_i) {
487 //            std::string s_ex = anna::functions::asString("Repeated vendor name reference '%s' not allowed within the same xml dictionary", ref.c_str());
488 //            throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
489 //         }
490 //      } else if (nodeName == "avp") {
491 //         ref = (*it)->getAttribute("name")->getValue();
492 //         int refs_i = avps.size(); avps[ref] = 0;
493 //
494 //         if (avps.size() == refs_i) {
495 //            std::string s_ex = anna::functions::asString("Repeated avp name reference '%s' not allowed within the same xml dictionary", ref.c_str());
496 //            throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
497 //         }
498 //      } else if (nodeName == "command") {
499 //         ref = (*it)->getAttribute("name")->getValue();
500 //         int refs_i = commands.size(); commands[ref] = 0;
501 //
502 //         if (commands.size() == refs_i) {
503 //            std::string s_ex = anna::functions::asString("Repeated command name reference '%s' not allowed within the same xml dictionary", ref.c_str());
504 //            throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
505 //         }
506 //      }
507 //   }
508 //}
509
510
511 //------------------------------------------------------------------------------
512 //------------------------------------------------- Dictionary::extractFormats()
513 //------------------------------------------------------------------------------
514 void Dictionary::extractFormats(const anna::xml::Node *rootNode) noexcept(false) {
515   Format aux;
516
517   for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
518     std::string nodeName = (*it)->getName();
519
520     if(nodeName == "format") {
521       // Reset:
522       aux.initialize(this);
523       // Attributes:
524       const char * type = (*it)->getAttribute("name")->getCStringValue(); // mandatory
525       const char * parentType = (*it)->getAttribute("parent-type")->getCStringValue(); // mandatory
526       // Assignments:
527       aux.setName(type);
528       aux.setParentName(parentType /* never empty, basics registered at initialization */);
529       // New entry:
530       addFormat(aux);
531     }
532   }
533 }
534
535
536 //------------------------------------------------------------------------------
537 //------------------------------------------------- Dictionary::extractVendors()
538 //------------------------------------------------------------------------------
539 void Dictionary::extractVendors(const anna::xml::Node *rootNode) noexcept(false) {
540   Vendor aux;
541
542   for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
543     std::string nodeName = (*it)->getName();
544
545     if(nodeName == "vendor") {
546       // Attributes:
547       const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
548       S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
549       // Assignments:
550       aux.setId(code);
551       aux.setName(name);
552       // New entry:
553       addVendor(aux);
554     }
555   }
556 }
557
558
559 //------------------------------------------------------------------------------
560 //---------------------------------------------------- Dictionary::extractAvps()
561 //------------------------------------------------------------------------------
562 void Dictionary::extractAvps(const anna::xml::Node *rootNode) noexcept(false) {
563   Avp auxAvp;
564   const anna::xml::Node *singleNode, *groupedNode;
565
566   for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
567     std::string nodeName = (*it)->getName();
568
569     if(nodeName == "avp") {
570       // Reset:
571       auxAvp.initialize(this);
572       // Attributes:
573       const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
574       S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
575       const anna::xml::Attribute *vendor_name = (*it)->getAttribute("vendor-name", anna::Exception::Mode::Ignore); // implied
576       S32 vendorCode = 0; /* IETF by default */
577
578       if(vendor_name) {
579         const char * c_name = vendor_name->getCStringValue();
580         auxAvp.setVendorName(c_name);
581         const_vendorNames_iterator v_it = a_vendorNames.find(c_name);
582
583         if(v_it == a_vendorNames.end()) {
584           std::string s_ex = anna::functions::asString("Vendor '%s', referenced at '%s' avp definition, not found at xml", c_name, name);
585           throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
586         }
587
588         vendorCode = ((*v_it).second)->getId();
589       }
590
591       // Assignments:
592       auxAvp.setCode(code);
593       auxAvp.setVendorId(vendorCode);
594       auxAvp.setName(name);
595       // libxml2 doesn't support default attribute value retrieving. All default values will be replaced by #IMPLIED sintax:
596       const anna::xml::Attribute *v_bit, *m_bit, *p_bit, *may_encript;
597       v_bit = (*it)->getAttribute("v-bit", anna::Exception::Mode::Ignore);
598       m_bit = (*it)->getAttribute("m-bit", anna::Exception::Mode::Ignore);
599       p_bit = (*it)->getAttribute("p-bit", anna::Exception::Mode::Ignore);
600       may_encript = (*it)->getAttribute("may-encrypt", anna::Exception::Mode::Ignore);
601       auxAvp.setVbit(v_bit ? (Avp::FlagRule::asEnum(v_bit->getCStringValue())) : (Avp::FlagRule::mustnot));
602       auxAvp.setMbit(m_bit ? (Avp::FlagRule::asEnum(m_bit->getCStringValue())) : (Avp::FlagRule::may));
603       auxAvp.setPbit(p_bit ? (Avp::FlagRule::asEnum(p_bit->getCStringValue())) : (Avp::FlagRule::may));
604       auxAvp.setMayEncrypt(may_encript ? ((may_encript->getValue()) == "yes") : false);
605
606       // Check vendor specific bit:
607       if(vendorCode && (auxAvp.getVbit() == Avp::FlagRule::mustnot)) {
608         std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (mustnot) at '%s' avp definicion, are incompatible with non-zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str());
609         throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
610       }
611
612       if(!vendorCode && (auxAvp.getVbit() == Avp::FlagRule::must)) {
613         std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (must) at '%s' avp definicion, are incompatible with zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str());
614         throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
615       }
616
617       // Single or grouped:
618       singleNode = (*it)->find("single", anna::Exception::Mode::Ignore);
619       groupedNode = (*it)->find("grouped", anna::Exception::Mode::Ignore);
620
621       if(singleNode) {
622         // Attributes:
623         const char * formatName = singleNode->getAttribute("format-name")->getCStringValue(); // mandatory
624         const anna::xml::Attribute *_enum = singleNode->getAttribute("enum", anna::Exception::Mode::Ignore); // implied
625         // Assignments:
626         const Format *format = getFormat(formatName);
627
628         if(!format) {
629           std::string s_ex = anna::functions::asString("Format '%s', referenced at '%s' avp definition, not found at dictionary (neither xml nor RFC 3588 diameter format types)", formatName, name);
630           throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
631         }
632
633         auxAvp.setFormatName(formatName);
634
635         if(_enum) {
636           const char *enums = _enum->getCStringValue();
637
638           if(!format->isEnumerated()) {
639             std::string s_ex = anna::functions::asString("Enumerated literal '%s' is not allowed for '%s' avp format", enums, formatName);
640             throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
641           }
642
643           auxAvp.setEnums(enums);
644         }
645
646         for(anna::xml::Node::const_child_iterator l_it = singleNode->child_begin(); l_it != singleNode->child_end(); l_it++) {
647           // Attributes:
648           std::string data = (*l_it)->getAttribute("data")->getValue(); // mandatory
649           std::string alias = (*l_it)->getAttribute("alias")->getValue(); // mandatory
650           // Assignment:
651           auxAvp.addLabel(data, alias);
652         }
653       } else { // grouped
654         // Assignments:
655         auxAvp.setFormatName(codec::Format::asText(codec::Format::Grouped));
656         // Wait for avprule insertion, because we need complete avp reference pool (*)
657       }
658
659       // New entry:
660       addAvp(auxAvp);
661     } // end if
662   } // end for
663
664   // (*) Avp rules adding:
665   for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
666     std::string nodeName = (*it)->getName();
667
668     if(nodeName == "avp") {
669       // Attributes:
670       const char * gid = (*it)->getAttribute("name")->getCStringValue(); // mandatory
671       // Avp:
672       const_avpNames_iterator a_it = a_avpNames.find(gid);
673       Avp * gavp = (Avp *)((*a_it).second);
674
675       if(!gavp) continue;  // it could be mising (a redefinition could have removed it)
676
677       const Format *format = gavp->getFormat();
678
679       // Avprule updating:
680       if(format->isGrouped()) {
681         AvpRule auxAvpRule(this);
682         groupedNode = (*it)->find("grouped");
683
684         for(anna::xml::Node::const_child_iterator r_it = groupedNode->child_begin(); r_it != groupedNode->child_end(); r_it++) {
685           // Attributes:
686           std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory
687           std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory
688           const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied
689           // Assignment:
690           const Avp * avp = getAvp(id);
691
692           if(avp == NULL) {
693             std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within grouped avp '%s', not found at xml", id.c_str(), gid);
694             throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
695           }
696
697           auxAvpRule.setAvpId(avp->getId());
698           auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
699           auxAvpRule.setQual(qual ? (qual->getValue()) : "");
700           gavp->addAvpRule(auxAvpRule);
701         }
702       } // grouped
703     } // end if
704   } // end for
705
706   // Check avp loops between grouped avps:
707
708   // In order to avoid loops, we could force to define grouped avps which children
709   //  had been previously defined at xml file. In this way, is imposible to get a loop:
710   //   C = ...
711   //   D = ...
712   //   A = grouped of B,C,D -> error, B unknown
713   //   B = grouped of A,F -> with former definition, would become a loop
714   //
715   // But this supposes a restriction at xml configuration (specific order).
716   // The other way is an internal check: a grouped AVP won't have descendants within
717   //  its ascendants. Then we will check all grouped avps in this way:
718   //
719   // 1. Searching for another grouped avps which are parents for this avp.
720   // 2. If these are children (even this avp(*)) at avp definition, then a loop is detected.
721   //
722   // Example 1: (1) Analyzing 'A', found parent 'B' / (2) 'B' is already children of 'A'
723   //       A -> B
724   //            C
725   //            D
726   //       ...
727   //       B -> A -> loop !!
728   //            F
729   //
730   // (*) Example 2: (1) Analyzing 'A', found parent 'A' / (2) 'A' is already children of 'A'
731   //       A -> B
732   //            C
733   //            D
734   //            A -> loop !!
735   //
736   for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
737     const Avp & avp = (*it).second;
738
739     if(!((avp.getFormat())->isGrouped())) continue;
740
741     for(const_avp_iterator it_p = avp_begin(); it_p != avp_end(); it_p++) {
742       const Avp & avp_p = (*it_p).second;
743
744       if(!((avp_p.getFormat())->isGrouped())) continue;
745
746       if(avp_p.isChild(avp.getId())) {
747         if(avp.isChild(avp_p.getId())) {
748           std::string s_ex;
749
750           if(it != it_p)
751             s_ex = anna::functions::asString("Loop detected between grouped avps '%s' and '%s'", avp.getName().c_str(), avp_p.getName().c_str());
752           else
753             s_ex = anna::functions::asString("Loop within grouped avp '%s': cannot contain itself !!", avp.getName().c_str());
754
755           throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
756         } // parent is children of (ref): loop !
757       } // parent found
758     } // search parents
759   } // search grouped avps (ref)
760 }
761
762
763 //------------------------------------------------------------------------------
764 //------------------------------------------------ Dictionary::extractCommands()
765 //------------------------------------------------------------------------------
766 void Dictionary::extractCommands(const anna::xml::Node *rootNode) noexcept(false) {
767   Command auxCommand;
768
769   // (*) Avp rules adding:
770   for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
771     std::string nodeName = (*it)->getName();
772
773     if(nodeName == "command") {
774       // Reset:
775       auxCommand.initialize(this);
776       // Attributes:
777       const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
778       U24 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
779       std::string type = (*it)->getAttribute("type")->getValue(); // mandatory
780       // Assignment:
781       auxCommand.setCode(code);
782       auxCommand.setName(name);
783       auxCommand.setRequest(type == "Request");
784       AvpRule auxAvpRule(this);
785
786       for(anna::xml::Node::const_child_iterator r_it = (*it)->child_begin(); r_it != (*it)->child_end(); r_it++) {
787         // Attributes:
788         std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory
789         std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory
790         const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied
791         // Assignment:
792         const Avp * avp = getAvp(id);
793
794         if(avp == NULL) {
795           std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within command '%s', not found at xml", id.c_str(), name);
796           throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
797         }
798
799         auxAvpRule.setAvpId(avp->getId());
800         auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
801         auxAvpRule.setQual(qual ? (qual->getValue()) : "");
802         auxCommand.addAvpRule(auxAvpRule);
803       }
804
805       // New entry:
806       addCommand(auxCommand);
807     } // end if
808   } // end for
809 }
810
811
812 //------------------------------------------------------------------------------
813 //----------------------------------------------------------- Dictionary::load()
814 //------------------------------------------------------------------------------
815 void Dictionary::load(const std::string & pathFile) noexcept(false) {
816   if(pathFile == "")
817     throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION);
818
819   LOGDEBUG(
820     std::string trace = "Loading diameter dictionary from '";
821     trace += pathFile;
822     trace += "' ...";
823     anna::Logger::debug(trace, ANNA_FILE_LOCATION);
824   );
825
826   try {
827     anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy)
828     const anna::xml::Node *rootNode;
829     xmlDocument.initialize(pathFile.c_str()); // fail here is i/o error
830     rootNode = xmlDocument.parse(*a_dtd); // Parsing: fail here if xml violates dtd
831     a_name = rootNode->getAttribute("name")->getValue();
832     //checkUniqueIdentifiers(rootNode);   // Check unique id within xml, for vendor, avp and command nodes:
833     extractFormats(rootNode);           // Add formats:
834     extractVendors(rootNode);           // Add vendors:
835     extractAvps(rootNode);              // Add avps:
836     extractCommands(rootNode);          // Add commands:
837   } catch(anna::RuntimeException& ex) {
838     ////ex.trace();
839     throw;
840   }
841
842   // Trace:
843   LOGDEBUG(anna::Logger::debug(asString(), ANNA_FILE_LOCATION));
844 }
845