b79aeb1428b3b049c290b145bb19b227a317c731
[anna.git] / include / anna / diameter / codec / EngineImpl.hpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // http://redmine.teslayout.com/projects/anna-suite
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 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.
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 #ifndef anna_diameter_codec_EngineImpl_hpp
38 #define anna_diameter_codec_EngineImpl_hpp
39
40
41 // STL
42 #include <string>
43
44 #include <anna/core/RuntimeException.hpp>
45 #include <anna/xml/DTDMemory.hpp>
46 #include <anna/core/util/Recycler.hpp>
47
48 #include <anna/core/util/Component.hpp>
49 #include <anna/diameter/defines.hpp>
50
51
52 //------------------------------------------------------------------------------
53 //---------------------------------------------------------------------- #define
54 //------------------------------------------------------------------------------
55
56
57 namespace anna {
58
59 namespace diameter {
60
61 namespace stack {
62 class Dictionary;
63 }
64
65 namespace codec {
66
67 extern const char *MessageDTD;
68
69 class Message;
70 class Avp;
71
72
73 /**
74  * General component implementation of a diameter elements factory (messages, avps) and common resources which
75  *  configure encode/decode operations behaviour.
76  *
77  * Standard inheritance is done over codec::Engine, allocating basic Avp and Message classes.
78  * A child implementation could manage complex Avp classes with new data-part formats. Grouped ones could
79  *  allocate new complex Avps through such engine which knows how to allocate this special Avp's (also for
80  *  complex Message classes with application-specific setters and getters as credit-control related avps,
81  *  or some another context items). For example helpers for TME scope stands for a new engine component
82  *  called tme::Engine, allocating tme::Avp and tme::Message classes which support three new Avp formats:
83  *  ISDNNumber, ISDNAddress and Unsigned16. Anyway, main Message/Avp and Engine classes stand for all contexts
84  *  included in anna::diameter, that is to say, whole contexts (at the time only TME) will be included in future
85  *  when needed apart from the independent namespace version. Thank to this, single threaded applications could
86  *  use whole engine in a easy way.
87  *
88  * Usually an engine component is associated to a single diameter stack, although single threaded processes could
89  *  use a common engine alternating different stack dictionaries by mean #setDictionary, depending on which kind of
90  *  messages are being analyzed. Although the application must ensure that a single dictionary is activated during
91  *  the same context operations an Avp could be considered as Unknown if was created with another, and we could
92  *  have validation problems (i.e. if mandatory Avp bit is enabled). In general, managing Unknown data-part format
93  *  don't have to be a problem because it is interpreted as OctetString format. Depending on what setters/getters
94  *  we use, it could reach a RuntimeException at our application.
95  *
96  * At multithread processes we must use one heir engine per stack and never switching stacks within same component.
97  * We will use each engine for each context.
98  *
99  * It is recommended to use Message class to create Avps (adding them through pair identification <code + vendor-id>
100  *  prototype), but we could create Avps separately (other program section, i.e) and join them after:
101  *
102  * <pre>
103  * 1. Recommended way:
104  *
105  *    // Message creation:
106  *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer);
107  *    // Adding + creation:
108  *    Avp * avp_sid = msg->addAvp(helpers::base::AVPID__Session_Id);
109  *    Avp * avp_oh = msg->addAvp(helpers::base::AVPID__Origin_Host);
110  *    Avp * avp_or = msg->addAvp(helpers::base::AVPID__Origin_Realm);
111  *    Avp * avp_rc = msg->addAvp(helpers::base::AVPID__Result_Code);
112  *    // Setting data:
113  *    avp_sid->getUTF8String()->setValue("grump.example.com:33041;23432;893;0AF3B81");
114  *    ...
115  *
116  * 2. External Avp creation:
117  *
118  *    // Message creation:
119  *    Message * msg = new Message(helpers::base::COMMANDID__Re_Auth_Answer);
120  *    // Creation:
121  *    Avp * avp_sid = new Avp(helpers::base::AVPID__Session_Id);
122  *    Avp * avp_oh = new Avp(helpers::base::AVPID__Origin_Host);
123  *    Avp * avp_or = new Avp(helpers::base::AVPID__Origin_Realm);
124  *    Avp * avp_rc = new Avp(helpers::base::AVPID__Result_Code);
125  *    // Adding:
126  *    msg->addAvp(avp_sid);
127  *    msg->addAvp(avp_oh);
128  *    msg->addAvp(avp_or);
129  *    msg->addAvp(avp_rc);
130  *    // Setting data:
131  *    avp_sid->getUTF8String()->setValue("grump.example.com:33041;23432;893;0AF3B81");
132  *    ...
133  *
134  * The main difference is that Avps created through Message (or through grouped Avps) are internally allocated
135  *  through engine which normally implements a recycler to optimize memory use.
136  * </pre>
137  *
138  *
139  * Implementation example:
140  *
141  *  \code
142  *
143  *     class MyEngine : public EngineImpl {
144  *     public:
145  *        Engine (getClassName()) {;}
146  *        static const char* getClassName() throw() { return "<full-naming path>::MyEngine"; }
147  *
148  *     private:
149  *        anna::Recycler<MyAvp> a_avps;
150  *        anna::Recycler<MyMessage> a_messages;
151  *
152  *        anna::diameter::codec::Avp* allocateAvp () throw () { return a_avps.create (); }
153  *
154  *        void releaseAvp (anna::diameter::codec::Avp* avp) throw () {
155  *             if (avp == NULL) return;
156  *             MyAvp* aux = static_cast <MyAvp*> (avp);
157  *             aux->clear(); // free internal data-part storage specially for grouped avps which will release its childrens
158  *             a_avps.release (aux);
159  *        }
160  *
161  *        anna::diameter::codec::Message* allocateMessage () throw () { return a_messages.create (); }
162  *
163  *        void releaseMessage (anna::diameter::codec::Message* message) throw () {
164  *             if (message == NULL) return;
165  *             MyMessage* aux = static_cast <MyMessage*> (message);
166  *             aux->clear(); // free internal data-part storage specially for childrens releasing
167  *             a_messages.release (aux);
168  *        }
169  *     };
170  *
171  *  \endcode
172  */
173 class EngineImpl : public anna::Component {
174
175 public:
176
177   /**
178    * Defines behaviour on validation procedure: complete analysis or stop at first validation error over the message (by default)
179    */
180   struct ValidationDepth { enum _v { Complete, FirstError /* default */ }; };
181
182   /**
183    * Defines behaviour mode regarding when to validate a message: before encoding, after decoding (by default), always or never
184    * Anyway validation procedure may be called at any moment (#valid)
185    */
186   struct ValidationMode { enum _v { BeforeEncoding, AfterDecoding /* default */, Always, Never /* optimization */ }; };
187
188   /**
189    * Defines behaviour mode regarding when to fix a message: before encoding (by default), after decoding, always or never.
190    * An application could add Avps in any order; the fix procedure try to adjust it regarding dictionary. I.e., fixed
191    *  Avps will be placed on first position, before mandatory and optional ones, within the message level or any
192    *  grouped Avp. Usually we need to configure fixing before encoding in order to provide flexibility to the application
193    *  during message construction, but actually, optimal mode implies disabling this procedure. Fixing after decoding will
194    *  hide any validation problem regarding Avps position at any level.
195    * Anyway fix procedure may be called at any moment (#fix)
196    */
197   struct FixMode { enum _v { BeforeEncoding /* default */, AfterDecoding, Always, Never /* optimization */ }; };
198
199
200   // Creators
201   Avp* createAvp(const AvpId *id) throw(anna::RuntimeException);
202   Message* createMessage(const CommandId *id) throw(anna::RuntimeException);
203
204
205 private:
206
207   anna::xml::DTDMemory a_dtd;
208   ValidationDepth::_v a_validationDepth;
209   ValidationMode::_v a_validationMode;
210   bool a_ignoreFlags;
211   FixMode::_v a_fixMode;
212   bool a_selectStackWithApplicationId; // default behaviour: let the user switch the stack (false for this boolean)
213
214
215   // Auxiliary
216   const stack::Dictionary * a_dictionary;
217
218   // helpers
219   static const char* asText(const ValidationDepth::_v) throw();
220   static const char* asText(const ValidationMode::_v) throw();
221   static const char* asText(const FixMode::_v) throw();
222
223 public:
224
225   /** Constructor
226       @param className Logical name for the class.
227    */
228   EngineImpl(const char* className);
229
230   /**
231    * Destructor
232    */
233   virtual ~EngineImpl() {;}
234
235
236   // setters
237   /**
238      Sets diameter dictionary loaded at stack engine. It's recommended to configure a valid dictionary
239      (if not, or NULL provided at #setDictionary, all avps will be managed as 'Unknown' format and all
240      items will need to be manually updated, i.e. message and avp flags).
241
242      @param dictionary Diameter dictionary. At single threaded processes, the same codec engine could be used with
243      different diameter dictionaries (multi-stack applications). In that case the process must switch the stack for
244      the whole decoding or enconding operation over a Message depending on the context (normally the message header
245      Application-Id is used as stack identifier). But the smart way implies inherit from this engine creating a
246      component for each diameter stack managed in the application. Inheritance is mandatory in multi-threaded processes:
247      one engine, a unique stack.
248   */
249   void setDictionary(const stack::Dictionary * dictionary) throw() { a_dictionary = dictionary; }
250
251   /**
252   * Sets diameter dictionary loaded at stack engine with the provided identifier.
253   *
254   * @param stackId Stack identifier. When missing, NULL will be returned
255   * @return Returns configured dictionary (NULL if stack id was not found)
256   */
257   const stack::Dictionary *setDictionary(unsigned int stackId) throw();
258
259
260   /**
261   * By default, the user will select the appropiate stack id depending on the context (see #setDictionary), but
262   * some applications could consider interesting automatic stack selection based on managed messages (incoming
263   * decoded ones, or built messages to be encoded). By default, on engine construction, no changes are done.
264   * Multithreaded processes should have a unique codec engine for each managed stack (then you don't have to
265   * worry about), but mono processes with multistack implementation over the same-unique engine, should activate
266   * this to have the commonly recommended way to choose the stack: using the Application-Id value.
267   *
268   * @warning do not activate in case of multithreaded applications.
269   * @param enable Activates/deactivates the stack selection from the Application-Id value within the message header.
270   */
271   void selectStackWithApplicationId (bool enable) throw() { a_selectStackWithApplicationId = enable; }
272
273   // getters
274
275   /**
276     Gets the currently configured behaviour regarding stack selection for multistack codec engines in mono thread
277     applications.
278
279     @return True if selection is done with the Application-Id. False if no selection is performed (user responsibility).
280   */
281   bool hasSelectStackWithApplicationId (void) throw() { return a_selectStackWithApplicationId; }
282
283
284   /**
285      Gets currently configured dictionary. NULL if not configured (manual encode/decode operations).
286
287      @return Returns currently configured engine dictionary
288   */
289   const stack::Dictionary *getDictionary() const throw() { return a_dictionary; }
290
291
292   /**
293    * Sets behaviour on validation procedure.
294    * \param validationDepth Behaviour on validation procedure: complete analysis or stop at first validation error over the message.
295    */
296   void setValidationDepth(const ValidationDepth::_v validationDepth)  throw() { a_validationDepth = validationDepth; }
297
298   /**
299    * Returns behaviour on on validation procedure.
300    * For practical purposes, the Failed-AVP would typically refer to the first AVP processing error that a Diameter node encounters
301    * (decoding error or validation error in this case).
302    * A complete validation depth incurs on multiple-content Failed-AVP and is perhaps useful during integration tasks.
303    *
304    * \return Behaviour on validation procedure: complete analysis or stop at first validation error over the message (by default).
305    */
306   ValidationDepth::_v getValidationDepth() const throw() { return a_validationDepth; }
307
308   /**
309    * Sets behaviour on validation procedure regarding stack flags. Actually, only AVP flags M & P are affected. The vendor bit is
310    * too important to be ignored, and there is no way to check operation flags (as request bit).
311    * By default (at engine start), flags are verified.
312    * \param ignoreFlags Validation will ignore flags.
313    */
314
315   void ignoreFlagsOnValidation(bool ignoreFlags) throw() { a_ignoreFlags = ignoreFlags; }
316
317   /**
318    * Gets behaviour on validation procedure regarding stack flags. Actually, only AVP flags M & P are affected. The vendor bit is
319    * too important to be ignored, and there is no way to check operation flags (as request bit).
320    * By default (at engine start), flags are verified.
321    * \return Validation ignore flags indicator.
322    */
323   bool ignoreFlagsOnValidation() const throw() { return a_ignoreFlags; }
324
325   /**
326    * Sets validation mode.
327    * \param validationMode Validation mode: before encoding, after decoding, always or never.
328    */
329   void setValidationMode(const ValidationMode::_v validationMode)  throw() { a_validationMode = validationMode; }
330
331   /**
332    * Returns validation mode.
333    * Before coding validation mode is perhaps useful during debugging tasks, i.e. to check answer messages built by the application
334    * during development phase.
335    * \return Validation mode: before encoding, after decoding (by default), always or never.
336    */
337   ValidationMode::_v getValidationMode() const throw() { return a_validationMode; }
338
339
340
341   /**
342    * Sets fix mode.
343    * \param fixMode Fix mode: before encoding, after decoding, always or never.
344    */
345   void setFixMode(const FixMode::_v fixMode)  throw() { a_fixMode = fixMode; }
346
347   /**
348    * Returns fix mode.
349    * \return Fix mode: before encoding (by default), after decoding, always or never.
350    */
351   FixMode::_v getFixMode() const throw() { return a_fixMode; }
352
353
354
355   /**
356      DTD document for xml message parsing
357   */
358   const anna::xml::DTDMemory & getDTD() const throw() { return a_dtd; }
359
360   /**
361   * Creates a new diameter avp assigning its identifier, using engine resources to allocate memory (recommended
362   *  recycler allocation at engine component re-implementation of allocator methods). Obviously, normal objects
363   *  creation (new) is possible.
364   *
365   * @param id Avp identifier. AVP flags will be established based on active dictionary for known avps, or
366   * uninitialized for unknown ones.
367   *
368   * @return Created avp ready to be used
369   */
370   Avp* createAvp(AvpId id) throw(anna::RuntimeException) { return createAvp(&id); }
371
372   /**
373   * Creates a new diameter avp, using engine resources to allocate memory (recommended recycler allocation at
374   *  engine component re-implementation of allocator methods). Obviously, normal objects creation (new) is possible.
375   *
376   * @return Created avp ready to be used
377   */
378   Avp* createAvp() throw(anna::RuntimeException) { return createAvp(NULL); }
379
380   /**
381   * Creates a new diameter Message assigning its identifier, using engine resources to allocate memory (recommended
382   *  recycler allocation at engine component re-implementation of allocator methods). Obviously, normal objects
383   *  creation (new) is possible.
384   *
385   * @param id Command identifier. Message flags will be established based on active dictionary for known commands,
386   *  or uninitialized for unknown ones.
387   *
388   * @return Created message ready to be used
389   */
390   Message* createMessage(CommandId id) throw(anna::RuntimeException) { return createMessage(&id); }
391
392   /**
393   * Creates a new diameter message, using engine resources to allocate memory (recommended recycler allocation
394   *  at engine component re-implementation of allocator methods). Obviously, normal objects creation (new) is possible.
395   *
396   * @return Created message ready to be used
397   */
398   Message* createMessage() throw(anna::RuntimeException) { return createMessage(NULL); }
399
400
401   /**
402      Loads an xml file representing a diameter message base in a DTD document (#getDTD)
403
404      @param xmlPathFile Complete path file to the xml document which represents the diameter message
405   */
406   Message *createMessage(const std::string & xmlPathFile) throw(anna::RuntimeException);
407
408
409   /**
410      Invoked to free Avps.
411      \see anna::Recycler
412   */
413   virtual void releaseAvp(Avp*) throw() = 0;
414
415   /**
416      Invoked to free Messages.
417      \see anna::Recycler
418   */
419   virtual void releaseMessage(Message*) throw() = 0;
420
421
422   /**
423   * Class string representation
424   *
425   * @return String with class content
426   */
427   virtual std::string asString(void) const throw();
428
429   /**
430      Class XML representation.
431      \param parent XML node over which we will put instance information.
432      \return XML documentcon with class content.
433   */
434   virtual anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
435
436
437   /**
438      Gets the Avp identifier providing its logical name at engine dictionary
439
440      @param name Name of the Avp at engine dictionary
441
442      @return Avp identifier as pair (code,vendor-id)
443   */
444   AvpId avpIdForName(const char * name) throw(anna::RuntimeException);
445
446
447   /**
448      Gets the Command identifier providing its logical name at engine dictionary
449
450      @param name Name of the Command at engine dictionary
451
452      @return Command identifier as pair (code,request-indicator)
453   */
454   CommandId commandIdForName(const char * name) throw(anna::RuntimeException);
455
456
457 protected:
458
459   /**
460      Avp allocator method.
461
462      It is recommended to use anna::Recycler for Avps creation/releasing.
463
464      \see anna::Recycler
465   */
466   virtual Avp* allocateAvp() throw() = 0;
467
468
469   /**
470      Message allocator method.
471
472      It is recommended to use anna::Recycler for Message creation/releasing.
473
474      \see anna::Recycler
475   */
476   virtual Message* allocateMessage() throw() = 0;
477
478
479   /**
480      Manages warning trace or exception on validation anomaly depending on ValidationDepth configuration
481      ('complete' and 'first error' reports respectively).
482
483      @description Anomaly description used in trace or exception
484
485      @see setValidationDepth
486      @see getValidationDepth
487   */
488   void validationAnomaly(const std::string & description) const throw(anna::RuntimeException);
489 };
490
491 }
492 }
493 }
494
495 #endif
496