Codec engine on Avp and Message constructors
[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   /** Sets the codec engine */
179   void setEngine(Engine *engine) throw() { a_engine = engine; }
180
181
182   // Length references
183   static const int HeaderLength;
184
185
186   //    Command Flags
187   //    +-+-+-+-+-+-+-+-+
188   //    |R P E T r r r r|
189   //    +-+-+-+-+-+-+-+-+
190   //
191   //      R(equest)
192   //      P(roxiable)
193   //      E(rror)
194   //      T(Potentially re-transmitted message)
195   //      r(eserved)  - these flag bits are reserved for future use, and
196   //                    MUST be set to zero, and ignored by the receiver.
197   static const U8 RBitMask;
198   static const U8 PBitMask;
199   static const U8 EBitMask;
200   static const U8 TBitMask;
201
202
203   /**
204   * Destructor
205   */
206   ~Message();
207   // Virtual destructors are useful when you can delete an instance of a derived class through a pointer to base class:
208   // 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.
209   // My current solution: virtualizing method 'clear'
210   //
211   // Recommendation:
212   // To sum up, always make base classes' destructors virtual when they're meant to be manipulated polymorphically.
213
214   // setters
215
216   /**
217      Sets the command identifier and clear the former content.
218
219      @param id Command identifier as pair (code,request-indicator).
220      @param _clear Message will be cleared when updating the command identifier (default behaviour).
221   */
222   void setId(CommandId id, bool _clear = true) throw(anna::RuntimeException);
223
224   /**
225      Same as #setId but providing dictionary logical name for Avp searched
226   */
227   void setId(const char *name) throw(anna::RuntimeException);
228
229   /**
230      Sets the command version. By default, messages initializes with value 1.
231
232      @param version Version provided
233   */
234   void setVersion(U8 version) throw() { a_version = version; }
235
236   /**
237      Sets/unsets P bit activation.
238      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
239
240      @param activate Activates/deactivates the bit. True by default.
241   */
242   void setProxiableBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
243
244   /**
245      Sets/unsets E bit activation.
246      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
247
248      @param activate Activates/deactivates the bit. True by default.
249   */
250   void setErrorBit(bool activate = true) throw() { if(activate) a_flags |= EBitMask; else a_flags &= (~EBitMask); }
251
252   /**
253      Sets/unsets T bit activation.
254      Application should not have to use this because dictionary information is used in order to configure flags when Message identifier is stored.
255
256      @param activate Activates/deactivates the bit. True by default.
257   */
258   void setPotentiallyReTransmittedMessageBit(bool activate = true) throw() { if(activate) a_flags |= TBitMask; else a_flags &= (~TBitMask); }
259
260   /**
261      Sets the message application id.
262
263      The codec engine could be configured to force a stack selection based in this field value: see #selectStackWithApplicationId.
264      In multistack applications (which also shall be monothreaded), you only have to take care about how to apply this method: the thing
265      is that you must not interleave message builds which belongs to different stacks. For example, you could think about setting the
266      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.
267      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
268      method). The result could be unexpected when adding/encoding messages with a dictionary which does not correspond.
269
270      @warning do not interleave build/encode operations between different messages which uses different stacks over the same codec engine.
271      It seems common sense, but it is not bad to advice about this.
272
273      @param aid Application-id.
274   */
275   void setApplicationId(U32 aid) throw();
276
277   /**
278      Sets the message hop-by-hop
279      @param hbh Hop-by-hop identifier.
280   */
281   void setHopByHop(U32 hbh) throw() { a_hopByHop = hbh; }
282
283   /**
284      Sets the message end-to-end
285      @param ete End-to-end identifier.
286   */
287   void setEndToEnd(U32 ete) throw() { a_endToEnd = ete; }
288
289
290   /**
291      Sets header to be an answer regarding provided request message code.
292      Internally, updates command identifier (indeed request flag), promotes version, application identifier, hop-by-hop and end-to-end fields.
293
294      @param request Message to be answered.
295
296      @warning Request provided must be a request, in other case method do nothing.
297   */
298   void setHeaderToAnswer(const Message &request) throw() {
299     if(!request.getId().second) return;
300
301     setId(CommandId(request.getId().first, !request.getId().second), false /* don't clear */);
302     setVersion(request.getVersion());
303     setApplicationId(request.getApplicationId());
304     setHopByHop(request.getHopByHop()); // The same Hop-by-Hop Identifier in the request is used in the answer (RFC 6733 Section 6.2).
305     setEndToEnd(request.getEndToEnd()); // The same End-to-End Identifier in the request is used in the answer (RFC 6733 Section 6.2).
306     setProxiableBit(request.proxiableBit()); // The 'P' bit is set to the same value as the one in the request (RFC 6733 Section 6.2).
307   }
308
309
310   /**
311     Standard minimum-answer building from requests. Adds Session-Id (mirrored from request if present), Origin-Host and Origin-Realm
312     (which could be configured, extracted from optional Destination AVPs, etc.), and all the Proxy-Info AVPs (added in same order as
313     appear on the request). Of course, answer message header is built from request information through #setHeaderToAnswer. Finally,
314     message is fixed regarding dictionary elements order (#fix).
315
316     Summing up, as RFC 6733 Section 6.2, says:
317
318     <pre>
319
320         6.2.  Diameter Answer Processing
321
322            When a request is locally processed, the following procedures MUST be
323            applied to create the associated answer, in addition to any
324            additional procedures that MAY be discussed in the Diameter
325            application defining the command:
326
327            o  The same Hop-by-Hop Identifier in the request is used in the
328               answer.
329
330            o  The local host's identity is encoded in the Origin-Host AVP.
331
332            o  The Destination-Host and Destination-Realm AVPs MUST NOT be
333               present in the answer message.
334
335            o  The Result-Code AVP is added with its value indicating success or
336               failure.
337
338            o  If the Session-Id is present in the request, it MUST be included
339               in the answer.
340
341            o  Any Proxy-Info AVPs in the request MUST be added to the answer
342               message, in the same order they were present in the request.
343
344            o  The 'P' bit is set to the same value as the one in the request.
345
346            o  The same End-to-End identifier in the request is used in the
347               answer.
348
349            Note that the error messages (see Section 7) are also subjected to
350            the above processing rules.
351
352    Regarding errors, is recommended to use this over automatic answer built at #decode and/or #valid procedures, which would had added
353    Result-Code and/or Failed-AVP AVPs if proceed, but be aware of DIAMETER_COMMAND_UNSUPPORTED Result-Code, because becomes impossible
354    to fix (Session-Id SHOULD appear immediately following the Diameter header, and #fix do this manually even if no information about
355    the command structure is known, but perhaps another fixed AVPs could not comply... use #getResultCode to find out this situation before
356    using #setStandardToAnswer). Anyway, application could add another Failed-AVP content no detected internally, for example:
357    DIAMETER_CONTRADICTING_AVPS or DIAMETER_INVALID_AVP_BIT_COMBO). Also, application could add more Failed-AVP avps with other
358    wrong avps, or accumulate wrong avps inside the one and only Failed-AVP managed by the stack. The standard is open to add multiple
359    avps inside Failed-AVP or multiple Failed-AVP avps with single or multiple avps inside. This depends on application criteria regarding
360    other nodes. However, internally the Anna::diameter stack only provides one Failed-AVP with the first wrong avp found, as RFC 6733 says
361    in section 7.5.
362
363    If application decoding and/or validation operations are ok, user may search for other problems and put the appropiate Result-Code.
364    For example, DIAMETER_TOO_BUSY (3004) depends on congestion issues at business layer and cannot be decided with the only message
365    information automatically (not all the Result-Code values are taken into account, only those which correspond to anomalies managed
366    by anna::diameter::codec). Application Result-Codes could be provided in this prototype, being DIAMETER_SUCCESS the default value if missing.
367
368    </pre>
369    @param request Message to be answered.
370    @param originHost Mandatory Origin-Host diameter identity value provided by application. If answer has already an Origin-Host, this will be ignored.
371    @param originRealm Mandatory Origin-Realm diameter identity value provided by application. If answer has already an Origin-Realm, this will be ignored.
372    @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.
373
374    @warning Request provided must be a request, in other case method do nothing.
375   */
376   void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw();
377
378
379   /**
380      Sets a Result-Code AVP over an answer message (for requests, do nothing).
381      If Result-Code AVP doesn't exists, is added and then filled with the value provided.
382      If Result-Code AVP already exists, value detected is replaced if was DIAMETER_SUCCESS (non success codes are unchanged).
383      When provided value corresponds to an protocol error, that is to say within range [3001,3010], message (E)rror bit is
384      automatically activated.
385
386      This method is internally used during #decode and/or #valid procedures in order to build automatic answers, but application
387      could call this for set another Result-Code no detected by these methods within its category or for other one (application
388      layer). These are the Result-Codes implemented (detected) by ANNA::diameter::codec:
389
390      <pre>
391         Protocol Errors:
392
393            DIAMETER_COMMAND_UNSUPPORTED
394            DIAMETER_INVALID_HDR_BITS
395            DIAMETER_INVALID_AVP_BITS
396
397         Permanent Failures:
398
399            DIAMETER_AVP_UNSUPPORTED (F)
400            DIAMETER_INVALID_AVP_VALUE (F)
401            DIAMETER_MISSING_AVP (F)
402            DIAMETER_AVP_NOT_ALLOWED (F)
403            DIAMETER_AVP_OCCURS_TOO_MANY_TIMES (F)
404            DIAMETER_INVALID_BIT_IN_HEADER
405            DIAMETER_INVALID_AVP_LENGTH (F)
406            DIAMETER_INVALID_MESSAGE_LENGTH
407
408            (F) Generates Failed-AVP (also DIAMETER_CONTRADICTING_AVPS and DIAMETER_INVALID_AVP_BIT_COMBO
409                                      values does, but these are not managed by anna::diameter::codec).
410      </pre>
411
412      @param rc Result-Code value. DIAMETER_SUCCESS by default.
413   */
414   void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException);
415
416
417   /**
418      Gets the Result-Code AVP value from an answer message (for requests, returns -1).
419      If missing, -1 value is returned.
420
421      @return Result-Code value for answers, -1 for request and answers without Result-Code AVP inside
422   */
423   int getResultCode() const throw();
424
425
426   /**
427      Adds an avp child providing its identifier and reserve internal memory it.
428
429      @param id Avp identifier as pair (code,vendor-id).
430
431      @return Pointer to the new created avp.
432   */
433   Avp * addAvp(AvpId id) throw(anna::RuntimeException) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
434
435
436   /**
437      Same as #addAvp but providing dictionary logical name for Avp searched
438   */
439   Avp * addAvp(const char *name) throw(anna::RuntimeException);
440
441
442   /**
443      Adds an avp child providing a persistent pointer (must be maintained by application).
444
445      @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned.
446
447      @return Pointer to the added avp (again).
448   */
449   Avp * addAvp(Avp * avp) throw() { if(!avp) return NULL; addChild(avp); return avp; }
450
451
452   /**
453      Removes an Avp within message (first level) and free resources.
454
455      @param id Avp identifier (pair code + vendor-id).
456      @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).
457      Negative values could be used to reverse access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
458
459      @return Returns true if something was removed. False in other cases (including i.e. when this message is empty).
460   */
461   bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
462
463
464   /**
465      Same as #removeAvp but providing dictionary logical name for Avp searched
466   */
467   bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException);
468
469
470   /**
471   * Clears and initializes Message class information.
472   * Application must clear auxiliary message objects before adding Avps in a new context.
473   * Application don't need to clear a message object before decode operation (decode invokes #clear before any other task).
474   * Any reimplementation must first invoke base class method.
475   */
476   virtual void clear() throw(anna::RuntimeException);
477
478   /**
479      Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved
480      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
481      in a moment which depends on validation depth (codec::Engine::ValidationDepth).
482
483      @param db buffer data block processed. Before decoding, the whole message instance will be cleared (no need to invoke #clear before #decode).
484      @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation,
485      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
486      NULL because no answer is built for answers. By default, automatic answer is not built.
487   */
488   void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) throw(anna::RuntimeException);
489
490   /**
491     Fix childrens content regarding dictionary avp positions.
492     Message could remain invalid because of possible fixed/mandatory avps.
493     This is useful to give flexibility to the application during message construction before encoding or representing the data.
494     Is not recommended to fix a recently decoded message because possible validation problems will be hidden.
495   */
496   void fix() throw();
497
498   /**
499      Validates the message regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc.
500      @return Boolean indicating validation result
501      @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation,
502      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
503      NULL because no answer is built for answers. By default, automatic answer is not built.
504   */
505   bool valid(Message *ptrAnswer = NULL) const throw(anna::RuntimeException);
506
507
508   /**
509      Interpret xml data in order to dump over the class content.
510      \param messageNode Message root node
511   */
512   void fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException);
513
514   /**
515      Interpret xml string representation in order to dump over the class content.
516      DTD validation is used in the same way that #loadXML does.
517      \param xmlString XML string representation with relevant information for this instance
518   */
519   void fromXMLString(const std::string &xmlString) throw(anna::RuntimeException);
520
521   /**
522      Loads an xml file based on this message DTD (could be accumulative, no initialization will be performed by this method).
523
524      <pre>
525      <!ELEMENT message (avp*)>
526      <!ELEMENT avp (avp*)>
527
528      <!ATTLIST message version CDATA #IMPLIED name CDATA #IMPLIED code CDATA #IMPLIED flags CDATA #IMPLIED application-id CDATA #REQUIRED hop-by-hop-id CDATA #IMPLIED end-by-end-id CDATA #IMPLIED>
529      <!--
530         version: Diameter version. Sets '1' by default
531         name:    Command name within working stack (dictionary identifier)
532
533         In order to get more coding capabilities, command code and flags could be established instead of former command name,
534          but neither of them are allowed if 'name' is provided (and vice versa):
535
536         code:    Command code
537         flags:   Command flags byte value (0-255) where standard bit set for flags is 'RPET rrrr': (R)equest, (P)roxiable, (E)rror, Potentially re-(T)ransmitted message and (r)eserved
538
539
540         application-id:   Message application id
541         hop-by-hop-id:    Message hop by hop id. Sets '0' by default
542         end-by-end-id:    Message end by end id. Sets '0' by default
543      -->
544
545      <!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
546      <!--
547         name:   Avp name within working stack (dictionary identifier)
548
549         In order to get more coding capabilities, avp code, vendor-id and flags could be established instead of former avp name,
550          but neither of them are allowed if 'name' is provided (and vice versa):
551
552         code:          Avp code
553         vendor-code:   Avp vendor code
554         flags:         Avp flags byte value (0-255) where standard bit set for flags is 'VMPr rrrr': (V)endor-specific, (M)andatory, end to end encry(P)tion and r(eserved)
555
556
557         data:          Natural string representation for avp data. Specially applicable with numbers and printable strings, but also
558                         useful for certain formats which could be easily understandable in such friendly/smart representation. We will
559                         achieve different human-readable strings depending on data format:
560
561                           [ OctetString ] (if printable, but not recommended)
562                           [ Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64 ] (normal number representation)
563                           [ Time ] (NTP timestamp, normal number representation)
564                           [ Address ] (auto detects IPv4 or IPv6 address version, then only ip address is specified: IPv4 with dots, IPv6 with colons)
565                           [ UTF8String, DiameterIdentity, DiameterURI ] (printable)
566                           [ IPFilterRule, QoSFilterRule ] (uses ASCII charset, printable)
567
568                           New application formats must define specific natural representation for internal raw data
569
570         hex-data:      Hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits). Suitable for whatever kind
571                         of diameter format, but mandatory for non printable information. OctetString usually transport non human-readable
572                         data and should better be encoded within this field although being printable. Unknown avps (which fails identifying
573                         provided name or code/vendor-code) must always use this representation.
574
575         Xml representation for decoded messages shows natural content except for 'OctetString' format and unknown avps. Anyway, when printable,
576          OctetString could show such information at data field apart from hex-data, because many implementations use this format to transport
577          readable-string data. In general, one of the data fields is mandatory except for 'Grouped' type (its data is another level of avps).
578         Application-specific formats must decide the way to represent its contents, being recommended to use a natural representation if possible,
579          because xml is read by humans with testing and monitoring purposes.
580      -->
581      </pre>
582
583      @param xmlPathFile Complete path file to the xml document which represents the diameter message
584      @see fromXMLString
585   */
586   void loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException);
587
588
589
590   // getters
591
592   /**
593      Gets Message identifier as pair (code, request indicator).
594   */
595   const CommandId & getId() const throw() { return a_id; }
596
597   /**
598      Gets the command version. By default, messages initializes with value 1.
599
600      @return version Message version
601   */
602   U8 getVersion() const throw() { return a_version; }
603
604   /**
605      Gets Message request indicator.
606   */
607   bool isRequest() const throw() { return a_id.second; }
608
609   /**
610      Gets Message answer indicator.
611   */
612   bool isAnswer() const throw() { return !isRequest(); }
613
614   /**
615      Gets the message application id
616      @return aid Application-id.
617   */
618   const U32 & getApplicationId() const throw() { return a_applicationId; }
619
620   /**
621      Gets the message hop-by-hop
622      @return hbh Hop-by-hop identifier.
623   */
624   const U32 & getHopByHop() const throw() { return a_hopByHop; }
625
626   /**
627      Gets the message end-to-end
628      @return ete End-to-end identifier.
629   */
630   const U32 & getEndToEnd() const throw() { return a_endToEnd; }
631
632   /**
633      Gets stack command (dictionary command reference).
634   */
635   const anna::diameter::stack::Command *getStackCommand() const throw(anna::RuntimeException) { return getStackCommand(a_id); }
636
637   /** Returns R bit activation state */
638   bool requestBit() const throw() { return ((a_flags & RBitMask) != 0x00); }
639
640   /** Returns P bit activation state */
641   bool proxiableBit() const throw() { return ((a_flags & PBitMask) != 0x00); }
642
643   /** Returns E bit activation state */
644   bool errorBit() const throw() { return ((a_flags & EBitMask) != 0x00); }
645
646   /** Returns T bit activation state */
647   bool potentiallyReTransmittedMessageBit() const throw() { return ((a_flags & TBitMask) != 0x00); }
648
649
650   /**
651      Access content for internal Avps. Exception mode allows different combinations like cascade access:
652      <pre>
653
654         try {
655            message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control, anna::Exception::Mode::Throw)
656                   ->getAvp(anna::diameter::helpers::base::AVP__Rating_Group, anna::Exception::Mode::Throw);
657         }
658         catch(anna::RuntimeException) {;}
659      </pre>
660
661      Or step access:
662
663      <pre>
664         const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
665         const Avp *rg;
666         if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
667      </pre>
668
669      Replacing procedures becomes easy because an Avp can be searched and its pointer reconfigured by mean #setId and data part setters.
670      Deleting procedures must use #removeAvp.
671      Access is internally cached to speed up the search operations. This cache is reset after calling #fix or #removeAvp methods.
672
673      @param id Avp identifier (pair code + vendor-id).
674      @param ocurrence Order of appearance for the searched avp. Zero position is rejected, but negative values could be used to reverse
675      access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
676      @param emode Excepcion mode handling: Ignore (no action is taken), Throw (excepcion when missing avp), Trace (trace situation as warning).
677   */
678   const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
679     return Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
680   }
681
682   Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
683     return const_cast<Avp*>(Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode));
684   }
685
686
687   /**
688      Same as #getAvp but providing dictionary logical name for Avp searched
689   */
690   const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
691     return _getAvp(name, ocurrence, emode);
692   }
693
694   Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
695     return const_cast<Avp*>(_getAvp(name, ocurrence, emode));
696   }
697
698 // Helpers
699
700   /**
701      Counts the number of ocurrences of Avps (first level) with the identifier provided
702
703      @param id Avp identifier (pair code + vendor-id).
704   */
705   int countAvp(AvpId id) const throw() { return Avp::countAvp(a_avps, id); }
706
707   /**
708      Same as #countAvp but providing dictionary logical name for Avp searched
709   */
710   int countAvp(const char *name) const throw(anna::RuntimeException);
711
712   /**
713      Counts the number of children
714
715      @param id Avp identifier (pair code + vendor-id).
716   */
717   int countChilds() const throw() { return Avp::countChilds(a_avps); }
718
719   /**
720      Encodes datablock with the class content. In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched
721      in a moment which depends on validation depth (codec::Engine::ValidationDepth). If you want to see validation errors but go on with encoding,
722      you should try/catch #valid() procedure out of #code.
723
724      @return DataBlock encoded (internal memory used)
725   */
726   const anna::DataBlock & code() throw(anna::RuntimeException);
727
728   /**
729      Class xml representation
730      \param parent Parent XML node on which hold this instance information.
731      \return XML document with relevant information for this instance.
732   */
733   anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
734
735   /**
736      Class xml string representation
737      \return XML string representation with relevant information for this instance.
738   */
739   std::string asXMLString() const throw();
740
741   /**
742      Comparison operator by mean serialization
743
744      @param m1 Instance 1 for Message class
745      @param m2 Instance 2 for Message class
746
747      @return Comparison result
748   */
749   friend bool operator == (const Message & m1, const Message & m2) throw() { return (m1.asXMLString() == m2.asXMLString()); }
750
751   /**
752      Match a regular expression (string pattern) regarding xml string serialization for this message.
753      Using a complex pattern (many avps, grouped ones) it could be necessary to fix the message before
754      using the method in order to perform a more controlled comparison. In the same way, flags could be
755      ignored to simplify message xml presentation.
756      This powerful tool could be used to program traffic analysis and decide future behaviour (routing,
757      traslation, etc.).
758
759      <pre>
760      Examples:
761
762      The pattern '<avp name="Service-Context-Id" data="(.)*32251@3gpp.org"/>' detects PS charging contexts
763      because of data suffix specification '32251@3gpp.org' for that AVP.
764
765      The pattern '<message version="1" name="Capabilities-Exchange-Request"' detects a CER message.
766
767      The pattern (string including carriage returns):
768
769      '<avp name="Subscription-Id">
770         <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
771         <avp name="Subscription-Id-Data" data="606000106"/>
772      </avp>'
773
774      detects MSISDN (not IMSI) equal to 606000106
775
776      It would seems strange or 'creative' to use regular expressions within an hex string representation,
777      but anyway you could also do such kind of things to check non-printable data parts within the message:
778      for example, the pattern '<avp name="Framed-IP-Address" hex-data="0a[A-Fa-f0-9][A-Fa-f0-9]0a0a"/>'
779      matchs IP addresses for '10.x.10.10' where x = [0..255].
780
781      Note that string pattern could also be generated via #loadXML and then #asXML, that is to say, you
782      could get patterns through xml files which act as conditional triggers over message. In that case,
783      it is not possible to specify regular expressions within xml 'hex-data' fields because parser will fail
784      during hexadecimal read. Normally only printable 'data' fields are used for matching issues.
785
786      For example, imagine a 'pattern.xml' file like:
787      <message version="1" name="Credit-Control-Request" application-id="16777236" hop-by-hop-id="0" end-by-end-id="0">
788         <avp name="Subscription-Id">
789            <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
790            <avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>
791         </avp>
792      </message>
793
794      Then you could do:
795
796      anna::diameter::codec::Message patternMessage;
797      patternMessage.loadXML("pattern.xml");
798      std::string pattern = patternMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString();
799      // Former is '<avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>'
800      bool match = incomingMessage.isLike(pattern);
801
802      Then, messages having MSISDN numbers starting with '616' will match the pattern.
803      Note, that any other message codes (and not only Credit-Control-Request ones), could pass the test...
804      You could also build that string manually:
805
806      Example 1:
807      std::string pattern = "<avp name=\"Subscription-Id\">\n";
808      pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Type\" data=\"0\" alias=\"END_USER_E164\"/>\n"
809      pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"/>"
810
811      Example 2:
812      std::string pattern = "name=\"Subscription-Id\"(.)*name=\"Subscription-Id-Type\" data=\"0\"(.)*name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"";
813      </pre>
814
815      \return Returns the match result
816   */
817   bool isLike(const std::string &pattern) const throw();
818
819
820 //friend class Engine;
821   friend class Avp;
822 };
823
824 }
825 }
826 }
827
828
829 #endif