First commit
[anna.git] / source / diameter / stack / Avp.cpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
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
16 // distribution.
17 //     * Neither the name of Google Inc. 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.
20 //
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.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 // Includes propios
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>
42
43 #include <anna/core/functions.hpp>
44 #include <anna/xml/xml.hpp>
45
46 #include <anna/core/functions.hpp>
47
48 // STL
49 #include <string>
50
51 #include <anna/core/tracing/Logger.hpp>
52
53
54 //using namespace diameter::stack;
55
56 anna_assign_enum(anna::diameter::stack::Avp::FlagRule) = { "must", "may", "shouldnot", "mustnot", NULL /* list end indicator */};
57
58 //------------------------------------------------------------------------------
59 //------------------------------------------------------------------ Avp::~Avp()
60 //------------------------------------------------------------------------------
61 anna::diameter::stack::Avp::~Avp(void) {
62 }
63
64
65 //------------------------------------------------------------------------------
66 //--------------------------------------------------------------- Avp::isChild()
67 //------------------------------------------------------------------------------
68 bool anna::diameter::stack::Avp::isChild(const AvpId & avpId) const throw() {
69   const Format * format = getFormat();
70
71   if(!format->isGrouped()) return false;
72
73   for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
74     if(avpId == ((*it).second.getId()))
75       return true;
76
77   return false;
78 }
79
80
81 //------------------------------------------------------------------------------
82 //--------------------------------------------------- Avp::getFlagsDescription()
83 //------------------------------------------------------------------------------
84 std::string anna::diameter::stack::Avp::getFlagsDescription(void) const throw() {
85   std::string trace;
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);
89   return (trace);
90 }
91
92
93 //------------------------------------------------------------------------------
94 //----------------------------------------------- Avp::getFlagRulesDescription()
95 //------------------------------------------------------------------------------
96 std::string anna::diameter::stack::Avp::getFlagRulesDescription(void) const throw() {
97   std::string trace;
98   // Flag Rules:
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" : "";
103
104   if(s_must == "") s_must = "-";
105
106   if(s_must[0] == ',') s_must.erase(0, 1);
107
108   s_may = (a_vBit == FlagRule::may) ? "V" : "";
109   s_may += (a_mBit == FlagRule::may) ? ",M" : "";
110   s_may += (a_pBit == FlagRule::may) ? ",P" : "";
111
112   if(s_may == "") s_may = "-";
113
114   if(s_may[0] == ',') s_may.erase(0, 1);
115
116   s_shouldnot = (a_vBit == FlagRule::shouldnot) ? "V" : "";
117   s_shouldnot += (a_mBit == FlagRule::shouldnot) ? ",M" : "";
118   s_shouldnot += (a_pBit == FlagRule::shouldnot) ? ",P" : "";
119
120   if(s_shouldnot == "") s_shouldnot = "-";
121
122   if(s_shouldnot[0] == ',') s_shouldnot.erase(0, 1);
123
124   s_mustnot = (a_vBit == FlagRule::mustnot) ? "V" : "";
125   s_mustnot += (a_mBit == FlagRule::mustnot) ? ",M" : "";
126   s_mustnot += (a_pBit == FlagRule::mustnot) ? ",P" : "";
127
128   if(s_mustnot == "") s_mustnot = "-";
129
130   if(s_mustnot[0] == ',') s_mustnot.erase(0, 1);
131
132   s_mayEncypt = a_mayEncrypt ? "Y" : "N";
133
134   if(s_must != "-") { trace += "must("; trace += s_must; trace += "), "; }
135
136   if(s_may != "-") { trace += "may("; trace += s_may; trace += "), "; }
137
138   if(s_shouldnot != "-") { trace += "shouldnot("; trace += s_shouldnot; trace += "), "; }
139
140   if(s_mustnot != "-") { trace += "mustnot("; trace += s_mustnot; trace += "), "; }
141
142   if(s_mayEncypt != "-") { trace += "mayEncypt("; trace += s_mayEncypt; trace += "), "; }
143
144   if(trace != "") trace.erase(trace.size() - 2, 2);  // remove ', '
145
146   return (trace);
147 }
148
149
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);
155 }
156
157
158 //------------------------------------------------------------------------------
159 //-------------------------------------------------------------- Avp::asString()
160 //------------------------------------------------------------------------------
161 std::string anna::diameter::stack::Avp::asString() const throw() {
162   std::string trace;
163   //trace = "Avp '";
164   trace = "'";
165   trace += a_name;
166   trace += "'";
167   trace += anna::diameter::functions::avpIdAsPairString(a_id);
168   trace += "|Format: ";
169   const Format * format = getFormat();
170   trace += format->asString();
171   // Flag Rules:
172   trace += "|FlagRules: ";
173   trace += getFlagRulesDescription();
174
175   if(format->isEnumerated()) {
176     trace += "|Allowed enum values: "; trace += getEnums();
177   }
178
179   if(format->isGrouped()) {
180     trace += "\n";
181
182     for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) {
183       // Align qualifier
184       std::string qual = (*it).second.getQual();
185       int NumberOfSpaces = strlen(DICTIONARY_AVPRULE_TAB) - qual.size();
186
187       for(register int k = 0; k < NumberOfSpaces; k++) trace += " ";
188
189       trace += (*it).second.asString();
190       trace += "\n";
191     }
192   } else {
193     if(hasAliases()) {
194       trace += "\n";
195
196       for(const_label_iterator it = label_begin(); it != label_end(); it++) {
197         trace += DICTIONARY_AVPRULE_TAB;
198         trace += (*it).second;
199         trace += " (";
200         trace += (*it).first;
201         trace += ")\n";
202       }
203     }
204   }
205
206   return (trace);
207 }
208
209
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();
215
216   if(format->isGrouped())
217     throw anna::RuntimeException("Cannot add 'data-alias' entry on a grouped Avp", ANNA_FILE_LOCATION);
218   else
219     a_labels[data] = alias;
220
221   LOGWARNING(
222
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);
226   }
227   );
228 }
229
230
231 //------------------------------------------------------------------------------
232 //------------------------------------------------------------ Avp::addAvpRule()
233 //------------------------------------------------------------------------------
234 void anna::diameter::stack::Avp::addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException) {
235   const Format * format = getFormat();
236
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);
243       }
244     } else a_allowFixedRule = false;
245
246     //a_avprules[avpRule.getId()] = avpRule;
247
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);
252     }
253
254     a_avprules[a_avprulePosition++] = avpRule;
255   } else
256     throw anna::RuntimeException("Cannot add Avp rule on non-grouped Avp", ANNA_FILE_LOCATION);
257 }
258
259
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));
274
275   if(a_id.second != 0) result->createAttribute("vendor-name", a_vendorName);
276
277   result->createAttribute("may-encrypt", a_mayEncrypt ? "yes" : "no");
278
279   if(a_vBit != Avp::FlagRule::None) result->createAttribute("v-bit", Avp::FlagRule::asText(a_vBit));
280
281   if(a_mBit != Avp::FlagRule::None) result->createAttribute("m-bit", Avp::FlagRule::asText(a_mBit));
282
283   if(a_pBit != Avp::FlagRule::None) result->createAttribute("p-bit", Avp::FlagRule::asText(a_pBit));
284
285   const Format * format = getFormat();
286
287   if(format->isGrouped()) {
288     anna::xml::Node* grouped = result->createChild("grouped");
289
290     for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
291       (*it).second.asXML(grouped);
292   } else {
293     anna::xml::Node* single = result->createChild("single");
294     single->createAttribute("format-name", a_formatName);
295
296     if(format->isEnumerated()) {
297       single->createAttribute("enum", getEnums());
298     }
299
300     if(hasAliases()) {
301       anna::xml::Node* label;
302
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);
307       }
308     }
309   }
310
311   return result;
312 }
313