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 std::string name = found->getName();\
45 pool.erase(pool.find(found->getId()));\
46 poolNames.erase(poolNames.find(name));
49 //------------------------------------------------------------------------------
50 //----------------------------------------------------- Dictionary::Dictionary()
51 //------------------------------------------------------------------------------
52 Dictionary::Dictionary(void) {
53 a_dtd = (Engine::instantiate()).getDictionariesDTD();
54 a_allowUpdates = false;
58 //------------------------------------------------------------------------------
59 //----------------------------------------------------- Dictionary::initialize()
60 //------------------------------------------------------------------------------
61 void Dictionary::initialize() throw() {
66 a_vendorNames.clear();
68 a_commandNames.clear();
69 a_dtd = (Engine::instantiate()).getDictionariesDTD();
70 // RFC3588 Diameter Formats harcoding:
71 // Basic diameter types
72 Format OctetString(this), Integer32(this), Integer64(this), Unsigned32(this), Unsigned64(this), Float32(this), Float64(this), Grouped(this);
73 OctetString.setRFC3588(codec::Format::OctetString);
74 Integer32.setRFC3588(codec::Format::Integer32);
75 Integer64.setRFC3588(codec::Format::Integer64);
76 Unsigned32.setRFC3588(codec::Format::Unsigned32);
77 Unsigned64.setRFC3588(codec::Format::Unsigned64);
78 Float32.setRFC3588(codec::Format::Float32);
79 Float64.setRFC3588(codec::Format::Float64);
80 Grouped.setRFC3588(codec::Format::Grouped);
81 addFormat(OctetString);
84 addFormat(Unsigned32);
85 addFormat(Unsigned64);
89 // Derived diameter types
90 Format Address(this), Time(this), UTF8String(this), DiameterIdentity(this), DiameterURI(this), Enumerated(this), IPFilterRule(this), QoSFilterRule(this);
91 Address.setRFC3588(codec::Format::Address); Address.setParentName(OctetString.getName());
92 Time.setRFC3588(codec::Format::Time); Time.setParentName(OctetString.getName());
93 UTF8String.setRFC3588(codec::Format::UTF8String); UTF8String.setParentName(OctetString.getName());
94 DiameterIdentity.setRFC3588(codec::Format::DiameterIdentity); DiameterIdentity.setParentName(OctetString.getName());
95 DiameterURI.setRFC3588(codec::Format::DiameterURI); DiameterURI.setParentName(OctetString.getName());
96 Enumerated.setRFC3588(codec::Format::Enumerated); Enumerated.setParentName(Integer32.getName());
97 IPFilterRule.setRFC3588(codec::Format::IPFilterRule); IPFilterRule.setParentName(OctetString.getName());
98 QoSFilterRule.setRFC3588(codec::Format::QoSFilterRule); QoSFilterRule.setParentName(OctetString.getName());
101 addFormat(UTF8String);
102 addFormat(DiameterIdentity);
103 addFormat(DiameterURI);
104 addFormat(Enumerated);
105 addFormat(IPFilterRule);
106 addFormat(QoSFilterRule);
107 // Generic AVP hardcoding:
108 Avp genericAvp(this);
109 genericAvp.setCode(0);
110 genericAvp.setVendorId(0/*Vendor::Code::Ietf*/);
111 genericAvp.setName("AVP");
113 Any.setRFC3588(codec::Format::Any);
114 addFormat(Any, true /*reserved*/);
115 genericAvp.setFormatName(Any.getName());
116 genericAvp.setVbit(Avp::FlagRule::mustnot);
117 genericAvp.setMbit(Avp::FlagRule::may);
118 genericAvp.setPbit(Avp::FlagRule::may);
119 genericAvp.setMayEncrypt(false);
124 //------------------------------------------------------------------------------
125 //------------------------------------------------------ Dictionary::addFormat()
126 //------------------------------------------------------------------------------
127 void Dictionary::addFormat(const Format & format, bool reserved) throw(anna::RuntimeException) {
128 if(!reserved && format.isReserved()) {
129 std::string s_ex = anna::functions::asString("Format type '%s' is reserved for internal use", format.getName().c_str());
130 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
133 const Format * found = getFormat(format.getName());
135 if(!a_allowUpdates) {
136 std::string s_ex = "Cannot add a format with an existing type name: ";
137 //s_ex += format.getName();
138 s_ex += format.asString();
140 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
144 std::string trace = "\n Updated format:\n";
145 trace += anna::functions::tab(found->asString(), 6);
146 trace += "\n New content:\n";
147 trace += anna::functions::tab(format.asString(), 6);
149 anna::Logger::notice(trace, ANNA_FILE_LOCATION);
153 a_formats[format.getName()] = format;
157 //------------------------------------------------------------------------------
158 //------------------------------------------------------ Dictionary::addVendor()
159 //------------------------------------------------------------------------------
160 void Dictionary::addVendor(const Vendor & vendor) throw(anna::RuntimeException) {
162 const Vendor * found = getVendor(vendor.getId());
164 if(!a_allowUpdates) {
165 std::string s_ex = "Cannot add a vendor with an existing code: ";
166 s_ex += vendor.asString();
167 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
170 ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
173 found = getVendor(vendor.getName());
175 if(!a_allowUpdates) {
176 std::string s_ex = "Cannot add a vendor with an existing name: ";
177 s_ex += vendor.asString();
178 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
181 ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
184 a_vendors[vendor.getId()] = vendor;
185 a_vendorNames[vendor.getName()] = getVendor(vendor.getId());
189 //------------------------------------------------------------------------------
190 //--------------------------------------------------------- Dictionary::addAvp()
191 //------------------------------------------------------------------------------
192 void Dictionary::addAvp(const Avp & avp) throw(anna::RuntimeException) {
194 const Avp * found = getAvp(avp.getId());
196 if(!a_allowUpdates) {
197 std::string s_ex = "Cannot add an avp with an existing identifier (code,vendor):\n";
198 s_ex += avp.asString();
199 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
202 ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
205 if((found = getAvp(avp.getName()))) {
206 if(!a_allowUpdates) {
207 std::string s_ex = "Cannot add an avp with an existing name:\n";
208 s_ex += avp.asString();
209 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
212 ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
215 a_avps[avp.getId()] = avp;
216 a_avpNames[avp.getName()] = getAvp(avp.getId());
220 //------------------------------------------------------------------------------
221 //----------------------------------------------------- Dictionary::addCommand()
222 //------------------------------------------------------------------------------
223 void Dictionary::addCommand(const Command & command) throw(anna::RuntimeException) {
225 const Command * found = getCommand(command.getId());
227 if(!a_allowUpdates) {
228 std::string s_ex = "Cannot add a command with an existing identifier:\n";
229 s_ex += command.asString();
230 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
233 ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
237 found = getCommand(command.getName());
239 if(!a_allowUpdates) {
240 std::string s_ex = "Cannot add a command with an existing name:\n";
241 s_ex += command.asString();
242 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
245 ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
248 a_commands[command.getId()] = command;
249 a_commandNames[command.getName()] = getCommand(command.getId());
255 //------------------------------------------------------------------------------
256 //------------------------------------------------------ Dictionary::getFormat()
257 //------------------------------------------------------------------------------
258 const Format * Dictionary::getFormat(const std::string & formatName) const throw() {
259 const_format_iterator it = a_formats.find(formatName);
261 if(it != format_end()) return ((const Format *) & ((*it).second));
267 //------------------------------------------------------------------------------
268 //------------------------------------------------------ Dictionary::getVendor()
269 //------------------------------------------------------------------------------
270 const Vendor * Dictionary::getVendor(S32 vendorId) const throw() {
271 const_vendor_iterator it = a_vendors.find(vendorId);
273 if(it != vendor_end()) return ((const Vendor *) & ((*it).second));
279 //------------------------------------------------------------------------------
280 //------------------------------------------------------ Dictionary::getVendor()
281 //------------------------------------------------------------------------------
282 const Vendor * Dictionary::getVendor(const std::string & vendorName) const throw() {
283 const_vendorNames_iterator v_it = a_vendorNames.find(vendorName);
285 if(v_it != a_vendorNames.end()) return ((*v_it).second);
291 //------------------------------------------------------------------------------
292 //--------------------------------------------------------- Dictionary::getAvp()
293 //------------------------------------------------------------------------------
294 const Avp * Dictionary::getAvp(const AvpId & avpId) const throw() {
295 const_avp_iterator it = a_avps.find(avpId);
297 if(it != avp_end()) return ((const Avp *) & ((*it).second));
303 //------------------------------------------------------------------------------
304 //--------------------------------------------------------- Dictionary::getAvp()
305 //------------------------------------------------------------------------------
306 const Avp * Dictionary::getAvp(const std::string & avpName) const throw() {
307 const_avpNames_iterator a_it = a_avpNames.find(avpName);
309 if(a_it != a_avpNames.end()) return ((*a_it).second);
315 //------------------------------------------------------------------------------
316 //----------------------------------------------------- Dictionary::getCommand()
317 //------------------------------------------------------------------------------
318 const Command * Dictionary::getCommand(const CommandId & commandId) const throw() {
319 const_command_iterator it = a_commands.find(commandId);
321 if(it != command_end()) return ((const Command *) & ((*it).second));
327 //------------------------------------------------------------------------------
328 //----------------------------------------------------- Dictionary::getCommand()
329 //------------------------------------------------------------------------------
330 const Command * Dictionary::getCommand(const std::string & commandName) const throw() {
331 const_commandNames_iterator c_it = a_commandNames.find(commandName);
333 if(c_it != a_commandNames.end()) return ((*c_it).second);
339 //------------------------------------------------------------------------------
340 //------------------------------------------------------- Dictionary::asString()
341 //------------------------------------------------------------------------------
342 std::string Dictionary::asString(void) const throw() {
343 std::string trace, title;
345 anna::functions::TextHighlightMode::_v thm = anna::functions::TextHighlightMode::LeftAndRightline;
346 trace += anna::functions::highlight("Name", thm);
347 trace += a_name; trace += "\n";
348 const_format_iterator f_it;
349 const_vendor_iterator v_it;
350 const_avp_iterator a_it;
351 const_command_iterator c_it;
355 //title = "Formats (";
356 //title += anna::functions::entriesAsString(format_size());
358 trace += anna::functions::highlight(title, thm);
360 for(f_it = format_begin(); f_it != format_end(); f_it++) {
361 if((*f_it).second.isReserved()) continue;
363 if((*f_it).second.isRFC3588())
364 trace += "(Diameter RFC-3588 type) ";
366 trace += "(Application-specific type) ";
368 trace += (*f_it).second.asString();
375 title += anna::functions::entriesAsString(vendor_size());
377 trace += anna::functions::highlight(title, thm);
379 for(v_it = vendor_begin(); v_it != vendor_end(); v_it++) {
380 trace += (*v_it).second.asString();
387 title += anna::functions::entriesAsString(avp_size());
389 trace += anna::functions::highlight(title, thm);
391 for(a_it = avp_begin(); a_it != avp_end(); a_it++) {
392 trace += (*a_it).second.asString();
398 title = "Commands (";
399 title += anna::functions::entriesAsString(command_size());
401 trace += anna::functions::highlight(title, thm);
403 for(c_it = command_begin(); c_it != command_end(); c_it++) {
404 trace += (*c_it).second.asString();
413 //------------------------------------------------------------------------------
414 //---------------------------------------------------------- Dictionary::asXML()
415 //------------------------------------------------------------------------------
416 anna::xml::Node* Dictionary::asXML(anna::xml::Node* parent) const throw() {
417 // <!ELEMENT dictionary (format*, vendor*, avp*, command*)>
418 // <!ATTLIST dictionary name CDATA #REQUIRED>
419 anna::xml::Node* result = parent->createChild("dictionary");
420 result->createAttribute("name", a_name);
423 for(const_format_iterator it = format_begin(); it != format_end(); it++) {
424 if((*it).second.isReserved()) continue;
426 if((*it).second.isRFC3588()) continue;
428 (*it).second.asXML(result);
432 for(const_vendor_iterator it = vendor_begin(); it != vendor_end(); it++)
433 (*it).second.asXML(result);
436 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
437 if((*it).second.getFormat()->isAny()) continue; // Generic AVP not shown
439 (*it).second.asXML(result);
443 for(const_command_iterator it = command_begin(); it != command_end(); it++)
444 (*it).second.asXML(result);
451 //------------------------------------------------------------------------------
452 //---------------------------------------------------- Dictionary::asXMLString()
453 //------------------------------------------------------------------------------
454 std::string Dictionary::asXMLString() const throw() {
455 anna::xml::Node root("root");
456 return anna::xml::Compiler().apply(asXML(&root));
461 ////------------------------------------------------------------------------------
462 ////----------------------------------------- Dictionary::checkUniqueIdentifiers()
463 ////------------------------------------------------------------------------------
464 //void Dictionary::checkUniqueIdentifiers(const anna::xml::Node *rootNode) const throw(anna::RuntimeException) {
465 // std::map < std::string/*xml ref*/, int/*dummy*/ > formats;
466 // std::map < std::string/*xml ref*/, int/*dummy*/ > vendors;
467 // std::map < std::string/*xml ref*/, int/*dummy*/ > avps;
468 // std::map < std::string/*xml ref*/, int/*dummy*/ > commands;
469 // std::string nodeName, ref;
471 // for (anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
472 // nodeName = (*it)->getName();
474 // if (nodeName == "format") {
475 // ref = (*it)->getAttribute("name")->getValue();
476 // int refs_i = formats.size(); formats[ref] = 0;
478 // if (formats.size() == refs_i) {
479 // std::string s_ex = anna::functions::asString("Repeated format name reference '%s' not allowed within the same xml dictionary", ref.c_str());
480 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
482 // } else if (nodeName == "vendor") {
483 // ref = (*it)->getAttribute("name")->getValue();
484 // int refs_i = vendors.size(); vendors[ref] = 0;
486 // if (vendors.size() == refs_i) {
487 // std::string s_ex = anna::functions::asString("Repeated vendor name reference '%s' not allowed within the same xml dictionary", ref.c_str());
488 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
490 // } else if (nodeName == "avp") {
491 // ref = (*it)->getAttribute("name")->getValue();
492 // int refs_i = avps.size(); avps[ref] = 0;
494 // if (avps.size() == refs_i) {
495 // std::string s_ex = anna::functions::asString("Repeated avp name reference '%s' not allowed within the same xml dictionary", ref.c_str());
496 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
498 // } else if (nodeName == "command") {
499 // ref = (*it)->getAttribute("name")->getValue();
500 // int refs_i = commands.size(); commands[ref] = 0;
502 // if (commands.size() == refs_i) {
503 // std::string s_ex = anna::functions::asString("Repeated command name reference '%s' not allowed within the same xml dictionary", ref.c_str());
504 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
511 //------------------------------------------------------------------------------
512 //------------------------------------------------- Dictionary::extractFormats()
513 //------------------------------------------------------------------------------
514 void Dictionary::extractFormats(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
517 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
518 std::string nodeName = (*it)->getName();
520 if(nodeName == "format") {
522 aux.initialize(this);
524 const char * type = (*it)->getAttribute("name")->getCStringValue(); // mandatory
525 const char * parentType = (*it)->getAttribute("parent-type")->getCStringValue(); // mandatory
528 aux.setParentName(parentType /* never empty, basics registered at initialization */);
536 //------------------------------------------------------------------------------
537 //------------------------------------------------- Dictionary::extractVendors()
538 //------------------------------------------------------------------------------
539 void Dictionary::extractVendors(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
542 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
543 std::string nodeName = (*it)->getName();
545 if(nodeName == "vendor") {
547 const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
548 S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
559 //------------------------------------------------------------------------------
560 //---------------------------------------------------- Dictionary::extractAvps()
561 //------------------------------------------------------------------------------
562 void Dictionary::extractAvps(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
564 const anna::xml::Node *singleNode, *groupedNode;
566 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
567 std::string nodeName = (*it)->getName();
569 if(nodeName == "avp") {
571 auxAvp.initialize(this);
573 const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
574 S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
575 const anna::xml::Attribute *vendor_name = (*it)->getAttribute("vendor-name", anna::Exception::Mode::Ignore); // implied
576 S32 vendorCode = 0; /* IETF by default */
579 const char * c_name = vendor_name->getCStringValue();
580 auxAvp.setVendorName(c_name);
581 const_vendorNames_iterator v_it = a_vendorNames.find(c_name);
583 if(v_it == a_vendorNames.end()) {
584 std::string s_ex = anna::functions::asString("Vendor '%s', referenced at '%s' avp definition, not found at xml", c_name, name);
585 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
588 vendorCode = ((*v_it).second)->getId();
592 auxAvp.setCode(code);
593 auxAvp.setVendorId(vendorCode);
594 auxAvp.setName(name);
595 // libxml2 doesn't support default attribute value retrieving. All default values will be replaced by #IMPLIED sintax:
596 const anna::xml::Attribute *v_bit, *m_bit, *p_bit, *may_encript;
597 v_bit = (*it)->getAttribute("v-bit", anna::Exception::Mode::Ignore);
598 m_bit = (*it)->getAttribute("m-bit", anna::Exception::Mode::Ignore);
599 p_bit = (*it)->getAttribute("p-bit", anna::Exception::Mode::Ignore);
600 may_encript = (*it)->getAttribute("may-encrypt", anna::Exception::Mode::Ignore);
601 auxAvp.setVbit(v_bit ? (Avp::FlagRule::asEnum(v_bit->getCStringValue())) : (Avp::FlagRule::mustnot));
602 auxAvp.setMbit(m_bit ? (Avp::FlagRule::asEnum(m_bit->getCStringValue())) : (Avp::FlagRule::may));
603 auxAvp.setPbit(p_bit ? (Avp::FlagRule::asEnum(p_bit->getCStringValue())) : (Avp::FlagRule::may));
604 auxAvp.setMayEncrypt(may_encript ? ((may_encript->getValue()) == "yes") : false);
606 // Check vendor specific bit:
607 if(vendorCode && (auxAvp.getVbit() == Avp::FlagRule::mustnot)) {
608 std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (mustnot) at '%s' avp definicion, are incompatible with non-zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str());
609 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
612 if(!vendorCode && (auxAvp.getVbit() == Avp::FlagRule::must)) {
613 std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (must) at '%s' avp definicion, are incompatible with zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str());
614 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
617 // Single or grouped:
618 singleNode = (*it)->find("single", anna::Exception::Mode::Ignore);
619 groupedNode = (*it)->find("grouped", anna::Exception::Mode::Ignore);
623 const char * formatName = singleNode->getAttribute("format-name")->getCStringValue(); // mandatory
624 const anna::xml::Attribute *_enum = singleNode->getAttribute("enum", anna::Exception::Mode::Ignore); // implied
626 const Format *format = getFormat(formatName);
629 std::string s_ex = anna::functions::asString("Format '%s', referenced at '%s' avp definition, not found at dictionary (neither xml nor RFC 3588 diameter format types)", formatName, name);
630 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
633 auxAvp.setFormatName(formatName);
636 const char *enums = _enum->getCStringValue();
638 if(!format->isEnumerated()) {
639 std::string s_ex = anna::functions::asString("Enumerated literal '%s' is not allowed for '%s' avp format", enums, formatName);
640 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
643 auxAvp.setEnums(enums);
646 for(anna::xml::Node::const_child_iterator l_it = singleNode->child_begin(); l_it != singleNode->child_end(); l_it++) {
648 std::string data = (*l_it)->getAttribute("data")->getValue(); // mandatory
649 std::string alias = (*l_it)->getAttribute("alias")->getValue(); // mandatory
651 auxAvp.addLabel(data, alias);
655 auxAvp.setFormatName(codec::Format::asText(codec::Format::Grouped));
656 // Wait for avprule insertion, because we need complete avp reference pool (*)
664 // (*) Avp rules adding:
665 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
666 std::string nodeName = (*it)->getName();
668 if(nodeName == "avp") {
670 const char * gid = (*it)->getAttribute("name")->getCStringValue(); // mandatory
672 const_avpNames_iterator a_it = a_avpNames.find(gid);
673 Avp * gavp = (Avp *)((*a_it).second);
675 if(!gavp) continue; // it could be mising (a redefinition could have removed it)
677 const Format *format = gavp->getFormat();
680 if(format->isGrouped()) {
681 AvpRule auxAvpRule(this);
682 groupedNode = (*it)->find("grouped");
684 for(anna::xml::Node::const_child_iterator r_it = groupedNode->child_begin(); r_it != groupedNode->child_end(); r_it++) {
686 std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory
687 std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory
688 const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied
690 const Avp * avp = getAvp(id);
693 std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within grouped avp '%s', not found at xml", id.c_str(), gid);
694 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
697 auxAvpRule.setAvpId(avp->getId());
698 auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
699 auxAvpRule.setQual(qual ? (qual->getValue()) : "");
700 gavp->addAvpRule(auxAvpRule);
706 // Check avp loops between grouped avps:
708 // In order to avoid loops, we could force to define grouped avps which children
709 // had been previously defined at xml file. In this way, is imposible to get a loop:
712 // A = grouped of B,C,D -> error, B unknown
713 // B = grouped of A,F -> with former definition, would become a loop
715 // But this supposes a restriction at xml configuration (specific order).
716 // The other way is an internal check: a grouped AVP won't have descendants within
717 // its ascendants. Then we will check all grouped avps in this way:
719 // 1. Searching for another grouped avps which are parents for this avp.
720 // 2. If these are children (even this avp(*)) at avp definition, then a loop is detected.
722 // Example 1: (1) Analyzing 'A', found parent 'B' / (2) 'B' is already children of 'A'
730 // (*) Example 2: (1) Analyzing 'A', found parent 'A' / (2) 'A' is already children of 'A'
736 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
737 const Avp & avp = (*it).second;
739 if(!((avp.getFormat())->isGrouped())) continue;
741 for(const_avp_iterator it_p = avp_begin(); it_p != avp_end(); it_p++) {
742 const Avp & avp_p = (*it_p).second;
744 if(!((avp_p.getFormat())->isGrouped())) continue;
746 if(avp_p.isChild(avp.getId())) {
747 if(avp.isChild(avp_p.getId())) {
751 s_ex = anna::functions::asString("Loop detected between grouped avps '%s' and '%s'", avp.getName().c_str(), avp_p.getName().c_str());
753 s_ex = anna::functions::asString("Loop within grouped avp '%s': cannot contain itself !!", avp.getName().c_str());
755 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
756 } // parent is children of (ref): loop !
759 } // search grouped avps (ref)
763 //------------------------------------------------------------------------------
764 //------------------------------------------------ Dictionary::extractCommands()
765 //------------------------------------------------------------------------------
766 void Dictionary::extractCommands(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
769 // (*) Avp rules adding:
770 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
771 std::string nodeName = (*it)->getName();
773 if(nodeName == "command") {
775 auxCommand.initialize(this);
777 const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
778 U24 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
779 std::string type = (*it)->getAttribute("type")->getValue(); // mandatory
781 auxCommand.setCode(code);
782 auxCommand.setName(name);
783 auxCommand.setRequest(type == "Request");
784 AvpRule auxAvpRule(this);
786 for(anna::xml::Node::const_child_iterator r_it = (*it)->child_begin(); r_it != (*it)->child_end(); r_it++) {
788 std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory
789 std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory
790 const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied
792 const Avp * avp = getAvp(id);
795 std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within command '%s', not found at xml", id.c_str(), name);
796 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
799 auxAvpRule.setAvpId(avp->getId());
800 auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
801 auxAvpRule.setQual(qual ? (qual->getValue()) : "");
802 auxCommand.addAvpRule(auxAvpRule);
806 addCommand(auxCommand);
812 //------------------------------------------------------------------------------
813 //----------------------------------------------------------- Dictionary::load()
814 //------------------------------------------------------------------------------
815 void Dictionary::load(const std::string & pathFile) throw(anna::RuntimeException) {
817 throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION);
820 std::string trace = "Loading diameter dictionary from '";
823 anna::Logger::debug(trace, ANNA_FILE_LOCATION);
827 anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy)
828 const anna::xml::Node *rootNode;
829 xmlDocument.initialize(pathFile.c_str()); // fail here is i/o error
830 rootNode = xmlDocument.parse(*a_dtd); // Parsing: fail here if xml violates dtd
831 a_name = rootNode->getAttribute("name")->getValue();
832 //checkUniqueIdentifiers(rootNode); // Check unique id within xml, for vendor, avp and command nodes:
833 extractFormats(rootNode); // Add formats:
834 extractVendors(rootNode); // Add vendors:
835 extractAvps(rootNode); // Add avps:
836 extractCommands(rootNode); // Add commands:
837 } catch(anna::RuntimeException& ex) {
843 LOGDEBUG(anna::Logger::debug(asString(), ANNA_FILE_LOCATION));