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/Format.hpp>
11 #include <anna/diameter/stack/Avp.hpp>
12 #include <anna/diameter/functions.hpp>
13 #include <anna/diameter/stack/Dictionary.hpp>
15 #include <anna/core/functions.hpp>
16 #include <anna/xml/xml.hpp>
18 #include <anna/core/functions.hpp>
23 #include <anna/core/tracing/Logger.hpp>
26 //using namespace diameter::stack;
28 anna_assign_enum(anna::diameter::stack::Avp::FlagRule) = { "must", "may", "shouldnot", "mustnot", NULL /* list end indicator */};
30 //------------------------------------------------------------------------------
31 //------------------------------------------------------------------ Avp::~Avp()
32 //------------------------------------------------------------------------------
33 anna::diameter::stack::Avp::~Avp(void) {
37 //------------------------------------------------------------------------------
38 //--------------------------------------------------------------- Avp::isChild()
39 //------------------------------------------------------------------------------
40 bool anna::diameter::stack::Avp::isChild(const AvpId & avpId) const throw() {
41 const Format * format = getFormat();
43 if(!format->isGrouped()) return false;
45 for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
46 if(avpId == ((*it).second.getId()))
53 //------------------------------------------------------------------------------
54 //--------------------------------------------------- Avp::getFlagsDescription()
55 //------------------------------------------------------------------------------
56 std::string anna::diameter::stack::Avp::getFlagsDescription(void) const throw() {
58 trace += "V: "; trace += Avp::FlagRule::asText(a_vBit);
59 trace += ", M: "; trace += Avp::FlagRule::asText(a_mBit);
60 trace += ", P: "; trace += Avp::FlagRule::asText(a_pBit);
65 //------------------------------------------------------------------------------
66 //----------------------------------------------- Avp::getFlagRulesDescription()
67 //------------------------------------------------------------------------------
68 std::string anna::diameter::stack::Avp::getFlagRulesDescription(void) const throw() {
71 std::string s_must, s_may, s_shouldnot, s_mustnot, s_mayEncypt;
72 s_must = (a_vBit == FlagRule::must) ? "V" : "";
73 s_must += (a_mBit == FlagRule::must) ? ",M" : "";
74 s_must += (a_pBit == FlagRule::must) ? ",P" : "";
76 if(s_must == "") s_must = "-";
78 if(s_must[0] == ',') s_must.erase(0, 1);
80 s_may = (a_vBit == FlagRule::may) ? "V" : "";
81 s_may += (a_mBit == FlagRule::may) ? ",M" : "";
82 s_may += (a_pBit == FlagRule::may) ? ",P" : "";
84 if(s_may == "") s_may = "-";
86 if(s_may[0] == ',') s_may.erase(0, 1);
88 s_shouldnot = (a_vBit == FlagRule::shouldnot) ? "V" : "";
89 s_shouldnot += (a_mBit == FlagRule::shouldnot) ? ",M" : "";
90 s_shouldnot += (a_pBit == FlagRule::shouldnot) ? ",P" : "";
92 if(s_shouldnot == "") s_shouldnot = "-";
94 if(s_shouldnot[0] == ',') s_shouldnot.erase(0, 1);
96 s_mustnot = (a_vBit == FlagRule::mustnot) ? "V" : "";
97 s_mustnot += (a_mBit == FlagRule::mustnot) ? ",M" : "";
98 s_mustnot += (a_pBit == FlagRule::mustnot) ? ",P" : "";
100 if(s_mustnot == "") s_mustnot = "-";
102 if(s_mustnot[0] == ',') s_mustnot.erase(0, 1);
104 s_mayEncypt = a_mayEncrypt ? "Y" : "N";
106 if(s_must != "-") { trace += "must("; trace += s_must; trace += "), "; }
108 if(s_may != "-") { trace += "may("; trace += s_may; trace += "), "; }
110 if(s_shouldnot != "-") { trace += "shouldnot("; trace += s_shouldnot; trace += "), "; }
112 if(s_mustnot != "-") { trace += "mustnot("; trace += s_mustnot; trace += "), "; }
114 if(s_mayEncypt != "-") { trace += "mayEncypt("; trace += s_mayEncypt; trace += "), "; }
116 if(trace != "") trace.erase(trace.size() - 2, 2); // remove ', '
122 //------------------------------------------------------------------------------
123 //------------------------------------------------------------- Avp::getFormat()
124 //------------------------------------------------------------------------------
125 const anna::diameter::stack::Format * anna::diameter::stack::Avp::getFormat() const throw() {
126 return a_dictionary->getFormat(a_formatName);
130 //------------------------------------------------------------------------------
131 //-------------------------------------------------------------- Avp::asString()
132 //------------------------------------------------------------------------------
133 std::string anna::diameter::stack::Avp::asString() const throw() {
139 trace += anna::diameter::functions::avpIdAsPairString(a_id);
140 trace += "|Format: ";
141 const Format * format = getFormat();
142 trace += format->asString();
144 trace += "|FlagRules: ";
145 trace += getFlagRulesDescription();
147 if(format->isEnumerated()) {
148 trace += "|Allowed enum values: "; trace += getEnums();
151 if(format->isGrouped()) {
154 for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) {
156 std::string qual = (*it).second.getQual();
157 int NumberOfSpaces = strlen(DICTIONARY_AVPRULE_TAB) - qual.size();
159 for(int k = 0; k < NumberOfSpaces; k++) trace += " ";
161 trace += (*it).second.asString();
168 for(const_label_iterator it = label_begin(); it != label_end(); it++) {
169 trace += DICTIONARY_AVPRULE_TAB;
170 trace += (*it).second;
172 trace += (*it).first;
182 //------------------------------------------------------------------------------
183 //-------------------------------------------------------------- Avp::addLabel()
184 //------------------------------------------------------------------------------
185 void anna::diameter::stack::Avp::addLabel(const std::string & data, const std::string & alias) throw(anna::RuntimeException) {
186 const Format * format = getFormat();
188 if(format->isGrouped())
189 throw anna::RuntimeException("Cannot add 'data-alias' entry on a grouped Avp", ANNA_FILE_LOCATION);
191 a_labels[data] = alias;
195 if(format->isEnumerated() && !allowEnum(atoi(data.c_str()))) {
196 anna::Logger::warning(anna::functions::asString("Makes no sense adding alias '%s' for enum value '%s' out of range ('%s'), Avp '%s'",
197 alias.c_str(), data.c_str(), getEnums(), a_name.c_str()), ANNA_FILE_LOCATION);
203 //------------------------------------------------------------------------------
204 //------------------------------------------------------------ Avp::addAvpRule()
205 //------------------------------------------------------------------------------
206 void anna::diameter::stack::Avp::addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException) {
207 const Format * format = getFormat();
209 if(format->isGrouped()) {
210 if(avpRule.isFixed()) {
211 if(!a_allowFixedRule) {
212 std::string s_ex = anna::functions::asString("Incorrect position for fixed avp rule '<%s>' within grouped avp '%s'", avpRule.getAvpName().c_str(), getName().c_str());
213 s_ex += ". Fixed avp rules must be located at the beginning";
214 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
216 } else a_allowFixedRule = false;
218 //a_avprules[avpRule.getId()] = avpRule;
220 // Restriction for redefinition (at this same level) of two rules for the same avp:
221 if(isChild(avpRule.getId())) {
222 std::string s_ex = anna::functions::asString("Cannot add two rules for avp '%s', at the same level within grouped avp '%s'", avpRule.getAvpName().c_str(), getName().c_str());
223 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
226 a_avprules[a_avprulePosition++] = avpRule;
228 throw anna::RuntimeException("Cannot add Avp rule on non-grouped Avp", ANNA_FILE_LOCATION);
232 //------------------------------------------------------------------------------
233 //----------------------------------------------------------------- Avp::asXML()
234 //------------------------------------------------------------------------------
235 anna::xml::Node* anna::diameter::stack::Avp::asXML(anna::xml::Node* parent) const throw() {
236 // <!ELEMENT avp (single | grouped)>
237 // <!ATTLIST avp name CDATA #REQUIREDcode CDATA #REQUIRED vendor-name CDATA #IMPLIED may-encrypt (yes | no) #IMPLIED v-bit (must | may | shouldnot | mustnot) #IMPLIED m-bit (must | may | shouldnot | mustnot) #IMPLIED p-bit (must | may | shouldnot | mustnot) #IMPLIED>
238 // <!ELEMENT single (label*)>
239 // <!ATTLIST single format-name CDATA #REQUIRED enum CDATA #IMPLIED>
240 // <!ELEMENT label EMPTY>
241 // <!ATTLIST label data CDATA #REQUIRED alias CDATA #REQUIRED>
242 // <!ELEMENT grouped (avprule+)>
243 anna::xml::Node* result = parent->createChild("avp");
244 result->createAttribute("name", a_name);
245 result->createAttribute("code", anna::functions::asString(a_id.first));
247 if(a_id.second != 0) result->createAttribute("vendor-name", a_vendorName);
249 result->createAttribute("may-encrypt", a_mayEncrypt ? "yes" : "no");
251 if(a_vBit != Avp::FlagRule::None) result->createAttribute("v-bit", Avp::FlagRule::asText(a_vBit));
253 if(a_mBit != Avp::FlagRule::None) result->createAttribute("m-bit", Avp::FlagRule::asText(a_mBit));
255 if(a_pBit != Avp::FlagRule::None) result->createAttribute("p-bit", Avp::FlagRule::asText(a_pBit));
257 const Format * format = getFormat();
259 if(format->isGrouped()) {
260 anna::xml::Node* grouped = result->createChild("grouped");
262 for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
263 (*it).second.asXML(grouped);
265 anna::xml::Node* single = result->createChild("single");
266 single->createAttribute("format-name", a_formatName);
268 if(format->isEnumerated()) {
269 std::string enums = getEnums();
271 if(enums != "") single->createAttribute("enum", enums);
275 anna::xml::Node* label;
277 for(const_label_iterator it = label_begin(); it != label_end(); it++) {
278 label = single->createChild("label");
279 label->createAttribute("data", (*it).first);
280 label->createAttribute("alias", (*it).second);