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