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/Format.hpp>
39 #include <anna/diameter/stack/Avp.hpp>
40 #include <anna/diameter/functions.hpp>
41 #include <anna/diameter/stack/Dictionary.hpp>
43 #include <anna/core/functions.hpp>
44 #include <anna/xml/xml.hpp>
46 #include <anna/core/functions.hpp>
51 #include <anna/core/tracing/Logger.hpp>
54 //using namespace diameter::stack;
56 anna_assign_enum(anna::diameter::stack::Avp::FlagRule) = { "must", "may", "shouldnot", "mustnot", NULL /* list end indicator */};
58 //------------------------------------------------------------------------------
59 //------------------------------------------------------------------ Avp::~Avp()
60 //------------------------------------------------------------------------------
61 anna::diameter::stack::Avp::~Avp(void) {
65 //------------------------------------------------------------------------------
66 //--------------------------------------------------------------- Avp::isChild()
67 //------------------------------------------------------------------------------
68 bool anna::diameter::stack::Avp::isChild(const AvpId & avpId) const throw() {
69 const Format * format = getFormat();
71 if(!format->isGrouped()) return false;
73 for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
74 if(avpId == ((*it).second.getId()))
81 //------------------------------------------------------------------------------
82 //--------------------------------------------------- Avp::getFlagsDescription()
83 //------------------------------------------------------------------------------
84 std::string anna::diameter::stack::Avp::getFlagsDescription(void) const throw() {
86 trace += "V: "; trace += Avp::FlagRule::asText(a_vBit);
87 trace += ", M: "; trace += Avp::FlagRule::asText(a_mBit);
88 trace += ", P: "; trace += Avp::FlagRule::asText(a_pBit);
93 //------------------------------------------------------------------------------
94 //----------------------------------------------- Avp::getFlagRulesDescription()
95 //------------------------------------------------------------------------------
96 std::string anna::diameter::stack::Avp::getFlagRulesDescription(void) const throw() {
99 std::string s_must, s_may, s_shouldnot, s_mustnot, s_mayEncypt;
100 s_must = (a_vBit == FlagRule::must) ? "V" : "";
101 s_must += (a_mBit == FlagRule::must) ? ",M" : "";
102 s_must += (a_pBit == FlagRule::must) ? ",P" : "";
104 if(s_must == "") s_must = "-";
106 if(s_must[0] == ',') s_must.erase(0, 1);
108 s_may = (a_vBit == FlagRule::may) ? "V" : "";
109 s_may += (a_mBit == FlagRule::may) ? ",M" : "";
110 s_may += (a_pBit == FlagRule::may) ? ",P" : "";
112 if(s_may == "") s_may = "-";
114 if(s_may[0] == ',') s_may.erase(0, 1);
116 s_shouldnot = (a_vBit == FlagRule::shouldnot) ? "V" : "";
117 s_shouldnot += (a_mBit == FlagRule::shouldnot) ? ",M" : "";
118 s_shouldnot += (a_pBit == FlagRule::shouldnot) ? ",P" : "";
120 if(s_shouldnot == "") s_shouldnot = "-";
122 if(s_shouldnot[0] == ',') s_shouldnot.erase(0, 1);
124 s_mustnot = (a_vBit == FlagRule::mustnot) ? "V" : "";
125 s_mustnot += (a_mBit == FlagRule::mustnot) ? ",M" : "";
126 s_mustnot += (a_pBit == FlagRule::mustnot) ? ",P" : "";
128 if(s_mustnot == "") s_mustnot = "-";
130 if(s_mustnot[0] == ',') s_mustnot.erase(0, 1);
132 s_mayEncypt = a_mayEncrypt ? "Y" : "N";
134 if(s_must != "-") { trace += "must("; trace += s_must; trace += "), "; }
136 if(s_may != "-") { trace += "may("; trace += s_may; trace += "), "; }
138 if(s_shouldnot != "-") { trace += "shouldnot("; trace += s_shouldnot; trace += "), "; }
140 if(s_mustnot != "-") { trace += "mustnot("; trace += s_mustnot; trace += "), "; }
142 if(s_mayEncypt != "-") { trace += "mayEncypt("; trace += s_mayEncypt; trace += "), "; }
144 if(trace != "") trace.erase(trace.size() - 2, 2); // remove ', '
150 //------------------------------------------------------------------------------
151 //------------------------------------------------------------- Avp::getFormat()
152 //------------------------------------------------------------------------------
153 const anna::diameter::stack::Format * anna::diameter::stack::Avp::getFormat() const throw() {
154 return a_dictionary->getFormat(a_formatName);
158 //------------------------------------------------------------------------------
159 //-------------------------------------------------------------- Avp::asString()
160 //------------------------------------------------------------------------------
161 std::string anna::diameter::stack::Avp::asString() const throw() {
167 trace += anna::diameter::functions::avpIdAsPairString(a_id);
168 trace += "|Format: ";
169 const Format * format = getFormat();
170 trace += format->asString();
172 trace += "|FlagRules: ";
173 trace += getFlagRulesDescription();
175 if(format->isEnumerated()) {
176 trace += "|Allowed enum values: "; trace += getEnums();
179 if(format->isGrouped()) {
182 for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) {
184 std::string qual = (*it).second.getQual();
185 int NumberOfSpaces = strlen(DICTIONARY_AVPRULE_TAB) - qual.size();
187 for(int k = 0; k < NumberOfSpaces; k++) trace += " ";
189 trace += (*it).second.asString();
196 for(const_label_iterator it = label_begin(); it != label_end(); it++) {
197 trace += DICTIONARY_AVPRULE_TAB;
198 trace += (*it).second;
200 trace += (*it).first;
210 //------------------------------------------------------------------------------
211 //-------------------------------------------------------------- Avp::addLabel()
212 //------------------------------------------------------------------------------
213 void anna::diameter::stack::Avp::addLabel(const std::string & data, const std::string & alias) throw(anna::RuntimeException) {
214 const Format * format = getFormat();
216 if(format->isGrouped())
217 throw anna::RuntimeException("Cannot add 'data-alias' entry on a grouped Avp", ANNA_FILE_LOCATION);
219 a_labels[data] = alias;
223 if(format->isEnumerated() && !allowEnum(atoi(data.c_str()))) {
224 anna::Logger::warning(anna::functions::asString("Makes no sense adding alias '%s' for enum value '%s' out of range ('%s'), Avp '%s'",
225 alias.c_str(), data.c_str(), getEnums(), a_name.c_str()), ANNA_FILE_LOCATION);
231 //------------------------------------------------------------------------------
232 //------------------------------------------------------------ Avp::addAvpRule()
233 //------------------------------------------------------------------------------
234 void anna::diameter::stack::Avp::addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException) {
235 const Format * format = getFormat();
237 if(format->isGrouped()) {
238 if(avpRule.isFixed()) {
239 if(!a_allowFixedRule) {
240 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());
241 s_ex += ". Fixed avp rules must be located at the beginning";
242 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
244 } else a_allowFixedRule = false;
246 //a_avprules[avpRule.getId()] = avpRule;
248 // Restriction for redefinition (at this same level) of two rules for the same avp:
249 if(isChild(avpRule.getId())) {
250 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());
251 throw anna::RuntimeException(s_ex, ANNA_FILE_LOCATION);
254 a_avprules[a_avprulePosition++] = avpRule;
256 throw anna::RuntimeException("Cannot add Avp rule on non-grouped Avp", ANNA_FILE_LOCATION);
260 //------------------------------------------------------------------------------
261 //----------------------------------------------------------------- Avp::asXML()
262 //------------------------------------------------------------------------------
263 anna::xml::Node* anna::diameter::stack::Avp::asXML(anna::xml::Node* parent) const throw() {
264 // <!ELEMENT avp (single | grouped)>
265 // <!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>
266 // <!ELEMENT single (label*)>
267 // <!ATTLIST single format-name CDATA #REQUIRED enum CDATA #IMPLIED>
268 // <!ELEMENT label EMPTY>
269 // <!ATTLIST label data CDATA #REQUIRED alias CDATA #REQUIRED>
270 // <!ELEMENT grouped (avprule+)>
271 anna::xml::Node* result = parent->createChild("avp");
272 result->createAttribute("name", a_name);
273 result->createAttribute("code", anna::functions::asString(a_id.first));
275 if(a_id.second != 0) result->createAttribute("vendor-name", a_vendorName);
277 result->createAttribute("may-encrypt", a_mayEncrypt ? "yes" : "no");
279 if(a_vBit != Avp::FlagRule::None) result->createAttribute("v-bit", Avp::FlagRule::asText(a_vBit));
281 if(a_mBit != Avp::FlagRule::None) result->createAttribute("m-bit", Avp::FlagRule::asText(a_mBit));
283 if(a_pBit != Avp::FlagRule::None) result->createAttribute("p-bit", Avp::FlagRule::asText(a_pBit));
285 const Format * format = getFormat();
287 if(format->isGrouped()) {
288 anna::xml::Node* grouped = result->createChild("grouped");
290 for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
291 (*it).second.asXML(grouped);
293 anna::xml::Node* single = result->createChild("single");
294 single->createAttribute("format-name", a_formatName);
296 if(format->isEnumerated()) {
297 single->createAttribute("enum", getEnums());
301 anna::xml::Node* label;
303 for(const_label_iterator it = label_begin(); it != label_end(); it++) {
304 label = single->createChild("label");
305 label->createAttribute("data", (*it).first);
306 label->createAttribute("alias", (*it).second);