1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
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 //
10 #include <anna/diameter/stack/Dictionary.hpp>
11 #include <anna/diameter/stack/Engine.hpp>
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>
18 #include <anna/config/defines.hpp>
19 #include <anna/core/functions.hpp>
20 #include <anna/diameter/codec/Format.hpp>
26 using namespace anna::diameter::stack;
30 //------------------------------------------------------------------------------
31 //---------------------------------------------------------------------- #define
32 //------------------------------------------------------------------------------
33 #define ITEM_OVERWRITE(item_n,item,pool,poolNames)\
35 std::string trace = "\n Updated ";\
38 trace += anna::functions::tab(found->asString(), 6);\
39 trace += "\n New content:\n";\
40 trace += anna::functions::tab(item.asString(), 6);\
42 anna::Logger::notice(trace, ANNA_FILE_LOCATION);\
44 pool.erase(pool.find(found->getId()));\
45 poolNames.erase(poolNames.find(found->getName()));
48 //------------------------------------------------------------------------------
49 //----------------------------------------------------- Dictionary::Dictionary()
50 //------------------------------------------------------------------------------
51 Dictionary::Dictionary(void) {
52 a_dtd = (Engine::instantiate()).getDictionariesDTD();
53 a_allowUpdates = false;
57 //------------------------------------------------------------------------------
58 //----------------------------------------------------- Dictionary::initialize()
59 //------------------------------------------------------------------------------
60 void Dictionary::initialize() throw() {
65 a_vendorNames.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);
83 addFormat(Unsigned32);
84 addFormat(Unsigned64);
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());
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");
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);
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);
132 const Format * found = getFormat(format.getName());
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();
139 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
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);
148 anna::Logger::notice(trace, ANNA_FILE_LOCATION);
152 a_formats[format.getName()] = format;
156 //------------------------------------------------------------------------------
157 //------------------------------------------------------ Dictionary::addVendor()
158 //------------------------------------------------------------------------------
159 void Dictionary::addVendor(const Vendor & vendor) throw(anna::RuntimeException) {
161 const Vendor * found = getVendor(vendor.getId());
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);
169 ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
172 found = getVendor(vendor.getName());
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);
180 ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
183 a_vendors[vendor.getId()] = vendor;
184 a_vendorNames[vendor.getName()] = getVendor(vendor.getId());
188 //------------------------------------------------------------------------------
189 //--------------------------------------------------------- Dictionary::addAvp()
190 //------------------------------------------------------------------------------
191 void Dictionary::addAvp(const Avp & avp) throw(anna::RuntimeException) {
193 const Avp * found = getAvp(avp.getId());
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);
201 ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
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);
211 ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
214 a_avps[avp.getId()] = avp;
215 a_avpNames[avp.getName()] = getAvp(avp.getId());
219 //------------------------------------------------------------------------------
220 //----------------------------------------------------- Dictionary::addCommand()
221 //------------------------------------------------------------------------------
222 void Dictionary::addCommand(const Command & command) throw(anna::RuntimeException) {
224 const Command * found = getCommand(command.getId());
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);
232 ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
236 found = getCommand(command.getName());
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);
244 ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
247 a_commands[command.getId()] = command;
248 a_commandNames[command.getName()] = getCommand(command.getId());
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);
260 if(it != format_end()) return ((const Format *) & ((*it).second));
266 //------------------------------------------------------------------------------
267 //------------------------------------------------------ Dictionary::getVendor()
268 //------------------------------------------------------------------------------
269 const Vendor * Dictionary::getVendor(S32 vendorId) const throw() {
270 const_vendor_iterator it = a_vendors.find(vendorId);
272 if(it != vendor_end()) return ((const Vendor *) & ((*it).second));
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);
284 if(v_it != a_vendorNames.end()) return ((*v_it).second);
290 //------------------------------------------------------------------------------
291 //--------------------------------------------------------- Dictionary::getAvp()
292 //------------------------------------------------------------------------------
293 const Avp * Dictionary::getAvp(const AvpId & avpId) const throw() {
294 const_avp_iterator it = a_avps.find(avpId);
296 if(it != avp_end()) return ((const Avp *) & ((*it).second));
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);
308 if(a_it != a_avpNames.end()) return ((*a_it).second);
314 //------------------------------------------------------------------------------
315 //----------------------------------------------------- Dictionary::getCommand()
316 //------------------------------------------------------------------------------
317 const Command * Dictionary::getCommand(const CommandId & commandId) const throw() {
318 const_command_iterator it = a_commands.find(commandId);
320 if(it != command_end()) return ((const Command *) & ((*it).second));
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);
332 if(c_it != a_commandNames.end()) return ((*c_it).second);
338 //------------------------------------------------------------------------------
339 //------------------------------------------------------- Dictionary::asString()
340 //------------------------------------------------------------------------------
341 std::string Dictionary::asString(void) const throw() {
342 std::string trace, title;
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;
354 //title = "Formats (";
355 //title += anna::functions::entriesAsString(format_size());
357 trace += anna::functions::highlight(title, thm);
359 for(f_it = format_begin(); f_it != format_end(); f_it++) {
360 if((*f_it).second.isReserved()) continue;
362 if((*f_it).second.isRFC3588())
363 trace += "(Diameter RFC-3588 type) ";
365 trace += "(Application-specific type) ";
367 trace += (*f_it).second.asString();
374 title += anna::functions::entriesAsString(vendor_size());
376 trace += anna::functions::highlight(title, thm);
378 for(v_it = vendor_begin(); v_it != vendor_end(); v_it++) {
379 trace += (*v_it).second.asString();
386 title += anna::functions::entriesAsString(avp_size());
388 trace += anna::functions::highlight(title, thm);
390 for(a_it = avp_begin(); a_it != avp_end(); a_it++) {
391 trace += (*a_it).second.asString();
397 title = "Commands (";
398 title += anna::functions::entriesAsString(command_size());
400 trace += anna::functions::highlight(title, thm);
402 for(c_it = command_begin(); c_it != command_end(); c_it++) {
403 trace += (*c_it).second.asString();
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);
422 for(const_format_iterator it = format_begin(); it != format_end(); it++) {
423 if((*it).second.isReserved()) continue;
425 if((*it).second.isRFC3588()) continue;
427 (*it).second.asXML(result);
431 for(const_vendor_iterator it = vendor_begin(); it != vendor_end(); it++)
432 (*it).second.asXML(result);
435 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
436 if((*it).second.getFormat()->isAny()) continue; // Generic AVP not shown
438 (*it).second.asXML(result);
442 for(const_command_iterator it = command_begin(); it != command_end(); it++)
443 (*it).second.asXML(result);
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));
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;
470 // for (anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
471 // nodeName = (*it)->getName();
473 // if (nodeName == "format") {
474 // ref = (*it)->getAttribute("name")->getValue();
475 // int refs_i = formats.size(); formats[ref] = 0;
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);
481 // } else if (nodeName == "vendor") {
482 // ref = (*it)->getAttribute("name")->getValue();
483 // int refs_i = vendors.size(); vendors[ref] = 0;
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);
489 // } else if (nodeName == "avp") {
490 // ref = (*it)->getAttribute("name")->getValue();
491 // int refs_i = avps.size(); avps[ref] = 0;
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);
497 // } else if (nodeName == "command") {
498 // ref = (*it)->getAttribute("name")->getValue();
499 // int refs_i = commands.size(); commands[ref] = 0;
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);
510 //------------------------------------------------------------------------------
511 //------------------------------------------------- Dictionary::extractFormats()
512 //------------------------------------------------------------------------------
513 void Dictionary::extractFormats(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
516 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
517 std::string nodeName = (*it)->getName();
519 if(nodeName == "format") {
521 aux.initialize(this);
523 const char * type = (*it)->getAttribute("name")->getCStringValue(); // mandatory
524 const char * parentType = (*it)->getAttribute("parent-type")->getCStringValue(); // mandatory
527 aux.setParentName(parentType /* never empty, basics registered at initialization */);
535 //------------------------------------------------------------------------------
536 //------------------------------------------------- Dictionary::extractVendors()
537 //------------------------------------------------------------------------------
538 void Dictionary::extractVendors(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
541 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
542 std::string nodeName = (*it)->getName();
544 if(nodeName == "vendor") {
546 const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
547 S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
558 //------------------------------------------------------------------------------
559 //---------------------------------------------------- Dictionary::extractAvps()
560 //------------------------------------------------------------------------------
561 void Dictionary::extractAvps(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
563 const anna::xml::Node *singleNode, *groupedNode;
565 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
566 std::string nodeName = (*it)->getName();
568 if(nodeName == "avp") {
570 auxAvp.initialize(this);
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 */
578 const char * c_name = vendor_name->getCStringValue();
579 auxAvp.setVendorName(c_name);
580 const_vendorNames_iterator v_it = a_vendorNames.find(c_name);
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);
587 vendorCode = ((*v_it).second)->getId();
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);
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);
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);
616 // Single or grouped:
617 singleNode = (*it)->find("single", anna::Exception::Mode::Ignore);
618 groupedNode = (*it)->find("grouped", anna::Exception::Mode::Ignore);
622 const char * formatName = singleNode->getAttribute("format-name")->getCStringValue(); // mandatory
623 const anna::xml::Attribute *_enum = singleNode->getAttribute("enum", anna::Exception::Mode::Ignore); // implied
625 const Format *format = getFormat(formatName);
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);
632 auxAvp.setFormatName(formatName);
635 const char *enums = _enum->getCStringValue();
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);
642 auxAvp.setEnums(enums);
645 for(anna::xml::Node::const_child_iterator l_it = singleNode->child_begin(); l_it != singleNode->child_end(); l_it++) {
647 std::string data = (*l_it)->getAttribute("data")->getValue(); // mandatory
648 std::string alias = (*l_it)->getAttribute("alias")->getValue(); // mandatory
650 auxAvp.addLabel(data, alias);
654 auxAvp.setFormatName(codec::Format::asText(codec::Format::Grouped));
655 // Wait for avprule insertion, because we need complete avp reference pool (*)
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();
667 if(nodeName == "avp") {
669 const char * gid = (*it)->getAttribute("name")->getCStringValue(); // mandatory
671 const_avpNames_iterator a_it = a_avpNames.find(gid);
672 Avp * gavp = (Avp *)((*a_it).second);
674 if(!gavp) continue; // it could be mising (a redefinition could have removed it)
676 const Format *format = gavp->getFormat();
679 if(format->isGrouped()) {
680 AvpRule auxAvpRule(this);
681 groupedNode = (*it)->find("grouped");
683 for(anna::xml::Node::const_child_iterator r_it = groupedNode->child_begin(); r_it != groupedNode->child_end(); r_it++) {
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
689 const Avp * avp = getAvp(id);
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);
696 auxAvpRule.setAvpId(avp->getId());
697 auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
698 auxAvpRule.setQual(qual ? (qual->getValue()) : "");
699 gavp->addAvpRule(auxAvpRule);
705 // Check avp loops between grouped avps:
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:
711 // A = grouped of B,C,D -> error, B unknown
712 // B = grouped of A,F -> with former definition, would become a loop
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:
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.
721 // Example 1: (1) Analyzing 'A', found parent 'B' / (2) 'B' is already children of 'A'
729 // (*) Example 2: (1) Analyzing 'A', found parent 'A' / (2) 'A' is already children of 'A'
735 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
736 const Avp & avp = (*it).second;
738 if(!((avp.getFormat())->isGrouped())) continue;
740 for(const_avp_iterator it_p = avp_begin(); it_p != avp_end(); it_p++) {
741 const Avp & avp_p = (*it_p).second;
743 if(!((avp_p.getFormat())->isGrouped())) continue;
745 if(avp_p.isChild(avp.getId())) {
746 if(avp.isChild(avp_p.getId())) {
750 s_ex = anna::functions::asString("Loop detected between grouped avps '%s' and '%s'", avp.getName().c_str(), avp_p.getName().c_str());
752 s_ex = anna::functions::asString("Loop within grouped avp '%s': cannot contain itself !!", avp.getName().c_str());
754 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
755 } // parent is children of (ref): loop !
758 } // search grouped avps (ref)
762 //------------------------------------------------------------------------------
763 //------------------------------------------------ Dictionary::extractCommands()
764 //------------------------------------------------------------------------------
765 void Dictionary::extractCommands(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
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();
772 if(nodeName == "command") {
774 auxCommand.initialize(this);
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
780 auxCommand.setCode(code);
781 auxCommand.setName(name);
782 auxCommand.setRequest(type == "Request");
783 AvpRule auxAvpRule(this);
785 for(anna::xml::Node::const_child_iterator r_it = (*it)->child_begin(); r_it != (*it)->child_end(); r_it++) {
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
791 const Avp * avp = getAvp(id);
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);
798 auxAvpRule.setAvpId(avp->getId());
799 auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
800 auxAvpRule.setQual(qual ? (qual->getValue()) : "");
801 auxCommand.addAvpRule(auxAvpRule);
805 addCommand(auxCommand);
811 //------------------------------------------------------------------------------
812 //----------------------------------------------------------- Dictionary::load()
813 //------------------------------------------------------------------------------
814 void Dictionary::load(const std::string & pathFile) throw(anna::RuntimeException) {
816 throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION);
819 std::string trace = "Loading diameter dictionary from '";
822 anna::Logger::debug(trace, ANNA_FILE_LOCATION);
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) {
842 LOGDEBUG(anna::Logger::debug(asString(), ANNA_FILE_LOCATION));