bug in RC
[anna.git] / include / anna / diameter / codec / Message.hpp
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 #ifndef anna_diameter_codec_Message_hpp
10 #define anna_diameter_codec_Message_hpp
11
12
13 // Local
14 #include <anna/config/defines.hpp>
15 #include <anna/diameter/defines.hpp>
16 #include <anna/diameter/codec/Avp.hpp>
17 #include <anna/diameter/helpers/base/defines.hpp>
18
19 #include <anna/core/DataBlock.hpp>
20 #include <anna/core/RuntimeException.hpp>
21
22 // STL
23 #include <string>
24
25 //------------------------------------------------------------------------------
26 //---------------------------------------------------------------------- #define
27 //------------------------------------------------------------------------------
28
29 namespace anna {
30 class Node;
31 }
32
33 namespace anna {
34
35 namespace diameter {
36
37 namespace stack {
38 class Dictionary;
39 class Format;
40 class Command;
41 }
42
43 namespace codec {
44
45 class Avp;
46 class Engine;
47
48 /**
49 * Diameter message generic container
50 * <pre>
51 *    RFC 3588                Diameter Based Protocol           September 2003
52 *    3.  Diameter Header
53 *
54 *       A summary of the Diameter header format is shown below.  The fields
55 *       are transmitted in network byte order.
56 *
57 *        0                   1                   2                   3
58 *        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
59 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 *       |    Version    |                 Message Length                |
61 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62 *       | command flags |                  Command-Code                 |
63 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64 *       |                         Application-ID                        |
65 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66 *       |                      Hop-by-Hop Identifier                    |
67 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68 *       |                      End-to-End Identifier                    |
69 *       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 *       |  AVPs ...
71 *       +-+-+-+-+-+-+-+-+-+-+-+-+-
72 * </pre>
73 */
74 class Message {
75
76   U8 a_version;
77   CommandId a_id;          // code and request indicator
78   U8 a_flags;
79   U32 a_applicationId;
80   U32 a_hopByHop;
81   U32 a_endToEnd;
82   avp_container a_avps; // childrens
83   find_container a_finds; // fast access for message first-level avps
84
85   // auxiliary
86   int a_insertionPositionForChilds; // used with childrens
87   anna::DataBlock a_forCode;
88
89   const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException);
90
91   // --- Developer notes ---
92   // 'AVP Length' does not include posible data padding. Thanks to this, 'Data Length'
93   // is the difference between 'AVP Length' and sum of code, length, flags and
94   // optionally the vendor-ID (all of them are 32-bit boundary), that is to say:
95   // 8 or 12 (vendor-specific avps).
96   //
97   // Grouped avps 'AVP Length' includes own headers plus the total length of all
98   //  underlying AVPs, including their headers and padding, then 'AVP Length' is
99   //  always multiple of 4 (library will check this), and smae for 'Data Length'
100   //  which is an 'whole avp Length with padding' itself.
101
102
103   // Children helpers
104
105   // Own
106   avp_iterator avp_begin() throw() { return a_avps.begin(); }
107   avp_iterator avp_end() throw() { return a_avps.end(); }
108   const_avp_iterator avp_begin() const throw() { return a_avps.begin(); }
109   const_avp_iterator avp_end() const throw() { return a_avps.end(); }
110
111   /**
112   * Gets avp total message length.
113   */
114   U24 getLength() const throw();
115
116
117   // Internal
118   bool flagsOK(int &rc) const throw(); // flags coherence regarding dictionary. Only must be called when Message is identified at the dictionary.
119   int addChild(Avp *avp) throw() { return Avp::addChild(a_avps, a_insertionPositionForChilds, avp); }
120   const anna::diameter::stack::Command *getStackCommand(CommandId id) const throw(anna::RuntimeException);
121
122   void setFailedAvp(const parent_t &parent, AvpId wrong, const char *wrongName = NULL) throw(anna::RuntimeException);
123   // During message decoding and validation, the first wrong avp is stored and all the tracking is managed to find out its
124   //  nested path for the case of grouped avps with wrong avps inside. Remember the RFC 6733, section 7.5:
125   //
126   //           In the case where the offending AVP is embedded within a Grouped AVP,
127   //           the Failed-AVP MAY contain the grouped AVP, which in turn contains
128   //           the single offending AVP.  The same method MAY be employed if the
129   //           grouped AVP itself is embedded in yet another grouped AVP and so on.
130   //           In this case, the Failed-AVP MAY contain the grouped AVP hierarchy up
131   //           to the single offending AVP.  This enables the recipient to detect
132   //           the location of the offending AVP when embedded in a group.
133   //
134   // The first wrong avp found will set the final result code, as the RFC recommends:
135   //
136   //           The value of the Result-Code AVP will provide information on the reason
137   //           for the Failed-AVP AVP.  A Diameter answer message SHOULD contain an
138   //           instance of the Failed-AVP AVP that corresponds to the error
139   //           indicated by the Result-Code AVP.  For practical purposes, this
140   //           Failed-AVP would typically refer to the first AVP processing error
141   //           that a Diameter node encounters.
142   //
143   // The message keeps the list (reverse order) of avps hierarchy (in case of grouping) for the final Failed-AVP construction,
144   // which is done at the end of decoding or validation, and only the first wrong avp is stored with its corresponding path.
145
146
147 protected:
148
149   /** Codec Engine */
150   mutable Engine *a_engine;
151
152   /** Codec Engine getter: avoids have to create base engine when using its child */
153   virtual Engine * getEngine() const throw(anna::RuntimeException);
154
155   /**
156   * Initializes Message class information.
157   * Any reimplementation must first invoke base class method.
158   */
159   virtual void initialize() throw();
160
161
162 public:
163
164   /**
165   * Default constructor
166   * @param engine Codec engine used
167   */
168   Message(Engine *engine = NULL);
169
170   /**
171   * Identified constructor
172   * @param id Command identifier as pair (code,request-indicator).
173   * @param engine Codec engine used
174   */
175   Message(CommandId id, Engine *engine = NULL);
176
177
178   /**
179   * Sets the codec engine.
180   *
181   * Once assigned (here or at constructor), this method SHALL NOT be used anymore.
182   * Also, the associated dictionary SHOULD NOT BE CHANGED through the engine,
183   * unless you know what are you doing.
184   * Setting a new different engine with different stack, even same engine where the
185   * stack has been dynamically changed, could cause a bad behaviour depending on the
186   * changes: in general, if the dictionary grows, nothing bad will happen, but if
187   * you remove or modified some elements which were processed with a certain format,
188   * will be interpreted as 'unknown' with the new dictionary, and then some problems
189   * may occur. If you add elements (vendors, avps, messages) is not a problem.
190   *
191   * IMPORTANT NOTES:
192   * 1) if you want to reuse the message, as a recommendation, you should #clear the
193   * message. In that way, next operation will adjust automatically the needed engine.
194   * 2) if you have dedicated message objects for each interface (application id), then
195   * you could set the corresponding engine on constructor (or setEngine), and forget
196   * about #clear. The needed cleanup will be done automatically from decoding and xml
197   * loading procedures, and initialized engine will be kept along message operations.
198   */
199   void setEngine(Engine *engine) throw();
200
201
202   // Length references
203   static const int HeaderLength;
204
205
206   //    Command Flags
207   //    +-+-+-+-+-+-+-+-+
208   //    |R P E T r r r r|
209   //    +-+-+-+-+-+-+-+-+
210   //
211   //      R(equest)
212   //      P(roxiable)
213   //      E(rror)
214   //      T(Potentially re-transmitted message)
215   //      r(eserved)  - these flag bits are reserved for future use, and
216   //                    MUST be set to zero, and ignored by the receiver.
217   static const U8 RBitMask;
218   static const U8 PBitMask;
219   static const U8 EBitMask;
220   static const U8 TBitMask;
221
222
223   /**
224   * Destructor
225   */
226   ~Message();
227   // Virtual destructors are useful when you can delete an instance of a derived class through a pointer to base class:
228   // This destructor is not virtual, then a pointer to base class (even pointing to a children one) will invoke this destructor, not the derived one.
229   // My current solution: virtualizing method 'clear'
230   //
231   // Recommendation:
232   // To sum up, always make base classes' destructors virtual when they're meant to be manipulated polymorphically.
233
234   // setters
235
236   /**
237      Sets the command identifier and clear the former content.
238
239      @param id Command identifier as pair (code,request-indicator).
240   */
241   void setId(CommandId id) throw(anna::RuntimeException);
242
243   /**
244      Same as #setId but providing dictionary logical name for Avp searched
245   */
246   void setId(const char *name) throw(anna::RuntimeException);
247
248   /**
249      Sets the command version. By default, messages initializes with value 1.
250
251      @param version Version provided
252   */
253   void setVersion(U8 version) throw() { a_version = version; }
254
255   /**
256      Sets/unsets P bit activation.
257      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
258
259      @param activate Activates/deactivates the bit. True by default.
260   */
261   void setProxiableBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
262
263   /**
264      Sets/unsets E bit activation.
265      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
266      This flag MUST NOT be set in request messages (in this case, it will be ignored).
267
268      @param activate Activates/deactivates the bit. True by default.
269   */
270   void setErrorBit(bool activate = true) throw() { if(isRequest()) return; if(activate) a_flags |= EBitMask; else a_flags &= (~EBitMask); }
271
272   /**
273      Sets/unsets T bit activation.
274      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
275      This flag MUST NOT be set in answer messages (in this case, it will be ignored).
276
277      @param activate Activates/deactivates the bit. True by default.
278   */
279   void setPotentiallyReTransmittedMessageBit(bool activate = true) throw() { if(isAnswer()) return; if(activate) a_flags |= TBitMask; else a_flags &= (~TBitMask); }
280
281   /**
282      Sets the message application id.
283
284      The codec engine could be configured to force a stack selection based in this field value: see #selectStackWithApplicationId.
285      In multistack applications (in case of being monothread), you only have to take care about how to apply this method: the thing
286      is that you must not interleave message builds which belongs to different stacks. For example, you could think about setting the
287      message header for message A using stack A. Then, start to add the message header fields for a second message B using another stack B.
288      Following you would add the message A avps, but then, the stack is not going to be automatically changed (this is only done through this
289      method). The result could be unexpected when adding/encoding messages with a dictionary which does not correspond.
290
291      @warning do not interleave build/encode operations between different messages which uses different stacks over the same codec engine.
292      It seems common sense, but it is not bad to advice about this.
293
294      @param aid Application-id.
295   */
296   void setApplicationId(U32 aid) throw(anna::RuntimeException);
297
298   /**
299      Sets the message hop-by-hop
300      @param hbh Hop-by-hop identifier.
301   */
302   void setHopByHop(U32 hbh) throw() { a_hopByHop = hbh; }
303
304   /**
305      Sets the message end-to-end
306      @param ete End-to-end identifier.
307   */
308   void setEndToEnd(U32 ete) throw() { a_endToEnd = ete; }
309
310
311   /**
312      Sets header to be an answer regarding provided request message code.
313      Internally, updates command identifier (indeed request flag), promotes version, application identifier, hop-by-hop and end-to-end fields.
314
315      @param request Message to be answered.
316
317      @warning Request provided must be a request, in other case method do nothing.
318   */
319   void setHeaderToAnswer(const Message &request) throw(anna::RuntimeException) {
320     if(!request.getId().second) return;
321
322     a_engine = request.getEngine(); // we know this will be
323
324     setId(CommandId(request.getId().first, !request.getId().second));
325     setVersion(request.getVersion());
326     setApplicationId(request.getApplicationId());
327     setHopByHop(request.getHopByHop()); // The same Hop-by-Hop Identifier in the request is used in the answer (RFC 6733 Section 6.2).
328     setEndToEnd(request.getEndToEnd()); // The same End-to-End Identifier in the request is used in the answer (RFC 6733 Section 6.2).
329     setProxiableBit(request.proxiableBit()); // The 'P' bit is set to the same value as the one in the request (RFC 6733 Section 6.2).
330   }
331
332
333   /**
334     Standard minimum-answer building from requests. Adds Session-Id (mirrored from request if present), Origin-Host and Origin-Realm
335     (which could be configured, extracted from optional Destination AVPs, etc.), and all the Proxy-Info AVPs (added in same order as
336     appear on the request). Of course, answer message header is built from request information through #setHeaderToAnswer. Finally,
337     message is fixed regarding dictionary elements order (#fix).
338
339     Summing up, as RFC 6733 Section 6.2, says:
340
341     <pre>
342
343         6.2.  Diameter Answer Processing
344
345            When a request is locally processed, the following procedures MUST be
346            applied to create the associated answer, in addition to any
347            additional procedures that MAY be discussed in the Diameter
348            application defining the command:
349
350            o  The same Hop-by-Hop Identifier in the request is used in the
351               answer.
352
353            o  The local host's identity is encoded in the Origin-Host AVP.
354
355            o  The Destination-Host and Destination-Realm AVPs MUST NOT be
356               present in the answer message.
357
358            o  The Result-Code AVP is added with its value indicating success or
359               failure.
360
361            o  If the Session-Id is present in the request, it MUST be included
362               in the answer.
363
364            o  Any Proxy-Info AVPs in the request MUST be added to the answer
365               message, in the same order they were present in the request.
366
367            o  The 'P' bit is set to the same value as the one in the request.
368
369            o  The same End-to-End identifier in the request is used in the
370               answer.
371
372            Note that the error messages (see Section 7) are also subjected to
373            the above processing rules.
374
375    Regarding errors, is recommended to use this over automatic answer built at #decode and/or #valid procedures, which would had added
376    Result-Code and/or Failed-AVP AVPs if proceed, but be aware of DIAMETER_COMMAND_UNSUPPORTED Result-Code, because becomes impossible
377    to fix (Session-Id SHOULD appear immediately following the Diameter header, and #fix do this manually even if no information about
378    the command structure is known, but perhaps another fixed AVPs could not comply... use #getResultCode to find out this situation before
379    using #setStandardToAnswer). Anyway, application could add another Failed-AVP content no detected internally, for example:
380    DIAMETER_CONTRADICTING_AVPS or DIAMETER_INVALID_AVP_BIT_COMBO). Also, application could add more Failed-AVP avps with other
381    wrong avps, or accumulate wrong avps inside the one and only Failed-AVP managed by the stack. The standard is open to add multiple
382    avps inside Failed-AVP or multiple Failed-AVP avps with single or multiple avps inside. This depends on application criteria regarding
383    other nodes. However, internally the Anna::diameter stack only provides one Failed-AVP with the first wrong avp found, as RFC 6733 says
384    in section 7.5.
385
386    If application decoding and/or validation operations are ok, user may search for other problems and put the appropiate Result-Code.
387    For example, DIAMETER_TOO_BUSY (3004) depends on congestion issues at business layer and cannot be decided with the only message
388    information automatically (not all the Result-Code values are taken into account, only those which correspond to anomalies managed
389    by anna::diameter::codec). Application Result-Codes could be provided in this prototype, being DIAMETER_SUCCESS the default value if missing.
390
391    </pre>
392    @param request Message to be answered.
393    @param originHost Mandatory Origin-Host diameter identity value provided by application. If answer has already an Origin-Host, this will be ignored.
394    @param originRealm Mandatory Origin-Realm diameter identity value provided by application. If answer has already an Origin-Realm, this will be ignored.
395    @param resultCode Result-Code value assigned by application. If non-success value is already assigned, this will be ignored. DIAMETER_SUCCESS is provided by default.
396
397    @warning Request provided must be a request, in other case method do nothing.
398   */
399   void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException);
400
401
402   /**
403      Sets a Result-Code AVP over an answer message (for requests, do nothing).
404      If Result-Code AVP doesn't exists, is added and then filled with the value provided.
405      If Result-Code AVP already exists, value detected is replaced if was DIAMETER_SUCCESS (non success codes are unchanged).
406      When provided value corresponds to an protocol error, that is to say within range [3001,3010], message (E)rror bit is
407      automatically activated.
408
409      This method is internally used during #decode and/or #valid procedures in order to build automatic answers, but application
410      could call this for set another Result-Code no detected by these methods within its category or for other one (application
411      layer). These are the Result-Codes implemented (detected) by ANNA::diameter::codec:
412
413      <pre>
414         Protocol Errors:
415
416            DIAMETER_COMMAND_UNSUPPORTED
417            DIAMETER_INVALID_HDR_BITS
418            DIAMETER_INVALID_AVP_BITS
419
420         Permanent Failures:
421
422            DIAMETER_AVP_UNSUPPORTED (F)
423            DIAMETER_INVALID_AVP_VALUE (F)
424            DIAMETER_MISSING_AVP (F)
425            DIAMETER_AVP_NOT_ALLOWED (F)
426            DIAMETER_AVP_OCCURS_TOO_MANY_TIMES (F)
427            DIAMETER_INVALID_BIT_IN_HEADER
428            DIAMETER_INVALID_AVP_LENGTH (F)
429            DIAMETER_INVALID_MESSAGE_LENGTH
430
431            (F) Generates Failed-AVP (also DIAMETER_CONTRADICTING_AVPS and DIAMETER_INVALID_AVP_BIT_COMBO
432                                      values does, but these are not managed by anna::diameter::codec).
433      </pre>
434
435      @param rc Result-Code value. DIAMETER_SUCCESS by default.
436   */
437   void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException);
438
439
440   /**
441      Gets the Result-Code AVP value from an answer message (for requests, returns -1).
442      If missing, -1 value is returned.
443
444      @return Result-Code value for answers, -1 for request and answers without Result-Code AVP inside
445   */
446   int getResultCode() const throw();
447
448
449   /**
450      Adds an avp child providing its identifier and reserve internal memory it.
451
452      @param id Avp identifier as pair (code,vendor-id).
453
454      @return Pointer to the new created avp.
455   */
456   Avp * addAvp(AvpId id) throw(anna::RuntimeException) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
457
458
459   /**
460      Same as #addAvp but providing dictionary logical name for Avp searched
461   */
462   Avp * addAvp(const char *name) throw(anna::RuntimeException);
463
464
465   /**
466      Adds an avp child providing a persistent pointer (must be maintained by application).
467      It is not allowed to add an avp with no codec engine configured, neither if the engine
468      is not the same.
469
470      @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned.
471      Also NULL returned for bad engine configuration.
472
473      @return Pointer to the added avp (again).
474   */
475   Avp * addAvp(Avp * avp) throw();
476
477
478   /**
479      Removes an Avp within message (first level) and free resources.
480
481      @param id Avp identifier (pair code + vendor-id).
482      @param ocurrence Order of appearance for the searched avp. Zero value means remove all avps with provided identifier at first level (no recursiveness would be allowed in the API in order to avoid unexpected behaviour).
483      Negative values could be used to reverse access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
484
485      @return Returns true if something was removed. False in other cases (including i.e. when this message is empty).
486   */
487   bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
488
489
490   /**
491      Same as #removeAvp but providing dictionary logical name for Avp searched
492   */
493   bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException);
494
495
496   /**
497   * Clears and initializes Message class information.
498   * Application must clear auxiliary message objects before adding Avps in a new context if the same object is reused.
499   * Application don't need to clear a message object before decode operation (decode invokes #clear before any other task).
500   * Any reimplementation must first invoke base class method.
501   *
502   * @param resetEngine Sets to NULL the codec engine (true, default) or respect its current value (false). If you are going
503   * to reuse the message instance it is better to clear all the information (default) to manage different stacks, because if
504   * you don't initialize the engine to NULL, the second use of the message will keep the same engine deduced from the first
505   * decoding/loading operation, which could be wrong if the second message belongs to a different application identifier.
506   */
507   virtual void clear(bool resetEngine = true) throw(anna::RuntimeException);
508
509   /**
510      Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved
511      message is valid against all odds then validation will go on). In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched
512      in a moment which depends on validation depth (codec::Engine::ValidationDepth).
513
514      You could decode multiple times over the same object. A basic cleanup is done respecting the codec engine.
515
516      @param db buffer data block processed. Before decoding, the whole message instance will be cleared (no need to invoke #clear before #decode).
517      @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation,
518      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
519      NULL because no answer is built for answers. By default, automatic answer is not built.
520   */
521   void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) throw(anna::RuntimeException);
522
523   /**
524     Fix childrens content regarding dictionary avp positions.
525     Message could remain invalid because of possible fixed/mandatory avps.
526     This is useful to give flexibility to the application during message construction before encoding or representing the data.
527     Is not recommended to fix a recently decoded message because possible validation problems will be hidden.
528   */
529   void fix() throw();
530
531   /**
532      Validates the message regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc.
533      @return Boolean indicating validation result
534      @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation,
535      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
536      NULL because no answer is built for answers. By default, automatic answer is not built.
537   */
538   bool valid(Message *ptrAnswer = NULL) const throw(anna::RuntimeException);
539
540   /**
541      Interpret xml data in order to dump over the class content.
542      You could apply this multiple times over the same object. A basic cleanup is done respecting the codec engine.
543      \param messageNode Message root node obtained from @functions::xmlFileTo
544   */
545   void fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException);
546
547   /**
548    * Interpret a xml file in order to create a diameter message
549    * You could apply this multiple times over the same object. A basic cleanup is done respecting the codec engine.
550    *
551    * @see functions::messageXmlDocumentFromXmlFile
552    * @see fromXML
553    *
554    * @param xmlPathFile Complete path file to the xml document which represents the diameter message
555    */
556   void loadXML(const std::string &xmlPathFile) throw(anna::RuntimeException);
557
558
559   // getters
560
561   /**
562      Gets Message identifier as pair (code, request indicator).
563   */
564   const CommandId & getId() const throw() { return a_id; }
565
566   /**
567      Gets the command version. By default, messages initializes with value 1.
568
569      @return version Message version
570   */
571   U8 getVersion() const throw() { return a_version; }
572
573   /**
574      Gets Message request indicator.
575   */
576   bool isRequest() const throw() { return a_id.second; }
577
578   /**
579      Gets Message answer indicator.
580   */
581   bool isAnswer() const throw() { return !isRequest(); }
582
583   /**
584      Gets the message application id
585      @return aid Application-id.
586   */
587   const U32 & getApplicationId() const throw() { return a_applicationId; }
588
589   /**
590      Gets the message hop-by-hop
591      @return hbh Hop-by-hop identifier.
592   */
593   const U32 & getHopByHop() const throw() { return a_hopByHop; }
594
595   /**
596      Gets the message end-to-end
597      @return ete End-to-end identifier.
598   */
599   const U32 & getEndToEnd() const throw() { return a_endToEnd; }
600
601   /**
602      Gets stack command (dictionary command reference).
603   */
604   const anna::diameter::stack::Command *getStackCommand() const throw(anna::RuntimeException) { return getStackCommand(a_id); }
605
606   /** Returns R bit activation state */
607   bool requestBit() const throw() { return ((a_flags & RBitMask) != 0x00); }
608
609   /** Returns P bit activation state */
610   bool proxiableBit() const throw() { return ((a_flags & PBitMask) != 0x00); }
611
612   /** Returns E bit activation state */
613   bool errorBit() const throw() { return ((a_flags & EBitMask) != 0x00); }
614
615   /** Returns T bit activation state */
616   bool potentiallyReTransmittedMessageBit() const throw() { return ((a_flags & TBitMask) != 0x00); }
617
618
619   /**
620      Access content for internal Avps. Exception mode allows different combinations like cascade access:
621      <pre>
622
623         try {
624            message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control, anna::Exception::Mode::Throw)
625                   ->getAvp(anna::diameter::helpers::base::AVP__Rating_Group, anna::Exception::Mode::Throw);
626         }
627         catch(anna::RuntimeException) {;}
628      </pre>
629
630      Or step access:
631
632      <pre>
633         const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
634         const Avp *rg;
635         if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
636      </pre>
637
638      Replacing procedures becomes easy because an Avp can be searched and its pointer reconfigured by mean #setId and data part setters.
639      Deleting procedures must use #removeAvp.
640      Access is internally cached to speed up the search operations. This cache is reset after calling #fix or #removeAvp methods.
641
642      @param id Avp identifier (pair code + vendor-id).
643      @param ocurrence Order of appearance for the searched avp. Zero position is rejected, but negative values could be used to reverse
644      access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
645      @param emode Excepcion mode handling: Ignore (no action is taken), Throw (excepcion when missing avp), Trace (trace situation as warning).
646   */
647   const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
648     return Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
649   }
650
651   Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
652     return const_cast<Avp*>(Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode));
653   }
654
655
656   /**
657      Same as #getAvp but providing dictionary logical name for Avp searched
658   */
659   const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
660     return _getAvp(name, ocurrence, emode);
661   }
662
663   Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
664     return const_cast<Avp*>(_getAvp(name, ocurrence, emode));
665   }
666
667 // Helpers
668
669   /**
670      Counts the number of ocurrences of Avps (first level) with the identifier provided
671
672      @param id Avp identifier (pair code + vendor-id).
673   */
674   int countAvp(AvpId id) const throw() { return Avp::countAvp(a_avps, id); }
675
676   /**
677      Same as #countAvp but providing dictionary logical name for Avp searched
678   */
679   int countAvp(const char *name) const throw(anna::RuntimeException);
680
681   /**
682      Counts the number of children
683
684      @param id Avp identifier (pair code + vendor-id).
685   */
686   int countChilds() const throw() { return Avp::countChilds(a_avps); }
687
688   /**
689      Encodes datablock with the class content. In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched
690      in a moment which depends on validation depth (codec::Engine::ValidationDepth). If you want to see validation errors but go on with encoding,
691      you should try/catch #valid() procedure out of #code.
692
693      @return DataBlock encoded (internal memory used)
694   */
695   const anna::DataBlock & code() throw(anna::RuntimeException);
696
697   /**
698      Class xml representation
699      \param parent Parent XML node on which hold this instance information.
700      \return XML document with relevant information for this instance.
701   */
702   anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
703
704   /**
705      Class xml string representation
706      \return XML string representation with relevant information for this instance.
707   */
708   std::string asXMLString() const throw();
709
710   /**
711      Comparison operator by mean serialization
712
713      @param m1 Instance 1 for Message class
714      @param m2 Instance 2 for Message class
715
716      @return Comparison result
717   */
718   friend bool operator == (const Message & m1, const Message & m2) throw() { return (m1.asXMLString() == m2.asXMLString()); }
719
720   /**
721      Match a regular expression (string pattern) regarding xml string serialization for this message.
722      Using a complex pattern (many avps, grouped ones) it could be necessary to fix the message before
723      using the method in order to perform a more controlled comparison. In the same way, flags could be
724      ignored to simplify message xml presentation.
725      This powerful tool could be used to program traffic analysis and decide future behaviour (routing,
726      traslation, etc.).
727
728      <pre>
729      Examples:
730
731      The pattern '<avp name="Service-Context-Id" data="(.)*32251@3gpp.org"/>' detects PS charging contexts
732      because of data suffix specification '32251@3gpp.org' for that AVP.
733
734      The pattern '<message version="1" name="Capabilities-Exchange-Request"' detects a CER message.
735
736      The pattern (string including carriage returns):
737
738      '<avp name="Subscription-Id">
739         <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
740         <avp name="Subscription-Id-Data" data="606000106"/>
741      </avp>'
742
743      detects MSISDN (not IMSI) equal to 606000106
744
745      It would seems strange or 'creative' to use regular expressions within an hex string representation,
746      but anyway you could also do such kind of things to check non-printable data parts within the message:
747      for example, the pattern '<avp name="Framed-IP-Address" hex-data="0a[A-Fa-f0-9][A-Fa-f0-9]0a0a"/>'
748      matchs IP addresses for '10.x.10.10' where x = [0..255].
749
750      Note that string pattern could also be generated via #loadXML and then #asXML, that is to say, you
751      could get patterns through xml files which act as conditional triggers over message. In that case,
752      it is not possible to specify regular expressions within xml 'hex-data' fields because parser will fail
753      during hexadecimal read. Normally only printable 'data' fields are used for matching issues.
754
755      For example, imagine a 'pattern.xml' file like:
756      <message version="1" name="Credit-Control-Request" application-id="16777236" hop-by-hop-id="0" end-by-end-id="0">
757         <avp name="Subscription-Id">
758            <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
759            <avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>
760         </avp>
761      </message>
762
763      Then you could do:
764
765      anna::diameter::codec::Message patternMessage;
766      patternMessage.loadXML("pattern.xml");
767      std::string pattern = patternMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString();
768      // Former is '<avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>'
769      bool match = incomingMessage.isLike(pattern);
770
771      Then, messages having MSISDN numbers starting with '616' will match the pattern.
772      Note, that any other message codes (and not only Credit-Control-Request ones), could pass the test...
773      You could also build that string manually:
774
775      Example 1:
776      std::string pattern = "<avp name=\"Subscription-Id\">\n";
777      pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Type\" data=\"0\" alias=\"END_USER_E164\"/>\n"
778      pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"/>"
779
780      Example 2:
781      std::string pattern = "name=\"Subscription-Id\"(.)*name=\"Subscription-Id-Type\" data=\"0\"(.)*name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"";
782      </pre>
783
784      \return Returns the match result
785   */
786   bool isLike(const std::string &pattern) const throw();
787
788
789 //friend class Engine;
790   friend class Avp;
791 };
792
793 }
794 }
795 }
796
797
798 #endif