Fix local server for multiple applications
[anna.git] / stack / Avp.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
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 //
7
8
9 // Includes propios
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>
14
15 #include <anna/core/functions.hpp>
16 #include <anna/xml/xml.hpp>
17
18 #include <anna/core/functions.hpp>
19
20 // STL
21 #include <string>
22
23 #include <anna/core/tracing/Logger.hpp>
24
25
26 //using namespace diameter::stack;
27
28 anna_assign_enum(anna::diameter::stack::Avp::FlagRule) = { "must", "may", "shouldnot", "mustnot", NULL /* list end indicator */};
29
30 //------------------------------------------------------------------------------
31 //------------------------------------------------------------------ Avp::~Avp()
32 //------------------------------------------------------------------------------
33 anna::diameter::stack::Avp::~Avp(void) {
34 }
35
36
37 //------------------------------------------------------------------------------
38 //--------------------------------------------------------------- Avp::isChild()
39 //------------------------------------------------------------------------------
40 bool anna::diameter::stack::Avp::isChild(const AvpId & avpId) const throw() {
41   const Format * format = getFormat();
42
43   if(!format->isGrouped()) return false;
44
45   for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
46     if(avpId == ((*it).second.getId()))
47       return true;
48
49   return false;
50 }
51
52
53 //------------------------------------------------------------------------------
54 //--------------------------------------------------- Avp::getFlagsDescription()
55 //------------------------------------------------------------------------------
56 std::string anna::diameter::stack::Avp::getFlagsDescription(void) const throw() {
57   std::string trace;
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);
61   return (trace);
62 }
63
64
65 //------------------------------------------------------------------------------
66 //----------------------------------------------- Avp::getFlagRulesDescription()
67 //------------------------------------------------------------------------------
68 std::string anna::diameter::stack::Avp::getFlagRulesDescription(void) const throw() {
69   std::string trace;
70   // Flag Rules:
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" : "";
75
76   if(s_must == "") s_must = "-";
77
78   if(s_must[0] == ',') s_must.erase(0, 1);
79
80   s_may = (a_vBit == FlagRule::may) ? "V" : "";
81   s_may += (a_mBit == FlagRule::may) ? ",M" : "";
82   s_may += (a_pBit == FlagRule::may) ? ",P" : "";
83
84   if(s_may == "") s_may = "-";
85
86   if(s_may[0] == ',') s_may.erase(0, 1);
87
88   s_shouldnot = (a_vBit == FlagRule::shouldnot) ? "V" : "";
89   s_shouldnot += (a_mBit == FlagRule::shouldnot) ? ",M" : "";
90   s_shouldnot += (a_pBit == FlagRule::shouldnot) ? ",P" : "";
91
92   if(s_shouldnot == "") s_shouldnot = "-";
93
94   if(s_shouldnot[0] == ',') s_shouldnot.erase(0, 1);
95
96   s_mustnot = (a_vBit == FlagRule::mustnot) ? "V" : "";
97   s_mustnot += (a_mBit == FlagRule::mustnot) ? ",M" : "";
98   s_mustnot += (a_pBit == FlagRule::mustnot) ? ",P" : "";
99
100   if(s_mustnot == "") s_mustnot = "-";
101
102   if(s_mustnot[0] == ',') s_mustnot.erase(0, 1);
103
104   s_mayEncypt = a_mayEncrypt ? "Y" : "N";
105
106   if(s_must != "-") { trace += "must("; trace += s_must; trace += "), "; }
107
108   if(s_may != "-") { trace += "may("; trace += s_may; trace += "), "; }
109
110   if(s_shouldnot != "-") { trace += "shouldnot("; trace += s_shouldnot; trace += "), "; }
111
112   if(s_mustnot != "-") { trace += "mustnot("; trace += s_mustnot; trace += "), "; }
113
114   if(s_mayEncypt != "-") { trace += "mayEncypt("; trace += s_mayEncypt; trace += "), "; }
115
116   if(trace != "") trace.erase(trace.size() - 2, 2);  // remove ', '
117
118   return (trace);
119 }
120
121
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);
127 }
128
129
130 //------------------------------------------------------------------------------
131 //-------------------------------------------------------------- Avp::asString()
132 //------------------------------------------------------------------------------
133 std::string anna::diameter::stack::Avp::asString() const throw() {
134   std::string trace;
135   //trace = "Avp '";
136   trace = "'";
137   trace += a_name;
138   trace += "'";
139   trace += anna::diameter::functions::avpIdAsPairString(a_id);
140   trace += "|Format: ";
141   const Format * format = getFormat();
142   trace += format->asString();
143   // Flag Rules:
144   trace += "|FlagRules: ";
145   trace += getFlagRulesDescription();
146
147   if(format->isEnumerated()) {
148     trace += "|Allowed enum values: "; trace += getEnums();
149   }
150
151   if(format->isGrouped()) {
152     trace += "\n";
153
154     for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++) {
155       // Align qualifier
156       std::string qual = (*it).second.getQual();
157       int NumberOfSpaces = strlen(DICTIONARY_AVPRULE_TAB) - qual.size();
158
159       for(int k = 0; k < NumberOfSpaces; k++) trace += " ";
160
161       trace += (*it).second.asString();
162       trace += "\n";
163     }
164   } else {
165     if(hasAliases()) {
166       trace += "\n";
167
168       for(const_label_iterator it = label_begin(); it != label_end(); it++) {
169         trace += DICTIONARY_AVPRULE_TAB;
170         trace += (*it).second;
171         trace += " (";
172         trace += (*it).first;
173         trace += ")\n";
174       }
175     }
176   }
177
178   return (trace);
179 }
180
181
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();
187
188   if(format->isGrouped())
189     throw anna::RuntimeException("Cannot add 'data-alias' entry on a grouped Avp", ANNA_FILE_LOCATION);
190   else
191     a_labels[data] = alias;
192
193   LOGWARNING(
194
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);
198   }
199   );
200 }
201
202
203 //------------------------------------------------------------------------------
204 //------------------------------------------------------------ Avp::addAvpRule()
205 //------------------------------------------------------------------------------
206 void anna::diameter::stack::Avp::addAvpRule(const AvpRule & avpRule) throw(anna::RuntimeException) {
207   const Format * format = getFormat();
208
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);
215       }
216     } else a_allowFixedRule = false;
217
218     //a_avprules[avpRule.getId()] = avpRule;
219
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);
224     }
225
226     a_avprules[a_avprulePosition++] = avpRule;
227   } else
228     throw anna::RuntimeException("Cannot add Avp rule on non-grouped Avp", ANNA_FILE_LOCATION);
229 }
230
231
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));
246
247   if(a_id.second != 0) result->createAttribute("vendor-name", a_vendorName);
248
249   result->createAttribute("may-encrypt", a_mayEncrypt ? "yes" : "no");
250
251   if(a_vBit != Avp::FlagRule::None) result->createAttribute("v-bit", Avp::FlagRule::asText(a_vBit));
252
253   if(a_mBit != Avp::FlagRule::None) result->createAttribute("m-bit", Avp::FlagRule::asText(a_mBit));
254
255   if(a_pBit != Avp::FlagRule::None) result->createAttribute("p-bit", Avp::FlagRule::asText(a_pBit));
256
257   const Format * format = getFormat();
258
259   if(format->isGrouped()) {
260     anna::xml::Node* grouped = result->createChild("grouped");
261
262     for(const_avprule_iterator it = avprule_begin(); it != avprule_end(); it++)
263       (*it).second.asXML(grouped);
264   } else {
265     anna::xml::Node* single = result->createChild("single");
266     single->createAttribute("format-name", a_formatName);
267
268     if(format->isEnumerated()) {
269       std::string enums = getEnums();
270
271       if(enums != "") single->createAttribute("enum", enums);
272     }
273
274     if(hasAliases()) {
275       anna::xml::Node* label;
276
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);
281       }
282     }
283   }
284
285   return result;
286 }
287