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/Engine.hpp>
12 #include <anna/xml/xml.hpp>
13 #include <anna/core/functions.hpp>
14 #include <anna/core/tracing/Logger.hpp>
16 #include <anna/core/functions.hpp>
26 const char *StackDTD = "\
27 <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
28 <!-- Diameter dictionary DTD -->\n\
30 <!-- <!ELEMENT dictionary (format*, vendor+, avp+, command+)> allowed empty dictionary load: diameter base protocol would be harcoded -->\n\
31 <!ELEMENT dictionary (format*, vendor*, avp*, command*)>\n\
32 <!ATTLIST dictionary name CDATA #REQUIRED>\n\
34 Dictionary definitions\n\
36 name: Dictionary name\n\
39 <!ELEMENT format EMPTY>\n\
40 <!ATTLIST format name CDATA #REQUIRED parent-type ( OctetString | Integer32 | Integer64 | Unsigned32 | Unsigned64 | Float32 | Float64 ) #REQUIRED>\n\
44 name: Format type unique name\n\
45 parent-type: Format parent type within diameter basics: OctetString, Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64\n\
48 <!ELEMENT vendor EMPTY>\n\
49 <!ATTLIST vendor name CDATA #REQUIRED code CDATA #REQUIRED>\n\
53 name: Vendor unique name\n\
54 code: Vendor numeric code\n\
57 <!ELEMENT avp (single | grouped)>\n\
58 <!ATTLIST avp name CDATA #REQUIRED code 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>\n\
62 name: Avp unique name\n\
63 code: Avp numeric code\n\
64 vendor-name: Avp vendor name with vendor-id value. Gets IETF (zero value) when missing\n\
65 may-encrypt: Avp data may be encrypted (yes, no). By default is 'no'\n\
66 v-bit: Avp vendor-specific bit rule (must, may, shouldnot, mustnot). By default is 'mustnot'\n\
67 m-bit: Avp mandatory bit rule (must, may, shouldnot, mustnot). By default is 'may'\n\
68 p-bit: Avp protected (encryption) bit rule (must, may, shouldnot, mustnot). By default is 'may'\n\
71 <!ELEMENT single (label*)>\n\
72 <!ATTLIST single format-name CDATA #REQUIRED enum CDATA #IMPLIED>\n\
74 Non-grouped avp struct\n\
76 format-name: Avp format type name (RFC3588: 'OctetString, Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64, Address, Time, UTF8String, DiameterIdentity, DiameterURI, Enumerated, IPFilterRule, QoSFilterRule' or application format data type names)\n\
77 enum: Enum values restriction for enumerated-format avp: '[i][,[j]][,[m-n]...]'\n\
80 <!ELEMENT label EMPTY>\n\
81 <!ATTLIST label data CDATA #REQUIRED alias CDATA #REQUIRED>\n\
83 Mostly used with enumerated-type avps\n\
85 data: Specific avp data\n\
86 alias: Data-linked name\n\
89 <!ELEMENT grouped (avprule+)>\n\
94 <!ELEMENT avprule EMPTY>\n\
95 <!ATTLIST avprule id CDATA #REQUIRED type (Fixed | Mandatory | Optional) #REQUIRED qual CDATA #IMPLIED>\n\
97 Avp rule definition\n\
99 id: Avp name reference. Generic AVP is harcoded with 'AVP' name\n\
100 type: Avp type (Fixed, Mandatory, Optional)\n\
101 qual: Avp qualifier: *:0-inf; x*:x-inf; *x:0-x; x*y:x-y; missing:1(Fixed, Mandatory), 0-1(Optional)\n\
104 <!ELEMENT command (avprule*)>\n\
105 <!ATTLIST command name CDATA #REQUIRED code CDATA #REQUIRED type (Request | Answer) #REQUIRED>\n\
109 name: Command unique name\n\
110 code: Command numeric code\n\
111 type: Command type (Request, Answer)\n\
121 //------------------------------------------------------------------------------
122 //------------------------------------------------------------- Engine::Engine()
123 //------------------------------------------------------------------------------
124 anna::diameter::stack::Engine::Engine(void) {
125 anna::xml::functions::initialize();
126 a_dtd.initialize(StackDTD);
130 //------------------------------------------------------------------------------
131 //------------------------------------------------------ Engine::getDictionary()
132 //------------------------------------------------------------------------------
133 const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDictionary(unsigned int stackId) const throw() {
134 const Dictionary * result = NULL;
135 const_stack_iterator it = a_stacks.find(stackId);
137 if(it != stack_end()) result = (*it).second;
143 //------------------------------------------------------------------------------
144 //----------------------------------------------------------- Engine::asString()
145 //------------------------------------------------------------------------------
146 std::string anna::diameter::stack::Engine::asString(bool all) const throw() {
150 trace = "No diameter stacks found";
152 int numberOfStacks = stack_size();
153 trace = ((numberOfStacks > 1) ? "Multi-stack " : "Mono-stack ");
154 trace += "configuration, ";
155 trace += anna::functions::entriesAsString(numberOfStacks);
159 for(const_stack_iterator it = stack_begin(); it != stack_end(); it++) {
160 std::string title = "Diameter stack id = ";
161 title += anna::functions::asString((*it).first);
162 trace += anna::functions::highlightJustify(title);
164 if(all) trace += (*it).second->asString();
165 else trace += (*it).second->getName();
176 //------------------------------------------------------------------------------
177 //------------------------------------------------- Engine::registerDictionary()
178 //------------------------------------------------------------------------------
179 anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::registerDictionary(unsigned int stackId, Dictionary *dictionary) throw(anna::RuntimeException) {
180 Dictionary * result = const_cast<Dictionary *>(getDictionary(stackId));
183 throw anna::RuntimeException("Cannot provide a NULL dictionary. It must be previously allocated", ANNA_FILE_LOCATION);
185 if(result) { // if exists, launch exception
186 throw anna::RuntimeException("Such provided stack id has already been created. Removes it before call this method", ANNA_FILE_LOCATION);
187 } else { // new stack
188 a_stacks[stackId] = dictionary; // no need for singleton destructor
189 //const_stack_iterator it = a_stacks.find(stackId);
190 //result = (Dictionary *)(*it).second;
197 //------------------------------------------------------------------------------
198 //--------------------------------------------------- Engine::createDictionary()
199 //------------------------------------------------------------------------------
200 anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::createDictionary(unsigned int stackId, const std::string & xmlPathFile) throw(anna::RuntimeException) {
201 Dictionary * result = const_cast<Dictionary *>(getDictionary(stackId));
203 if(result) // if exists, launch exception
204 throw anna::RuntimeException("Such provided stack id has already been created (note: API allows you to remove any registered stack)", ANNA_FILE_LOCATION);
206 // Register a new dictionary:
207 result = registerDictionary(stackId, new Dictionary());
209 if(xmlPathFile != "") {
211 result->load(xmlPathFile);
212 } catch(anna::RuntimeException& ex) {
222 void anna::diameter::stack::Engine::loadDictionary(const std::vector<unsigned int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) {
223 std::vector<unsigned int>::const_iterator it;
226 if(xmlPathFile == "")
227 throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION);
229 for(it = stacks.begin(); it != stacks.end(); it++) {
230 d = const_cast<Dictionary*>(getDictionary(*it));
232 if(d) d->load(xmlPathFile);
235 std::string trace = "Cannot load dictionary '";
236 trace += xmlPathFile;
237 trace += "' over stack id '";
238 trace += anna::functions::asString(*it);
239 trace += "' because it doesn't exists";
240 anna::Logger::warning(trace, ANNA_FILE_LOCATION);
246 void anna::diameter::stack::Engine::loadDictionary(const std::string & xmlPathFile) throw(anna::RuntimeException) {
249 if(xmlPathFile == "")
250 throw anna::RuntimeException("Empty xml path file provided", ANNA_FILE_LOCATION);
252 for(const_stack_iterator it = stack_begin(); it != stack_end(); it++) {
253 d = const_cast<Dictionary*>(getDictionary((*it).first));
254 d->load(xmlPathFile);
259 //------------------------------------------------------------------------------
260 //-------------------------------------------------------- Engine::removeStack()
261 //------------------------------------------------------------------------------
262 void anna::diameter::stack::Engine::removeStack(unsigned int stackId) throw() {
263 stack_iterator it = a_stacks.find(stackId);
265 if(it != stack_end()) { // if exists, clear
266 //(*it).second->clear();
268 } else { // new stack
270 std::string trace = "Cannot remove stack id '";
271 trace += anna::functions::asString(stackId);
272 trace += "' because it doesn't exists";
273 anna::Logger::warning(trace, ANNA_FILE_LOCATION);