1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
38 #include <anna/diameter/stack/Dictionary.hpp>
39 #include <anna/diameter/stack/Engine.hpp>
41 #include <anna/config/defines.hpp>
42 #include <anna/core/tracing/Logger.hpp>
43 #include <anna/xml/xml.hpp>
44 #include <anna/core/functions.hpp>
46 #include <anna/config/defines.hpp>
47 #include <anna/core/functions.hpp>
48 #include <anna/diameter/codec/Format.hpp>
54 using namespace anna::diameter::stack;
58 //------------------------------------------------------------------------------
59 //---------------------------------------------------------------------- #define
60 //------------------------------------------------------------------------------
61 #define ITEM_OVERWRITE(item_n,item,pool,poolNames)\
63 std::string trace = "\n Updated ";\
66 trace += anna::functions::tab(found->asString(), 6);\
67 trace += "\n New content:\n";\
68 trace += anna::functions::tab(item.asString(), 6);\
70 anna::Logger::notice(trace, ANNA_FILE_LOCATION);\
72 pool.erase(pool.find(found->getId()));\
73 poolNames.erase(poolNames.find(found->getName()));
76 //------------------------------------------------------------------------------
77 //----------------------------------------------------- Dictionary::Dictionary()
78 //------------------------------------------------------------------------------
79 Dictionary::Dictionary(void) {
80 a_dtd = (Engine::instantiate()).getDictionariesDTD();
81 a_allowUpdates = false;
85 //------------------------------------------------------------------------------
86 //----------------------------------------------------- Dictionary::initialize()
87 //------------------------------------------------------------------------------
88 void Dictionary::initialize() throw() {
93 a_vendorNames.clear();
95 a_commandNames.clear();
96 a_dtd = (Engine::instantiate()).getDictionariesDTD();
97 // RFC3588 Diameter Formats harcoding:
98 // Basic diameter types
99 Format OctetString(this), Integer32(this), Integer64(this), Unsigned32(this), Unsigned64(this), Float32(this), Float64(this), Grouped(this);
100 OctetString.setRFC3588(codec::Format::OctetString);
101 Integer32.setRFC3588(codec::Format::Integer32);
102 Integer64.setRFC3588(codec::Format::Integer64);
103 Unsigned32.setRFC3588(codec::Format::Unsigned32);
104 Unsigned64.setRFC3588(codec::Format::Unsigned64);
105 Float32.setRFC3588(codec::Format::Float32);
106 Float64.setRFC3588(codec::Format::Float64);
107 Grouped.setRFC3588(codec::Format::Grouped);
108 addFormat(OctetString);
109 addFormat(Integer32);
110 addFormat(Integer64);
111 addFormat(Unsigned32);
112 addFormat(Unsigned64);
116 // Derived diameter types
117 Format Address(this), Time(this), UTF8String(this), DiameterIdentity(this), DiameterURI(this), Enumerated(this), IPFilterRule(this), QoSFilterRule(this);
118 Address.setRFC3588(codec::Format::Address); Address.setParentName(OctetString.getName());
119 Time.setRFC3588(codec::Format::Time); Time.setParentName(OctetString.getName());
120 UTF8String.setRFC3588(codec::Format::UTF8String); UTF8String.setParentName(OctetString.getName());
121 DiameterIdentity.setRFC3588(codec::Format::DiameterIdentity); DiameterIdentity.setParentName(OctetString.getName());
122 DiameterURI.setRFC3588(codec::Format::DiameterURI); DiameterURI.setParentName(OctetString.getName());
123 Enumerated.setRFC3588(codec::Format::Enumerated); Enumerated.setParentName(Integer32.getName());
124 IPFilterRule.setRFC3588(codec::Format::IPFilterRule); IPFilterRule.setParentName(OctetString.getName());
125 QoSFilterRule.setRFC3588(codec::Format::QoSFilterRule); QoSFilterRule.setParentName(OctetString.getName());
128 addFormat(UTF8String);
129 addFormat(DiameterIdentity);
130 addFormat(DiameterURI);
131 addFormat(Enumerated);
132 addFormat(IPFilterRule);
133 addFormat(QoSFilterRule);
134 // Generic AVP hardcoding:
135 Avp genericAvp(this);
136 genericAvp.setCode(0);
137 genericAvp.setVendorId(0/*Vendor::Code::Ietf*/);
138 genericAvp.setName("AVP");
140 Any.setRFC3588(codec::Format::Any);
141 addFormat(Any, true /*reserved*/);
142 genericAvp.setFormatName(Any.getName());
143 genericAvp.setVbit(Avp::FlagRule::mustnot);
144 genericAvp.setMbit(Avp::FlagRule::may);
145 genericAvp.setPbit(Avp::FlagRule::may);
146 genericAvp.setMayEncrypt(false);
151 //------------------------------------------------------------------------------
152 //------------------------------------------------------ Dictionary::addFormat()
153 //------------------------------------------------------------------------------
154 void Dictionary::addFormat(const Format & format, bool reserved) throw(anna::RuntimeException) {
155 if(!reserved && format.isReserved()) {
156 std::string s_ex = anna::functions::asString("Format type '%s' is reserved for internal use", format.getName().c_str());
157 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
160 const Format * found = getFormat(format.getName());
162 if(!a_allowUpdates) {
163 std::string s_ex = "Cannot add a format with an existing type name: ";
164 //s_ex += format.getName();
165 s_ex += format.asString();
167 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
171 std::string trace = "\n Updated format:\n";
172 trace += anna::functions::tab(found->asString(), 6);
173 trace += "\n New content:\n";
174 trace += anna::functions::tab(format.asString(), 6);
176 anna::Logger::notice(trace, ANNA_FILE_LOCATION);
180 a_formats[format.getName()] = format;
184 //------------------------------------------------------------------------------
185 //------------------------------------------------------ Dictionary::addVendor()
186 //------------------------------------------------------------------------------
187 void Dictionary::addVendor(const Vendor & vendor) throw(anna::RuntimeException) {
189 const Vendor * found = getVendor(vendor.getId());
191 if(!a_allowUpdates) {
192 std::string s_ex = "Cannot add a vendor with an existing code: ";
193 s_ex += vendor.asString();
194 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
197 ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
200 found = getVendor(vendor.getName());
202 if(!a_allowUpdates) {
203 std::string s_ex = "Cannot add a vendor with an existing name: ";
204 s_ex += vendor.asString();
205 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
208 ITEM_OVERWRITE("vendor", vendor, a_vendors, a_vendorNames);
211 a_vendors[vendor.getId()] = vendor;
212 a_vendorNames[vendor.getName()] = getVendor(vendor.getId());
216 //------------------------------------------------------------------------------
217 //--------------------------------------------------------- Dictionary::addAvp()
218 //------------------------------------------------------------------------------
219 void Dictionary::addAvp(const Avp & avp) throw(anna::RuntimeException) {
221 const Avp * found = getAvp(avp.getId());
223 if(!a_allowUpdates) {
224 std::string s_ex = "Cannot add an avp with an existing identifier (code,vendor):\n";
225 s_ex += avp.asString();
226 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
229 ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
232 if(found = getAvp(avp.getName())) {
233 if(!a_allowUpdates) {
234 std::string s_ex = "Cannot add an avp with an existing name:\n";
235 s_ex += avp.asString();
236 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
239 ITEM_OVERWRITE("avp", avp, a_avps, a_avpNames);
242 a_avps[avp.getId()] = avp;
243 a_avpNames[avp.getName()] = getAvp(avp.getId());
247 //------------------------------------------------------------------------------
248 //----------------------------------------------------- Dictionary::addCommand()
249 //------------------------------------------------------------------------------
250 void Dictionary::addCommand(const Command & command) throw(anna::RuntimeException) {
252 const Command * found = getCommand(command.getId());
254 if(!a_allowUpdates) {
255 std::string s_ex = "Cannot add a command with an existing identifier:\n";
256 s_ex += command.asString();
257 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
260 ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
264 found = getCommand(command.getName());
266 if(!a_allowUpdates) {
267 std::string s_ex = "Cannot add a command with an existing name:\n";
268 s_ex += command.asString();
269 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
272 ITEM_OVERWRITE("command", command, a_commands, a_commandNames);
275 a_commands[command.getId()] = command;
276 a_commandNames[command.getName()] = getCommand(command.getId());
282 //------------------------------------------------------------------------------
283 //------------------------------------------------------ Dictionary::getFormat()
284 //------------------------------------------------------------------------------
285 const Format * Dictionary::getFormat(const std::string & formatName) const throw() {
286 const_format_iterator it = a_formats.find(formatName);
288 if(it != format_end()) return ((const Format *) & ((*it).second));
294 //------------------------------------------------------------------------------
295 //------------------------------------------------------ Dictionary::getVendor()
296 //------------------------------------------------------------------------------
297 const Vendor * Dictionary::getVendor(S32 vendorId) const throw() {
298 const_vendor_iterator it = a_vendors.find(vendorId);
300 if(it != vendor_end()) return ((const Vendor *) & ((*it).second));
306 //------------------------------------------------------------------------------
307 //------------------------------------------------------ Dictionary::getVendor()
308 //------------------------------------------------------------------------------
309 const Vendor * Dictionary::getVendor(const std::string & vendorName) const throw() {
310 const_vendorNames_iterator v_it = a_vendorNames.find(vendorName);
312 if(v_it != a_vendorNames.end()) return ((*v_it).second);
318 //------------------------------------------------------------------------------
319 //--------------------------------------------------------- Dictionary::getAvp()
320 //------------------------------------------------------------------------------
321 const Avp * Dictionary::getAvp(const AvpId & avpId) const throw() {
322 const_avp_iterator it = a_avps.find(avpId);
324 if(it != avp_end()) return ((const Avp *) & ((*it).second));
330 //------------------------------------------------------------------------------
331 //--------------------------------------------------------- Dictionary::getAvp()
332 //------------------------------------------------------------------------------
333 const Avp * Dictionary::getAvp(const std::string & avpName) const throw() {
334 const_avpNames_iterator a_it = a_avpNames.find(avpName);
336 if(a_it != a_avpNames.end()) return ((*a_it).second);
342 //------------------------------------------------------------------------------
343 //----------------------------------------------------- Dictionary::getCommand()
344 //------------------------------------------------------------------------------
345 const Command * Dictionary::getCommand(const CommandId & commandId) const throw() {
346 const_command_iterator it = a_commands.find(commandId);
348 if(it != command_end()) return ((const Command *) & ((*it).second));
354 //------------------------------------------------------------------------------
355 //----------------------------------------------------- Dictionary::getCommand()
356 //------------------------------------------------------------------------------
357 const Command * Dictionary::getCommand(const std::string & commandName) const throw() {
358 const_commandNames_iterator c_it = a_commandNames.find(commandName);
360 if(c_it != a_commandNames.end()) return ((*c_it).second);
366 //------------------------------------------------------------------------------
367 //------------------------------------------------------- Dictionary::asString()
368 //------------------------------------------------------------------------------
369 std::string Dictionary::asString(void) const throw() {
370 std::string trace, title;
372 anna::functions::TextHighlightMode::_v thm = anna::functions::TextHighlightMode::LeftAndRightline;
373 trace += anna::functions::highlight("Name", thm);
374 trace += a_name; trace += "\n";
375 const_format_iterator f_it;
376 const_vendor_iterator v_it;
377 const_avp_iterator a_it;
378 const_command_iterator c_it;
382 //title = "Formats (";
383 //title += anna::functions::entriesAsString(format_size());
385 trace += anna::functions::highlight(title, thm);
387 for(f_it = format_begin(); f_it != format_end(); f_it++) {
388 if((*f_it).second.isReserved()) continue;
390 if((*f_it).second.isRFC3588())
391 trace += "(Diameter RFC-3588 type) ";
393 trace += "(Application-specific type) ";
395 trace += (*f_it).second.asString();
402 title += anna::functions::entriesAsString(vendor_size());
404 trace += anna::functions::highlight(title, thm);
406 for(v_it = vendor_begin(); v_it != vendor_end(); v_it++) {
407 trace += (*v_it).second.asString();
414 title += anna::functions::entriesAsString(avp_size());
416 trace += anna::functions::highlight(title, thm);
418 for(a_it = avp_begin(); a_it != avp_end(); a_it++) {
419 trace += (*a_it).second.asString();
425 title = "Commands (";
426 title += anna::functions::entriesAsString(command_size());
428 trace += anna::functions::highlight(title, thm);
430 for(c_it = command_begin(); c_it != command_end(); c_it++) {
431 trace += (*c_it).second.asString();
440 //------------------------------------------------------------------------------
441 //---------------------------------------------------------- Dictionary::asXML()
442 //------------------------------------------------------------------------------
443 anna::xml::Node* Dictionary::asXML(anna::xml::Node* parent) const throw() {
444 // <!ELEMENT dictionary (format*, vendor*, avp*, command*)>
445 // <!ATTLIST dictionary name CDATA #REQUIRED>
446 anna::xml::Node* result = parent->createChild("dictionary");
447 result->createAttribute("name", a_name);
450 for(const_format_iterator it = format_begin(); it != format_end(); it++) {
451 if((*it).second.isReserved()) continue;
453 if((*it).second.isRFC3588()) continue;
455 (*it).second.asXML(result);
459 for(const_vendor_iterator it = vendor_begin(); it != vendor_end(); it++)
460 (*it).second.asXML(result);
463 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
464 if((*it).second.getFormat()->isAny()) continue; // Generic AVP not shown
466 (*it).second.asXML(result);
470 for(const_command_iterator it = command_begin(); it != command_end(); it++)
471 (*it).second.asXML(result);
478 //------------------------------------------------------------------------------
479 //---------------------------------------------------- Dictionary::asXMLString()
480 //------------------------------------------------------------------------------
481 std::string Dictionary::asXMLString() const throw() {
482 anna::xml::Node root("root");
483 return anna::xml::Compiler().apply(asXML(&root));
488 ////------------------------------------------------------------------------------
489 ////----------------------------------------- Dictionary::checkUniqueIdentifiers()
490 ////------------------------------------------------------------------------------
491 //void Dictionary::checkUniqueIdentifiers(const anna::xml::Node *rootNode) const throw(anna::RuntimeException) {
492 // std::map < std::string/*xml ref*/, int/*dummy*/ > formats;
493 // std::map < std::string/*xml ref*/, int/*dummy*/ > vendors;
494 // std::map < std::string/*xml ref*/, int/*dummy*/ > avps;
495 // std::map < std::string/*xml ref*/, int/*dummy*/ > commands;
496 // std::string nodeName, ref;
498 // for (anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
499 // nodeName = (*it)->getName();
501 // if (nodeName == "format") {
502 // ref = (*it)->getAttribute("name")->getValue();
503 // int refs_i = formats.size(); formats[ref] = 0;
505 // if (formats.size() == refs_i) {
506 // std::string s_ex = anna::functions::asString("Repeated format name reference '%s' not allowed within the same xml dictionary", ref.c_str());
507 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
509 // } else if (nodeName == "vendor") {
510 // ref = (*it)->getAttribute("name")->getValue();
511 // int refs_i = vendors.size(); vendors[ref] = 0;
513 // if (vendors.size() == refs_i) {
514 // std::string s_ex = anna::functions::asString("Repeated vendor name reference '%s' not allowed within the same xml dictionary", ref.c_str());
515 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
517 // } else if (nodeName == "avp") {
518 // ref = (*it)->getAttribute("name")->getValue();
519 // int refs_i = avps.size(); avps[ref] = 0;
521 // if (avps.size() == refs_i) {
522 // std::string s_ex = anna::functions::asString("Repeated avp name reference '%s' not allowed within the same xml dictionary", ref.c_str());
523 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
525 // } else if (nodeName == "command") {
526 // ref = (*it)->getAttribute("name")->getValue();
527 // int refs_i = commands.size(); commands[ref] = 0;
529 // if (commands.size() == refs_i) {
530 // std::string s_ex = anna::functions::asString("Repeated command name reference '%s' not allowed within the same xml dictionary", ref.c_str());
531 // throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
538 //------------------------------------------------------------------------------
539 //------------------------------------------------- Dictionary::extractFormats()
540 //------------------------------------------------------------------------------
541 void Dictionary::extractFormats(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
544 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
545 std::string nodeName = (*it)->getName();
547 if(nodeName == "format") {
549 aux.initialize(this);
551 const char * type = (*it)->getAttribute("name")->getCStringValue(); // mandatory
552 const char * parentType = (*it)->getAttribute("parent-type")->getCStringValue(); // mandatory
555 aux.setParentName(parentType /* never empty, basics registered at initialization */);
563 //------------------------------------------------------------------------------
564 //------------------------------------------------- Dictionary::extractVendors()
565 //------------------------------------------------------------------------------
566 void Dictionary::extractVendors(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
569 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
570 std::string nodeName = (*it)->getName();
572 if(nodeName == "vendor") {
574 const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
575 S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
586 //------------------------------------------------------------------------------
587 //---------------------------------------------------- Dictionary::extractAvps()
588 //------------------------------------------------------------------------------
589 void Dictionary::extractAvps(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
591 const anna::xml::Node *singleNode, *groupedNode;
593 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
594 std::string nodeName = (*it)->getName();
596 if(nodeName == "avp") {
598 auxAvp.initialize(this);
600 const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
601 S32 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
602 const anna::xml::Attribute *vendor_name = (*it)->getAttribute("vendor-name", anna::Exception::Mode::Ignore); // implied
603 S32 vendorCode = 0; /* IETF by default */
606 const char * c_name = vendor_name->getCStringValue();
607 auxAvp.setVendorName(c_name);
608 const_vendorNames_iterator v_it = a_vendorNames.find(c_name);
610 if(v_it == a_vendorNames.end()) {
611 std::string s_ex = anna::functions::asString("Vendor '%s', referenced at '%s' avp definition, not found at xml", c_name, name);
612 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
615 vendorCode = ((*v_it).second)->getId();
619 auxAvp.setCode(code);
620 auxAvp.setVendorId(vendorCode);
621 auxAvp.setName(name);
622 // libxml2 doesn't support default attribute value retrieving. All default values will be replaced by #IMPLIED sintax:
623 const anna::xml::Attribute *v_bit, *m_bit, *p_bit, *may_encript;
624 v_bit = (*it)->getAttribute("v-bit", anna::Exception::Mode::Ignore);
625 m_bit = (*it)->getAttribute("m-bit", anna::Exception::Mode::Ignore);
626 p_bit = (*it)->getAttribute("p-bit", anna::Exception::Mode::Ignore);
627 may_encript = (*it)->getAttribute("may-encrypt", anna::Exception::Mode::Ignore);
628 auxAvp.setVbit(v_bit ? (Avp::FlagRule::asEnum(v_bit->getCStringValue())) : (Avp::FlagRule::mustnot));
629 auxAvp.setMbit(m_bit ? (Avp::FlagRule::asEnum(m_bit->getCStringValue())) : (Avp::FlagRule::may));
630 auxAvp.setPbit(p_bit ? (Avp::FlagRule::asEnum(p_bit->getCStringValue())) : (Avp::FlagRule::may));
631 auxAvp.setMayEncrypt(may_encript ? ((may_encript->getValue()) == "yes") : false);
633 // Check vendor specific bit:
634 if(vendorCode && (auxAvp.getVbit() == Avp::FlagRule::mustnot)) {
635 std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (mustnot) at '%s' avp definicion, are incompatible with non-zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str());
636 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
639 if(!vendorCode && (auxAvp.getVbit() == Avp::FlagRule::must)) {
640 std::string s_ex = anna::functions::asString("Flag rules for vendor specific bit (must) at '%s' avp definicion, are incompatible with zeroed vendor id %s", name, getVendor(vendorCode)->asString().c_str());
641 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
644 // Single or grouped:
645 singleNode = (*it)->find("single", anna::Exception::Mode::Ignore);
646 groupedNode = (*it)->find("grouped", anna::Exception::Mode::Ignore);
650 const char * formatName = singleNode->getAttribute("format-name")->getCStringValue(); // mandatory
651 const anna::xml::Attribute *_enum = singleNode->getAttribute("enum", anna::Exception::Mode::Ignore); // implied
653 const Format *format = getFormat(formatName);
656 std::string s_ex = anna::functions::asString("Format '%s', referenced at '%s' avp definition, not found at dictionary (neither xml nor RFC 3588 diameter format types)", formatName, name);
657 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
660 auxAvp.setFormatName(formatName);
663 const char *enums = _enum->getCStringValue();
665 if(!format->isEnumerated()) {
666 std::string s_ex = anna::functions::asString("Enumerated literal '%s' is not allowed for '%s' avp format", enums, formatName);
667 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
670 auxAvp.setEnums(enums);
673 for(anna::xml::Node::const_child_iterator l_it = singleNode->child_begin(); l_it != singleNode->child_end(); l_it++) {
675 std::string data = (*l_it)->getAttribute("data")->getValue(); // mandatory
676 std::string alias = (*l_it)->getAttribute("alias")->getValue(); // mandatory
678 auxAvp.addLabel(data, alias);
682 auxAvp.setFormatName(codec::Format::asText(codec::Format::Grouped));
683 // Wait for avprule insertion, because we need complete avp reference pool (*)
691 // (*) Avp rules adding:
692 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
693 std::string nodeName = (*it)->getName();
695 if(nodeName == "avp") {
697 const char * gid = (*it)->getAttribute("name")->getCStringValue(); // mandatory
699 const_avpNames_iterator a_it = a_avpNames.find(gid);
700 Avp * gavp = (Avp *)((*a_it).second);
702 if(!gavp) continue; // it could be mising (a redefinition could have removed it)
704 const Format *format = gavp->getFormat();
707 if(format->isGrouped()) {
708 AvpRule auxAvpRule(this);
709 groupedNode = (*it)->find("grouped");
711 for(anna::xml::Node::const_child_iterator r_it = groupedNode->child_begin(); r_it != groupedNode->child_end(); r_it++) {
713 std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory
714 std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory
715 const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied
717 const Avp * avp = getAvp(id);
720 std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within grouped avp '%s', not found at xml", id.c_str(), gid);
721 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
724 auxAvpRule.setAvpName(id);
725 auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
726 auxAvpRule.setQual(qual ? (qual->getValue()) : "");
727 gavp->addAvpRule(auxAvpRule);
733 // Check avp loops between grouped avps:
735 // In order to avoid loops, we could force to define grouped avps which children
736 // had been previously defined at xml file. In this way, is imposible to get a loop:
739 // A = grouped of B,C,D -> error, B unknown
740 // B = grouped of A,F -> with former definition, would become a loop
742 // But this supposes a restriction at xml configuration (specific order).
743 // The other way is an internal check: a grouped AVP won't have descendants within
744 // its ascendants. Then we will check all grouped avps in this way:
746 // 1. Searching for another grouped avps which are parents for this avp.
747 // 2. If these are children (even this avp(*)) at avp definition, then a loop is detected.
749 // Example 1: (1) Analyzing 'A', found parent 'B' / (2) 'B' is already children of 'A'
757 // (*) Example 2: (1) Analyzing 'A', found parent 'A' / (2) 'A' is already children of 'A'
763 for(const_avp_iterator it = avp_begin(); it != avp_end(); it++) {
764 const Avp & avp = (*it).second;
766 if(!((avp.getFormat())->isGrouped())) continue;
768 for(const_avp_iterator it_p = avp_begin(); it_p != avp_end(); it_p++) {
769 const Avp & avp_p = (*it_p).second;
771 if(!((avp_p.getFormat())->isGrouped())) continue;
773 if(avp_p.isChild(avp.getId())) {
774 if(avp.isChild(avp_p.getId())) {
778 s_ex = anna::functions::asString("Loop detected between grouped avps '%s' and '%s'", avp.getName().c_str(), avp_p.getName().c_str());
780 s_ex = anna::functions::asString("Loop within grouped avp '%s': cannot contain itself !!", avp.getName().c_str());
782 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
783 } // parent is children of (ref): loop !
786 } // search grouped avps (ref)
790 //------------------------------------------------------------------------------
791 //------------------------------------------------ Dictionary::extractCommands()
792 //------------------------------------------------------------------------------
793 void Dictionary::extractCommands(const anna::xml::Node *rootNode) throw(anna::RuntimeException) {
796 // (*) Avp rules adding:
797 for(anna::xml::Node::const_child_iterator it = rootNode->child_begin(); it != rootNode->child_end(); it++) {
798 std::string nodeName = (*it)->getName();
800 if(nodeName == "command") {
802 auxCommand.initialize(this);
804 const char * name = (*it)->getAttribute("name")->getCStringValue(); // mandatory
805 U24 code = (*it)->getAttribute("code")->getIntegerValue(); // mandatory
806 std::string type = (*it)->getAttribute("type")->getValue(); // mandatory
808 auxCommand.setCode(code);
809 auxCommand.setName(name);
810 auxCommand.setRequest(type == "Request");
811 AvpRule auxAvpRule(this);
813 for(anna::xml::Node::const_child_iterator r_it = (*it)->child_begin(); r_it != (*it)->child_end(); r_it++) {
815 std::string id = (*r_it)->getAttribute("id")->getValue(); // mandatory
816 std::string type = (*r_it)->getAttribute("type")->getValue(); // mandatory
817 const anna::xml::Attribute *qual = (*r_it)->getAttribute("qual", anna::Exception::Mode::Ignore); // implied
819 const Avp * avp = getAvp(id);
822 std::string s_ex = anna::functions::asString("Avp '%s', referenced at avp rule definition within command '%s', not found at xml", id.c_str(), name);
823 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
826 auxAvpRule.setAvpName(id);
827 auxAvpRule.setPresence(AvpRule::Presence::asEnum(type));
828 auxAvpRule.setQual(qual ? (qual->getValue()) : "");
829 auxCommand.addAvpRule(auxAvpRule);
833 addCommand(auxCommand);
839 //------------------------------------------------------------------------------
840 //----------------------------------------------------------- Dictionary::load()
841 //------------------------------------------------------------------------------
842 void Dictionary::load(const std::string & xmlPathFile) throw(anna::RuntimeException) {
843 if(xmlPathFile == "")
844 throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION);
847 std::string trace = "Loading diameter dictionary from '";
848 trace += xmlPathFile;
850 anna::Logger::debug(trace, ANNA_FILE_LOCATION);
854 anna::xml::DocumentFile xmlDocument; // has private copy constructor defined but not implemented to avoid inhenrit/copy (is very heavy)
855 const anna::xml::Node *rootNode;
856 xmlDocument.initialize(xmlPathFile.c_str()); // fail here is i/o error
857 rootNode = xmlDocument.parse(*a_dtd); // Parsing: fail here if xml violates dtd
858 a_name = rootNode->getAttribute("name")->getValue();
859 //checkUniqueIdentifiers(rootNode); // Check unique id within xml, for vendor, avp and command nodes:
860 extractFormats(rootNode); // Add formats:
861 extractVendors(rootNode); // Add vendors:
862 extractAvps(rootNode); // Add avps:
863 extractCommands(rootNode); // Add commands:
864 } catch(anna::RuntimeException& ex) {
870 LOGDEBUG(anna::Logger::debug(asString(), ANNA_FILE_LOCATION));