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