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