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