Fixed multiple AVP error. Missing fix RFC 6733 section 7.5 regarding avps within...
[anna.git] / include / anna / diameter / codec / Message.hpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // http://redmine.teslayout.com/projects/anna-suite
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     *  Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_diameter_codec_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 * addTheFailedAVP() throw(); // returns the Failed-AVP if exists, creates it when missing. The method could be named 'addFailedAVP'
150                                       // but we consider this better because only one instance (as RFC 6733 says in section 7.5) will be
151                                       // added by internal procedures (although, the application could obviously add more).
152
153 protected:
154
155   /** Codec Engine */
156   mutable Engine *a_engine;
157
158   /** Codec Engine getter: avoids have to create base engine when using its child */
159   virtual Engine * getEngine() const throw(anna::RuntimeException);
160
161   /**
162   * Initializes Message class information.
163   * Any reimplementation must first invoke base class method.
164   */
165   virtual void initialize() throw();
166
167
168 public:
169
170   /**
171   * Default constructor
172   */
173   Message();
174
175   /**
176   * Identified constructor
177   * @param id Command identifier as pair (code,request-indicator).
178   */
179   Message(CommandId id);
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      @param aid Application-id.
263   */
264   void setApplicationId(U32 aid) throw() { a_applicationId = aid; }
265
266   /**
267      Sets the message hop-by-hop
268      @param hbh Hop-by-hop identifier.
269   */
270   void setHopByHop(U32 hbh) throw() { a_hopByHop = hbh; }
271
272   /**
273      Sets the message end-to-end
274      @param ete End-to-end identifier.
275   */
276   void setEndToEnd(U32 ete) throw() { a_endToEnd = ete; }
277
278
279   /**
280      Sets header to be an answer regarding provided request message code.
281      Internally, updates command identifier (indeed request flag), promotes version, application identifier, hop-by-hop and end-to-end fields.
282
283      @param request Message to be answered.
284
285      @warning Request provided must be a request, in other case method do nothing.
286   */
287   void setHeaderToAnswer(const Message &request) throw() {
288     if(!request.getId().second) return;
289
290     setId(CommandId(request.getId().first, !request.getId().second), false /* don't clear */);
291     setVersion(request.getVersion());
292     setApplicationId(request.getApplicationId());
293     setHopByHop(request.getHopByHop()); // The same Hop-by-Hop Identifier in the request is used in the answer (RFC 6733 Section 6.2).
294     setEndToEnd(request.getEndToEnd()); // The same End-to-End Identifier in the request is used in the answer (RFC 6733 Section 6.2).
295     setProxiableBit(request.proxiableBit()); // The 'P' bit is set to the same value as the one in the request (RFC 6733 Section 6.2).
296   }
297
298
299   /**
300     Standard minimum-answer building from requests. Adds Session-Id (mirrored from request if present), Origin-Host and Origin-Realm
301     (which could be configured, extracted from optional Destination AVPs, etc.), and all the Proxy-Info AVPs (added in same order as
302     appear on the request). Of course, answer message header is built from request information through #setHeaderToAnswer. Finally,
303     message is fixed regarding dictionary elements order (#fix).
304
305     Summing up, as RFC 6733 Section 6.2, says:
306
307     <pre>
308
309         6.2.  Diameter Answer Processing
310
311            When a request is locally processed, the following procedures MUST be
312            applied to create the associated answer, in addition to any
313            additional procedures that MAY be discussed in the Diameter
314            application defining the command:
315
316            o  The same Hop-by-Hop Identifier in the request is used in the
317               answer.
318
319            o  The local host's identity is encoded in the Origin-Host AVP.
320
321            o  The Destination-Host and Destination-Realm AVPs MUST NOT be
322               present in the answer message.
323
324            o  The Result-Code AVP is added with its value indicating success or
325               failure.
326
327            o  If the Session-Id is present in the request, it MUST be included
328               in the answer.
329
330            o  Any Proxy-Info AVPs in the request MUST be added to the answer
331               message, in the same order they were present in the request.
332
333            o  The 'P' bit is set to the same value as the one in the request.
334
335            o  The same End-to-End identifier in the request is used in the
336               answer.
337
338            Note that the error messages (see Section 7) are also subjected to
339            the above processing rules.
340
341    Regarding errors, is recommended to use this over automatic answer built at #decode and/or #valid procedures, which would had added
342    Result-Code and/or Failed-AVP AVPs if proceed, but be aware of DIAMETER_COMMAND_UNSUPPORTED Result-Code, because becomes impossible
343    to fix (Session-Id SHOULD appear immediately following the Diameter header, and #fix do this manually even if no information about
344    the command structure is known, but perhaps another fixed AVPs could not comply... use #getResultCode to find out this situation before
345    using #setStandardToAnswer).
346
347    If application decoding and/or validation operations are ok, user may search for other problems and put the appropiate Result-Code.
348    For example, DIAMETER_TOO_BUSY (3004) depends on congestion issues at business layer and cannot be decided with the only message
349    information automatically (not all the Result-Code values are taken into account, only those which correspond to anomalies managed
350    by anna::diameter::codec). Application Result-Codes could be provided in this prototype, being DIAMETER_SUCCESS the default value if missing.
351
352    </pre>
353    @param request Message to be answered.
354    @param originHost Mandatory Origin-Host diameter identity value provided by application. If answer has already an Origin-Host, this will be ignored.
355    @param originRealm Mandatory Origin-Realm diameter identity value provided by application. If answer has already an Origin-Realm, this will be ignored.
356    @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.
357
358    @warning Request provided must be a request, in other case method do nothing.
359   */
360   void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw();
361
362
363   /**
364      Sets a Result-Code AVP over an answer message (for requests, do nothing).
365      If Result-Code AVP doesn't exists, is added and then filled with the value provided.
366      If Result-Code AVP already exists, value detected is replaced if was DIAMETER_SUCCESS (non success codes are unchanged).
367      When provided value corresponds to an protocol error, that is to say within range [3001,3010], message (E)rror bit is
368      automatically activated.
369
370      This method is internally used during #decode and/or #valid procedures in order to build automatic answers, but application
371      could call this for set another Result-Code no detected by these methods within its category or for other one (application
372      layer). These are the Result-Codes implemented (detected) by ANNA::diameter::codec:
373
374      <pre>
375         Protocol Errors:
376
377            DIAMETER_COMMAND_UNSUPPORTED
378            DIAMETER_INVALID_HDR_BITS
379            DIAMETER_INVALID_AVP_BITS
380
381         Permanent Failures:
382
383            DIAMETER_AVP_UNSUPPORTED (F)
384            DIAMETER_INVALID_AVP_VALUE (F)
385            DIAMETER_MISSING_AVP (F)
386            DIAMETER_AVP_NOT_ALLOWED (F)
387            DIAMETER_AVP_OCCURS_TOO_MANY_TIMES (F)
388            DIAMETER_INVALID_BIT_IN_HEADER
389            DIAMETER_INVALID_AVP_LENGTH (F)
390            DIAMETER_INVALID_MESSAGE_LENGTH
391
392            (F) Generates Failed-AVP (also DIAMETER_CONTRADICTING_AVPS and DIAMETER_INVALID_AVP_BIT_COMBO
393                                      values does, but these are not managed by anna::diameter::codec).
394      </pre>
395
396      @param rc Result-Code value. DIAMETER_SUCCESS by default.
397   */
398   void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException);
399
400
401   /**
402      Gets the Result-Code AVP value from an answer message (for requests, returns -1).
403      If missing, -1 value is returned.
404
405      @return Result-Code value for answers, -1 for request and answers without Result-Code AVP inside
406   */
407   int getResultCode() const throw();
408
409
410   /**
411      Adds the wrong AVP within the Failed-AVP over an answer message (for requests, do nothing).
412      If Failed-AVP AVP doesn't exists, is added and then filled (added within) with the value provided (empty AVP id representantion).
413      If Failed-AVP AVP already exists, is probably filled by a previous found error, but anyway this is verified and if empty then is
414      filled (added within) with the value provided (empty AVP id representantion).
415
416      This method is internally used during #decode and/or #valid procedures in order to build automatic answers, but application
417      could call this for set another Failed-AVP content no detected by these methods, for example: DIAMETER_CONTRADICTING_AVPS or
418      DIAMETER_INVALID_AVP_BIT_COMBO). Also, application could add more Failed-AVP avps with other wrong avps, or accumulate wrong
419      avps inside the one and only Failed-AVP managed by the stack (see section 7.5 of RFC 6733).
420
421      @param id Avp identifier as pair (code,vendor-id).
422
423      @return Pointer to the new AVP added within Failed-AVP, to make easy data-part access if needed.
424   */
425   Avp * setFailedAvp(AvpId id) throw(anna::RuntimeException);
426
427   /**
428      Same as #setFailedAvp(AvpId id) but providing an avp pointer with the needed information
429
430      @param avp Pointer to the added wrong avp
431
432      @return Pointer to the new AVP added within Failed-AVP, to make easy data-part access if needed.
433   */
434   Avp * setFailedAvp(Avp *avp) throw(anna::RuntimeException);
435
436
437
438   /**
439      Adds an avp child providing its identifier and reserve internal memory it.
440
441      @param id Avp identifier as pair (code,vendor-id).
442
443      @return Pointer to the new created avp.
444   */
445   Avp * addAvp(AvpId id) throw(anna::RuntimeException) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
446
447
448   /**
449      Same as #addAvp but providing dictionary logical name for Avp searched
450   */
451   Avp * addAvp(const char *name) throw(anna::RuntimeException);
452
453
454   /**
455      Adds an avp child providing a persistent pointer (must be maintained by application).
456
457      @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned.
458
459      @return Pointer to the added avp (again).
460   */
461   Avp * addAvp(Avp * avp) throw() { if(!avp) return NULL; addChild(avp); return avp; }
462
463
464   /**
465      Removes an Avp within message (first level) and free resources.
466
467      @param id Avp identifier (pair code + vendor-id).
468      @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).
469      Negative values could be used to reverse access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
470
471      @return Returns true if something was removed. False in other cases (including i.e. when this message is empty).
472   */
473   bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
474
475
476   /**
477      Same as #removeAvp but providing dictionary logical name for Avp searched
478   */
479   bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException);
480
481
482   /**
483   * Clears and initializes Message class information.
484   * Application must clear auxiliary message objects before adding Avps in a new context.
485   * Application don't need to clear a message object before decode operation (decode invokes #clear before any other task).
486   * Any reimplementation must first invoke base class method.
487   */
488   virtual void clear() throw(anna::RuntimeException);
489
490   /**
491      Decodes buffer provided over class content. If an error ocurred, decoding will stop launching exception (fatal error) or a warning trace (perhaps the achieved
492      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
493      in a moment which depends on validation depth (codec::Engine::ValidationDepth).
494
495      @param db buffer data block processed. Before decoding, the whole message instance will be cleared (no need to invoke #clear before #decode).
496      @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation,
497      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
498      NULL because no answer is built for answers. By default, automatic answer is not built.
499   */
500   void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) throw(anna::RuntimeException);
501
502   /**
503     Fix childrens content regarding dictionary avp positions.
504     Message could remain invalid because of possible fixed/mandatory avps.
505     This is useful to give flexibility to the application during message construction before encoding or representing the data.
506     Is not recommended to fix a recently decoded message because possible validation problems will be hidden.
507   */
508   void fix() throw();
509
510   /**
511      Validates the message regarding dictionary rules like enumerated range, flags coherence, mandatory and fixed types, cardinality qualifiers, etc.
512      @return Boolean indicating validation result
513      @param ptrAnswer Answer set by application (could be empty or not), who is responsible for its memory reservation,
514      and automatically built regarding standard. If message analyzed realizes to be an answer, internal reference becomes
515      NULL because no answer is built for answers. By default, automatic answer is not built.
516   */
517   bool valid(Message *ptrAnswer = NULL) const throw(anna::RuntimeException);
518
519
520   /**
521      Interpret xml data in order to dump over the class content.
522      \param messageNode Message root node
523   */
524   void fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException);
525
526   /**
527      Interpret xml string representation in order to dump over the class content.
528      DTD validation is used in the same way that #loadXML does.
529      \param xmlString XML string representation with relevant information for this instance
530   */
531   void fromXMLString(const std::string &xmlString) throw(anna::RuntimeException);
532
533   /**
534      Loads an xml file based on this message DTD (could be accumulative, no initialization will be performed by this method).
535
536      <pre>
537      <!ELEMENT message (avp*)>
538      <!ELEMENT avp (avp*)>
539
540      <!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>
541      <!--
542         version: Diameter version. Sets '1' by default
543         name:    Command name within working stack (dictionary identifier)
544
545         In order to get more coding capabilities, command code and flags could be established instead of former command name,
546          but neither of them are allowed if 'name' is provided (and vice versa):
547
548         code:    Command code
549         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
550
551
552         application-id:   Message application id
553         hop-by-hop-id:    Message hop by hop id. Sets '0' by default
554         end-by-end-id:    Message end by end id. Sets '0' by default
555      -->
556
557      <!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
558      <!--
559         name:   Avp name within working stack (dictionary identifier)
560
561         In order to get more coding capabilities, avp code, vendor-id and flags could be established instead of former avp name,
562          but neither of them are allowed if 'name' is provided (and vice versa):
563
564         code:          Avp code
565         vendor-code:   Avp vendor code
566         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)
567
568
569         data:          Natural string representation for avp data. Specially applicable with numbers and printable strings, but also
570                         useful for certain formats which could be easily understandable in such friendly/smart representation. We will
571                         achieve different human-readable strings depending on data format:
572
573                           [ OctetString ] (if printable, but not recommended)
574                           [ Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64 ] (normal number representation)
575                           [ Time ] (NTP timestamp, normal number representation)
576                           [ Address ] (auto detects IPv4 or IPv6 address version, then only ip address is specified: IPv4 with dots, IPv6 with colons)
577                           [ UTF8String, DiameterIdentity, DiameterURI ] (printable)
578                           [ IPFilterRule, QoSFilterRule ] (uses ASCII charset, printable)
579
580                           New application formats must define specific natural representation for internal raw data
581
582         hex-data:      Hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits). Suitable for whatever kind
583                         of diameter format, but mandatory for non printable information. OctetString usually transport non human-readable
584                         data and should better be encoded within this field although being printable. Unknown avps (which fails identifying
585                         provided name or code/vendor-code) must always use this representation.
586
587         Xml representation for decoded messages shows natural content except for 'OctetString' format and unknown avps. Anyway, when printable,
588          OctetString could show such information at data field apart from hex-data, because many implementations use this format to transport
589          readable-string data. In general, one of the data fields is mandatory except for 'Grouped' type (its data is another level of avps).
590         Application-specific formats must decide the way to represent its contents, being recommended to use a natural representation if possible,
591          because xml is read by humans with testing and monitoring purposes.
592      -->
593      </pre>
594
595      @param xmlPathFile Complete path file to the xml document which represents the diameter message
596      @see fromXMLString
597   */
598   void loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException);
599
600
601
602   // getters
603
604   /**
605      Gets Message identifier as pair (code, request indicator).
606   */
607   const CommandId & getId() const throw() { return a_id; }
608
609   /**
610      Gets the command version. By default, messages initializes with value 1.
611
612      @return version Message version
613   */
614   U8 getVersion() const throw() { return a_version; }
615
616   /**
617      Gets Message request indicator.
618   */
619   bool isRequest() const throw() { return a_id.second; }
620
621   /**
622      Gets Message answer indicator.
623   */
624   bool isAnswer() const throw() { return !isRequest(); }
625
626   /**
627      Gets the message application id
628      @return aid Application-id.
629   */
630   const U32 & getApplicationId() const throw() { return a_applicationId; }
631
632   /**
633      Gets the message hop-by-hop
634      @return hbh Hop-by-hop identifier.
635   */
636   const U32 & getHopByHop() const throw() { return a_hopByHop; }
637
638   /**
639      Gets the message end-to-end
640      @return ete End-to-end identifier.
641   */
642   const U32 & getEndToEnd() const throw() { return a_endToEnd; }
643
644   /**
645      Gets stack command (dictionary command reference).
646   */
647   const anna::diameter::stack::Command *getStackCommand() const throw(anna::RuntimeException) { return getStackCommand(a_id); }
648
649   /** Returns R bit activation state */
650   bool requestBit() const throw() { return ((a_flags & RBitMask) != 0x00); }
651
652   /** Returns P bit activation state */
653   bool proxiableBit() const throw() { return ((a_flags & PBitMask) != 0x00); }
654
655   /** Returns E bit activation state */
656   bool errorBit() const throw() { return ((a_flags & EBitMask) != 0x00); }
657
658   /** Returns T bit activation state */
659   bool potentiallyReTransmittedMessageBit() const throw() { return ((a_flags & TBitMask) != 0x00); }
660
661
662   /**
663      Access content for internal Avps. Exception mode allows different combinations like cascade access:
664      <pre>
665
666         try {
667            message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control, anna::Exception::Mode::Throw)
668                   ->getAvp(anna::diameter::helpers::base::AVP__Rating_Group, anna::Exception::Mode::Throw);
669         }
670         catch(anna::RuntimeException) {;}
671      </pre>
672
673      Or step access:
674
675      <pre>
676         const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
677         const Avp *rg;
678         if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
679      </pre>
680
681      Replacing procedures becomes easy because an Avp can be searched and its pointer reconfigured by mean #setId and data part setters.
682      Deleting procedures must use #removeAvp.
683      Access is internally cached to speed up the search operations. This cache is reset after calling #fix or #removeAvp methods.
684
685      @param id Avp identifier (pair code + vendor-id).
686      @param ocurrence Order of appearance for the searched avp. Zero position is rejected, but negative values could be used to reverse
687      access positions: i.e. -1 is the last ocurrence, -2 is the second to last (penultimate), etc.
688      @param emode Excepcion mode handling: Ignore (no action is taken), Throw (excepcion when missing avp), Trace (trace situation as warning).
689   */
690   const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
691     return Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
692   }
693
694   Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
695     return const_cast<Avp*>(Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode));
696   }
697
698
699   /**
700      Same as #getAvp but providing dictionary logical name for Avp searched
701   */
702   const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const throw(anna::RuntimeException) {
703     return _getAvp(name, ocurrence, emode);
704   }
705
706   Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) throw(anna::RuntimeException) {
707     return const_cast<Avp*>(_getAvp(name, ocurrence, emode));
708   }
709
710 // Helpers
711
712   /**
713      Counts the number of ocurrences of Avps (first level) with the identifier provided
714
715      @param id Avp identifier (pair code + vendor-id).
716   */
717   int countAvp(AvpId id) const throw() { return Avp::countAvp(a_avps, id); }
718
719   /**
720      Same as #countAvp but providing dictionary logical name for Avp searched
721   */
722   int countAvp(const char *name) const throw(anna::RuntimeException);
723
724   /**
725      Counts the number of children
726
727      @param id Avp identifier (pair code + vendor-id).
728   */
729   int countChilds() const throw() { return Avp::countChilds(a_avps); }
730
731   /**
732      Encodes datablock with the class content. In case that validation is enabled (codec::Engine::ValidationMode) an exception will be launched
733      in a moment which depends on validation depth (codec::Engine::ValidationDepth). If you want to see validation errors but go on with encoding,
734      you should try/catch #valid() procedure out of #code.
735
736      @return DataBlock encoded (internal memory used)
737   */
738   const anna::DataBlock & code() throw(anna::RuntimeException);
739
740   /**
741      Class xml representation
742      \param parent Parent XML node on which hold this instance information.
743      \return XML document with relevant information for this instance.
744   */
745   anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
746
747   /**
748      Class xml string representation
749      \return XML string representation with relevant information for this instance.
750   */
751   std::string asXMLString() const throw();
752
753   /**
754      Comparison operator
755
756      @param m1 Instance 1 for Message class
757      @param m2 Instance 2 for Message class
758
759      @return Comparison result
760   */
761   friend bool operator == (const Message & m1, const Message & m2) throw() { return (m1.asXMLString() == m2.asXMLString()); }
762
763   /**
764      Match a regular expression (string pattern) regarding xml string serialization for this message.
765      Using a complex pattern (many avps, grouped ones) it could be necessary to fix the message before
766      using the method in order to perform a more controlled comparison. In the same way, flags could be
767      ignored to simplify message xml presentation.
768      This powerful tool could be used to program traffic analysis and decide future behaviour (routing,
769      traslation, etc.).
770
771      <pre>
772      Examples:
773
774      The pattern '<avp name="Service-Context-Id" data="(.)*32251@3gpp.org"/>' detects PS charging contexts
775      because of data suffix specification '32251@3gpp.org' for that AVP.
776
777      The pattern '<message version="1" name="Capabilities-Exchange-Request"' detects a CER message.
778
779      The pattern (string including carriage returns):
780
781      '<avp name="Subscription-Id">
782         <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
783         <avp name="Subscription-Id-Data" data="606000106"/>
784      </avp>'
785
786      detects MSISDN (not IMSI) equal to 606000106
787
788      It would seems strange or 'creative' to use regular expressions within an hex string representation,
789      but anyway you could also do such kind of things to check non-printable data parts within the message:
790      for example, the pattern '<avp name="Framed-IP-Address" hex-data="0a[A-Fa-f0-9][A-Fa-f0-9]0a0a"/>'
791      matchs IP addresses for '10.x.10.10' where x = [0..255].
792
793      Note that string pattern could also be generated via #loadXML and then #asXML, that is to say, you
794      could get patterns through xml files which act as conditional triggers over message. In that case,
795      it is not possible to specify regular expressions within xml 'hex-data' fields because parser will fail
796      during hexadecimal read. Normally only printable 'data' fields are used for matching issues.
797
798      For example, imagine a 'pattern.xml' file like:
799      <message version="1" name="Credit-Control-Request" application-id="16777236" hop-by-hop-id="0" end-by-end-id="0">
800         <avp name="Subscription-Id">
801            <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
802            <avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>
803         </avp>
804      </message>
805
806      Then you could do:
807
808      anna::diameter::codec::Message patternMessage;
809      patternMessage.loadXML("pattern.xml");
810      std::string pattern = patternMessage.getAvp("Subscription-Id")->getAvp("Subscription-Id-Type")->asXMLString();
811      // Former is '<avp name="Subscription-Id-Data" data="616[0-9]{6,6}"/>'
812      bool match = incomingMessage.isLike(pattern);
813
814      Then, messages having MSISDN numbers starting with '616' will match the pattern.
815      Note, that any other message codes (and not only Credit-Control-Request ones), could pass the test...
816      You could also build that string manually:
817
818      Example 1:
819      std::string pattern = "<avp name=\"Subscription-Id\">\n";
820      pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Type\" data=\"0\" alias=\"END_USER_E164\"/>\n"
821      pattern += ANNA_XML_COMPILER_TAB; pattern += "<avp name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"/>"
822
823      Example 2:
824      std::string pattern = "name=\"Subscription-Id\"(.)*name=\"Subscription-Id-Type\" data=\"0\"(.)*name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"";
825      </pre>
826
827      \return Returns the match result
828   */
829   bool isLike(const std::string &pattern) const throw();
830
831
832 //friend class Engine;
833   friend class Avp;
834 };
835
836 }
837 }
838 }
839
840
841 #endif