1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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
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.
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.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_diameter_codec_Message_hpp
38 #define anna_diameter_codec_Message_hpp
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>
47 #include <anna/core/DataBlock.hpp>
48 #include <anna/core/RuntimeException.hpp>
53 //------------------------------------------------------------------------------
54 //---------------------------------------------------------------------- #define
55 //------------------------------------------------------------------------------
77 * Diameter message generic container
79 * RFC 3588 Diameter Based Protocol September 2003
82 * A summary of the Diameter header format is shown below. The fields
83 * are transmitted in network byte order.
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94 * | Hop-by-Hop Identifier |
95 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96 * | End-to-End Identifier |
97 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99 * +-+-+-+-+-+-+-+-+-+-+-+-+-
105 CommandId a_id; // code and request indicator
110 avp_container a_avps; // childrens
111 find_container a_finds; // fast access for message first-level avps
114 int a_insertionPositionForChilds; // used with childrens
115 anna::DataBlock a_forCode;
117 const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const throw(anna::RuntimeException);
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).
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.
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(); }
140 * Gets avp total message length.
142 U24 getLength() const throw();
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
154 mutable Engine *a_engine;
156 /** Codec Engine getter: avoids have to create base engine when using its child */
157 virtual Engine * getEngine() const throw(anna::RuntimeException);
160 * Initializes Message class information.
161 * Any reimplementation must first invoke base class method.
163 virtual void initialize() throw();
169 * Default constructor
174 * Identified constructor
175 * @param id Command identifier as pair (code,request-indicator).
177 Message(CommandId id);
181 static const int HeaderLength;
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;
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.
212 Sets the command identifier and clear the former content.
214 @param id Command identifier as pair (code,request-indicator).
215 @param _clear Message will be cleared when updating the command identifier (default behaviour).
217 void setId(CommandId id, bool _clear = true) throw(anna::RuntimeException);
220 Same as #setId but providing dictionary logical name for Avp searched
222 void setId(const char *name) throw(anna::RuntimeException);
225 Sets the command version. By default, messages initializes with value 1.
227 @param version Version provided
229 void setVersion(U8 version) throw() { a_version = version; }
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.
235 @param activate Activates/deactivates the bit. True by default.
237 void setProxiableBit(bool activate = true) throw() { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
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.
243 @param activate Activates/deactivates the bit. True by default.
245 void setErrorBit(bool activate = true) throw() { if(activate) a_flags |= EBitMask; else a_flags &= (~EBitMask); }
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.
251 @param activate Activates/deactivates the bit. True by default.
253 void setPotentiallyReTransmittedMessageBit(bool activate = true) throw() { if(activate) a_flags |= TBitMask; else a_flags &= (~TBitMask); }
256 Sets the message application id
257 @param aid Application-id.
259 void setApplicationId(U32 aid) throw() { a_applicationId = aid; }
262 Sets the message hop-by-hop
263 @param hbh Hop-by-hop identifier.
265 void setHopByHop(U32 hbh) throw() { a_hopByHop = hbh; }
268 Sets the message end-to-end
269 @param ete End-to-end identifier.
271 void setEndToEnd(U32 ete) throw() { a_endToEnd = ete; }
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.
278 @param request Message to be answered.
280 @warning Request provided must be a request, in other case method do nothing.
282 void setHeaderToAnswer(const Message &request) throw() {
283 if(!request.getId().second) return;
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).
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).
300 Summing up, as RFC 6733 Section 6.2, says:
304 6.2. Diameter Answer Processing
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:
311 o The same Hop-by-Hop Identifier in the request is used in the
314 o The local host's identity is encoded in the Origin-Host AVP.
316 o The Destination-Host and Destination-Realm AVPs MUST NOT be
317 present in the answer message.
319 o The Result-Code AVP is added with its value indicating success or
322 o If the Session-Id is present in the request, it MUST be included
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.
328 o The 'P' bit is set to the same value as the one in the request.
330 o The same End-to-End identifier in the request is used in the
333 Note that the error messages (see Section 7) are also subjected to
334 the above processing rules.
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).
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.
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.
353 @warning Request provided must be a request, in other case method do nothing.
355 void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw();
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.
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:
372 DIAMETER_COMMAND_UNSUPPORTED
373 DIAMETER_INVALID_HDR_BITS
374 DIAMETER_INVALID_AVP_BITS
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
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).
391 @param rc Result-Code value. DIAMETER_SUCCESS by default.
393 void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) throw(anna::RuntimeException);
397 Gets the Result-Code AVP value from an answer message (for requests, returns -1).
398 If missing, -1 value is returned.
400 @return Result-Code value for answers, -1 for request and answers without Result-Code AVP inside
402 int getResultCode() const throw();
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).
410 This method is internally used during #decode and/or #valid procedures in order to build automatic answers.
412 @param id Avp identifier as pair (code,vendor-id).
414 @return Pointer to the new AVP added within Failed-AVP, to make easy data-part accessif needed.
416 Avp * setNewFailedAvp(AvpId id) throw(anna::RuntimeException) { if(isRequest()) return NULL; return (addFailedAVP()->addAvp(id)); }
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).
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).
427 @param id Avp identifier as pair (code,vendor-id).
429 @return Pointer to the new AVP added within Failed-AVP, to make easy data-part accessif needed.
431 Avp * setNewFailedAvp(Avp *avp) throw() { if(!avp || isRequest()) return NULL; return (addFailedAVP()->addAvp(avp)); }
435 Adds an avp child providing its identifier and reserve internal memory it.
437 @param id Avp identifier as pair (code,vendor-id).
439 @return Pointer to the new created avp.
441 Avp * addAvp(AvpId id) throw(anna::RuntimeException) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
445 Same as #addAvp but providing dictionary logical name for Avp searched
447 Avp * addAvp(const char *name) throw(anna::RuntimeException);
451 Adds an avp child providing a persistent pointer (must be maintained by application).
453 @param avp Avp external pointer. If NULL provided, nothing is done and NULL returned.
455 @return Pointer to the added avp (again).
457 Avp * addAvp(Avp * avp) throw() { if(!avp) return NULL; addChild(avp); return avp; }
461 Removes an Avp within message (first level) and free resources.
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.
467 @return Returns true if something was removed. False in other cases (including i.e. when this message is empty).
469 bool removeAvp(AvpId id, int ocurrence = 1) throw(anna::RuntimeException) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
473 Same as #removeAvp but providing dictionary logical name for Avp searched
475 bool removeAvp(const char *name, int ocurrence = 1) throw(anna::RuntimeException);
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.
484 virtual void clear() throw(anna::RuntimeException);
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).
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.
496 void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) throw(anna::RuntimeException);
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.
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.
513 bool valid(Message *ptrAnswer = NULL) const throw(anna::RuntimeException);
517 Interpret xml data in order to dump over the class content.
518 \param messageNode Message root node
520 void fromXML(const anna::xml::Node* messageNode) throw(anna::RuntimeException);
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
527 void fromXMLString(const std::string &xmlString) throw(anna::RuntimeException);
530 Loads an xml file based on this message DTD (could be accumulative, no initialization will be performed by this method).
533 <!ELEMENT message (avp*)>
534 <!ELEMENT avp (avp*)>
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>
538 version: Diameter version. Sets '1' by default
539 name: Command name within working stack (dictionary identifier)
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):
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
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
553 <!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
555 name: Avp name within working stack (dictionary identifier)
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):
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)
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:
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)
576 New application formats must define specific natural representation for internal raw data
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.
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.
591 @param xmlPathFile Complete path file to the xml document which represents the diameter message
594 void loadXML(const std::string & xmlPathFile) throw(anna::RuntimeException);
601 Gets Message identifier as pair (code, request indicator).
603 const CommandId & getId() const throw() { return a_id; }
606 Gets the command version. By default, messages initializes with value 1.
608 @return version Message version
610 U8 getVersion() const throw() { return a_version; }
613 Gets Message request indicator.
615 bool isRequest() const throw() { return a_id.second; }
618 Gets Message answer indicator.
620 bool isAnswer() const throw() { return !isRequest(); }
623 Gets the message application id
624 @return aid Application-id.
626 const U32 & getApplicationId() const throw() { return a_applicationId; }
629 Gets the message hop-by-hop
630 @return hbh Hop-by-hop identifier.
632 const U32 & getHopByHop() const throw() { return a_hopByHop; }
635 Gets the message end-to-end
636 @return ete End-to-end identifier.
638 const U32 & getEndToEnd() const throw() { return a_endToEnd; }
641 Gets stack command (dictionary command reference).
643 const anna::diameter::stack::Command *getStackCommand() const throw(anna::RuntimeException) { return getStackCommand(a_id); }
645 /** Returns R bit activation state */
646 bool requestBit() const throw() { return ((a_flags & RBitMask) != 0x00); }
648 /** Returns P bit activation state */
649 bool proxiableBit() const throw() { return ((a_flags & PBitMask) != 0x00); }
651 /** Returns E bit activation state */
652 bool errorBit() const throw() { return ((a_flags & EBitMask) != 0x00); }
654 /** Returns T bit activation state */
655 bool potentiallyReTransmittedMessageBit() const throw() { return ((a_flags & TBitMask) != 0x00); }
659 Access content for internal Avps. Exception mode allows different combinations like cascade access:
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);
666 catch(anna::RuntimeException) {;}
672 const Avp *mscc = message->getAvp(anna::diameter::helpers::base::AVP__Multiple_Services_Credit_Control);
674 if (mscc) rg = mscc->getAvp(anna::diameter::helpers::base::AVP__Rating_Group);
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.
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).
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);
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));
696 Same as #getAvp but providing dictionary logical name for Avp searched
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);
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));
709 Counts the number of ocurrences of Avps (first level) with the identifier provided
711 @param id Avp identifier (pair code + vendor-id).
713 int countAvp(AvpId id) const throw() { return Avp::countAvp(a_avps, id); }
716 Same as #countAvp but providing dictionary logical name for Avp searched
718 int countAvp(const char *name) const throw(anna::RuntimeException);
721 Counts the number of children
723 @param id Avp identifier (pair code + vendor-id).
725 int countChilds() const throw() { return Avp::countChilds(a_avps); }
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.
732 @return DataBlock encoded (internal memory used)
734 const anna::DataBlock & code() throw(anna::RuntimeException);
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.
741 anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
744 Class xml string representation
745 \return XML string representation with relevant information for this instance.
747 std::string asXMLString() const throw();
752 @param m1 Instance 1 for Message class
753 @param m2 Instance 2 for Message class
755 @return Comparison result
757 friend bool operator == (const Message & m1, const Message & m2) throw() { return (m1.asXMLString() == m2.asXMLString()); }
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,
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.
773 The pattern '<message version="1" name="Capabilities-Exchange-Request"' detects a CER message.
775 The pattern (string including carriage returns):
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"/>
782 detects MSISDN (not IMSI) equal to 606000106
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].
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.
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}"/>
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);
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:
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}\"/>"
820 std::string pattern = "name=\"Subscription-Id\"(.)*name=\"Subscription-Id-Type\" data=\"0\"(.)*name=\"Subscription-Id-Data\" data=\"616[0-9]{6,6}\"";
823 \return Returns the match result
825 bool isLike(const std::string &pattern) const throw();
828 //friend class Engine;