ANNA Suite  2020b
Multipurpose development suite for Telco applications
Message.hpp
Go to the documentation of this file.
1 // ANNA - Anna is Not Nothingness Anymore //
2 // //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
4 // //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7 
8 
9 #ifndef anna_diameter_codec_Message_hpp
10 #define anna_diameter_codec_Message_hpp
11 
12 
13 // Local
14 #include <anna/config/defines.hpp>
18 
19 #include <anna/core/DataBlock.hpp>
21 
22 // STL
23 #include <string>
24 
25 //------------------------------------------------------------------------------
26 //---------------------------------------------------------------------- #define
27 //------------------------------------------------------------------------------
28 
29 namespace anna {
30 class Node;
31 }
32 
33 namespace anna {
34 
35 namespace diameter {
36 
37 namespace stack {
38 class Dictionary;
39 class Format;
40 class Command;
41 }
42 
43 namespace codec {
44 
45 class Avp;
46 class Engine;
47 
74 class Message {
75 
76  U8 a_version;
77  CommandId a_id; // code and request indicator
78  U8 a_flags;
79  U32 a_applicationId;
80  U32 a_hopByHop;
81  U32 a_endToEnd;
82  avp_container a_avps; // childrens
83  find_container a_finds; // fast access for message first-level avps
84 
85  // auxiliary
86  int a_insertionPositionForChilds; // used with childrens
87  anna::DataBlock a_forCode;
88 
89  const Avp* _getAvp(const char *name, int ocurrence, anna::Exception::Mode::_v emode) const noexcept(false);
90 
91  // --- Developer notes ---
92  // 'AVP Length' does not include posible data padding. Thanks to this, 'Data Length'
93  // is the difference between 'AVP Length' and sum of code, length, flags and
94  // optionally the vendor-ID (all of them are 32-bit boundary), that is to say:
95  // 8 or 12 (vendor-specific avps).
96  //
97  // Grouped avps 'AVP Length' includes own headers plus the total length of all
98  // underlying AVPs, including their headers and padding, then 'AVP Length' is
99  // always multiple of 4 (library will check this), and smae for 'Data Length'
100  // which is an 'whole avp Length with padding' itself.
101 
102 
103  // Children helpers
104 
105  // Own
106  avp_iterator avp_begin() { return a_avps.begin(); }
107  avp_iterator avp_end() { return a_avps.end(); }
108  const_avp_iterator avp_begin() const { return a_avps.begin(); }
109  const_avp_iterator avp_end() const { return a_avps.end(); }
110 
114  U24 getLength() const ;
115 
116 
117  // Internal
118  bool flagsOK(int &rc) const ; // flags coherence regarding dictionary. Only must be called when Message is identified at the dictionary.
119  int addChild(Avp *avp) { return Avp::addChild(a_avps, a_insertionPositionForChilds, avp); }
120  const anna::diameter::stack::Command *getStackCommand(CommandId id) const noexcept(false);
121 
122  void setFailedAvp(const parent_t &parent, AvpId wrong, const char *wrongName = NULL) noexcept(false);
123  // During message decoding and validation, the first wrong avp is stored and all the tracking is managed to find out its
124  // nested path for the case of grouped avps with wrong avps inside. Remember the RFC 6733, section 7.5:
125  //
126  // In the case where the offending AVP is embedded within a Grouped AVP,
127  // the Failed-AVP MAY contain the grouped AVP, which in turn contains
128  // the single offending AVP. The same method MAY be employed if the
129  // grouped AVP itself is embedded in yet another grouped AVP and so on.
130  // In this case, the Failed-AVP MAY contain the grouped AVP hierarchy up
131  // to the single offending AVP. This enables the recipient to detect
132  // the location of the offending AVP when embedded in a group.
133  //
134  // The first wrong avp found will set the final result code, as the RFC recommends:
135  //
136  // The value of the Result-Code AVP will provide information on the reason
137  // for the Failed-AVP AVP. A Diameter answer message SHOULD contain an
138  // instance of the Failed-AVP AVP that corresponds to the error
139  // indicated by the Result-Code AVP. For practical purposes, this
140  // Failed-AVP would typically refer to the first AVP processing error
141  // that a Diameter node encounters.
142  //
143  // The message keeps the list (reverse order) of avps hierarchy (in case of grouping) for the final Failed-AVP construction,
144  // which is done at the end of decoding or validation, and only the first wrong avp is stored with its corresponding path.
145 
146 
147 protected:
148 
150  mutable Engine *a_engine;
151 
153  virtual Engine * getEngine() const noexcept(false);
154 
159  virtual void initialize() ;
160 
161 
162 public:
163 
168  Message(Engine *engine = NULL);
169 
175  Message(CommandId id, Engine *engine = NULL);
176 
177 
199  void setEngine(Engine *engine) ;
200 
201 
202  // Length references
203  static const int HeaderLength;
204 
205 
206  // Command Flags
207  // +-+-+-+-+-+-+-+-+
208  // |R P E T r r r r|
209  // +-+-+-+-+-+-+-+-+
210  //
211  // R(equest)
212  // P(roxiable)
213  // E(rror)
214  // T(Potentially re-transmitted message)
215  // r(eserved) - these flag bits are reserved for future use, and
216  // MUST be set to zero, and ignored by the receiver.
217  static const U8 RBitMask;
218  static const U8 PBitMask;
219  static const U8 EBitMask;
220  static const U8 TBitMask;
221 
222 
226  virtual ~Message();
227 
228  // Virtual destructors are useful when you can delete an instance of a derived class through a pointer to base class:
229  // 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.
230  // My current solution: virtualizing method 'clear'
231  //
232  // Recommendation:
233  // To sum up, always make base classes' destructors virtual when they're meant to be manipulated polymorphically.
234 
235  // setters
236 
242  void setId(CommandId id) noexcept(false);
243 
247  void setId(const char *name) noexcept(false);
248 
254  void setVersion(U8 version) { a_version = version; }
255 
262  void setProxiableBit(bool activate = true) { if(activate) a_flags |= PBitMask; else a_flags &= (~PBitMask); }
263 
271  void setErrorBit(bool activate = true) { if(isRequest()) return; if(activate) a_flags |= EBitMask; else a_flags &= (~EBitMask); }
272 
280  void setPotentiallyReTransmittedMessageBit(bool activate = true) { if(isAnswer()) return; if(activate) a_flags |= TBitMask; else a_flags &= (~TBitMask); }
281 
297  void setApplicationId(U32 aid) noexcept(false);
298 
303  void setHopByHop(U32 hbh) { a_hopByHop = hbh; }
304 
309  void setEndToEnd(U32 ete) { a_endToEnd = ete; }
310 
311 
320  void setHeaderToAnswer(const Message &request) noexcept(false) {
321  if(!request.getId().second) return;
322 
323  a_engine = request.getEngine(); // we know this will be
324 
325  setId(CommandId(request.getId().first, !request.getId().second));
326  setVersion(request.getVersion());
327  setApplicationId(request.getApplicationId());
328  setHopByHop(request.getHopByHop()); // The same Hop-by-Hop Identifier in the request is used in the answer (RFC 6733 Section 6.2).
329  setEndToEnd(request.getEndToEnd()); // The same End-to-End Identifier in the request is used in the answer (RFC 6733 Section 6.2).
330  setProxiableBit(request.proxiableBit()); // The 'P' bit is set to the same value as the one in the request (RFC 6733 Section 6.2).
331  }
332 
333 
400  void setStandardToAnswer(const Message &request, const std::string &originHost, const std::string &originRealm, int resultCode = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) noexcept(false);
401 
402 
438  void setResultCode(int rc = helpers::base::AVPVALUES__Result_Code::DIAMETER_SUCCESS) noexcept(false);
439 
440 
447  int getResultCode() const ;
448 
449 
457  Avp * addAvp(AvpId id) noexcept(false) { return Avp::addAvp(a_avps, a_insertionPositionForChilds, id, getEngine()); }
458 
459 
463  Avp * addAvp(const char *name) noexcept(false);
464 
465 
476  Avp * addAvp(Avp * avp) ;
477 
478 
488  bool removeAvp(AvpId id, int ocurrence = 1) noexcept(false) { return Avp::removeAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine()); }
489 
490 
494  bool removeAvp(const char *name, int ocurrence = 1) noexcept(false);
495 
496 
508  virtual void clear(bool resetEngine = true) noexcept(false);
509 
522  void decode(const anna::DataBlock &db, Message *ptrAnswer = NULL) noexcept(false);
523 
530  void fix() ;
531 
539  bool valid(Message *ptrAnswer = NULL) const noexcept(false);
540 
546  void fromXML(const anna::xml::Node* messageNode) noexcept(false);
547 
557  void loadXMLFile(const std::string &xmlPathFile) noexcept(false);
558 
568  void loadXMLString(const std::string &xmlString) noexcept(false);
569 
570 
571  // getters
572 
576  const CommandId & getId() const { return a_id; }
577 
583  U8 getVersion() const { return a_version; }
584 
588  bool isRequest() const { return a_id.second; }
589 
593  bool isAnswer() const { return !isRequest(); }
594 
599  const U32 & getApplicationId() const { return a_applicationId; }
600 
605  const U32 & getHopByHop() const { return a_hopByHop; }
606 
611  const U32 & getEndToEnd() const { return a_endToEnd; }
612 
616  const anna::diameter::stack::Command *getStackCommand() const noexcept(false) { return getStackCommand(a_id); }
617 
619  bool requestBit() const { return ((a_flags & RBitMask) != 0x00); }
620 
622  bool proxiableBit() const { return ((a_flags & PBitMask) != 0x00); }
623 
625  bool errorBit() const { return ((a_flags & EBitMask) != 0x00); }
626 
628  bool potentiallyReTransmittedMessageBit() const { return ((a_flags & TBitMask) != 0x00); }
629 
630 
659  const Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const noexcept(false) {
660  return Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode);
661  }
662 
663  Avp* getAvp(AvpId id, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) noexcept(false) {
664  return const_cast<Avp*>(Avp::getAvp(a_avps, (find_container&)a_finds, id, ocurrence, getEngine(), emode));
665  }
666 
667 
671  const Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) const noexcept(false) {
672  return _getAvp(name, ocurrence, emode);
673  }
674 
675  Avp* getAvp(const char *name, int ocurrence = 1, anna::Exception::Mode::_v emode = anna::Exception::Mode::Throw) noexcept(false) {
676  return const_cast<Avp*>(_getAvp(name, ocurrence, emode));
677  }
678 
679 // Helpers
680 
686  int countAvp(AvpId id) const { return Avp::countAvp(a_avps, id); }
687 
691  int countAvp(const char *name) const noexcept(false);
692 
698  int countChilds() const { return Avp::countChilds(a_avps); }
699 
707  const anna::DataBlock & code() noexcept(false);
708 
714  anna::xml::Node* asXML(anna::xml::Node* parent) const ;
715 
723  std::string asXMLString(bool normalize = false) const ;
724 
733  friend bool operator == (const Message & m1, const Message & m2) { return (m1.asXMLString() == m2.asXMLString()); }
734 
791  bool isLike(const std::string &pattern) const ;
792 
793 
794 //friend class Engine;
795  friend class Avp;
796 };
797 
798 }
799 }
800 }
801 
802 
803 #endif
804 
Definition: Exception.hpp:26
void setHeaderToAnswer(const Message &request) noexcept(false)
Definition: Message.hpp:320
Avp * getAvp(const char *name, int ocurrence=1, anna::Exception::Mode::_v emode=anna::Exception::Mode::Throw) noexcept(false)
Definition: Message.hpp:675
int countChilds() const
Definition: Message.hpp:698
avp_container::const_iterator const_avp_iterator
Definition: Avp.hpp:79
Definition: Engine.hpp:42
_v
Definition: Exception.hpp:26
bool proxiableBit() const
Definition: Message.hpp:622
void setHopByHop(U32 hbh)
Definition: Message.hpp:303
void setProxiableBit(bool activate=true)
Definition: Message.hpp:262
Definition: Node.hpp:56
bool removeAvp(AvpId id, int ocurrence=1) noexcept(false)
Definition: Message.hpp:488
void setPotentiallyReTransmittedMessageBit(bool activate=true)
Definition: Message.hpp:280
bool isAnswer() const
Definition: Message.hpp:593
uint32_t U32
Definition: defines.hpp:75
bool isRequest() const
Definition: Message.hpp:588
std::pair< S32, S32 > AvpId
Definition: defines.hpp:31
const Avp * getAvp(const char *name, int ocurrence=1, anna::Exception::Mode::_v emode=anna::Exception::Mode::Throw) const noexcept(false)
Definition: Message.hpp:671
void setEndToEnd(U32 ete)
Definition: Message.hpp:309
Definition: Avp.hpp:125
bool requestBit() const
Definition: Message.hpp:619
Engine * a_engine
Definition: Message.hpp:150
Definition: Message.hpp:74
U32 U24
Definition: defines.hpp:96
std::string asXMLString(bool normalize=false) const
int countAvp(AvpId id) const
Definition: Message.hpp:686
const CommandId & getId() const
Definition: Message.hpp:576
const anna::diameter::stack::Command * getStackCommand() const noexcept(false)
Definition: Message.hpp:616
bool potentiallyReTransmittedMessageBit() const
Definition: Message.hpp:628
unsigned char U8
Definition: defines.hpp:62
U8 getVersion() const
Definition: Message.hpp:583
Definition: Command.hpp:48
void setErrorBit(bool activate=true)
Definition: Message.hpp:271
Definition: app.hpp:12
const Avp * getAvp(AvpId id, int ocurrence=1, anna::Exception::Mode::_v emode=anna::Exception::Mode::Throw) const noexcept(false)
Definition: Message.hpp:659
Avp * getAvp(AvpId id, int ocurrence=1, anna::Exception::Mode::_v emode=anna::Exception::Mode::Throw) noexcept(false)
Definition: Message.hpp:663
std::pair< U24, bool > CommandId
Definition: defines.hpp:32
bool errorBit() const
Definition: Message.hpp:625
std::map< find_key, Avp * > find_container
Definition: Avp.hpp:83
avp_container::iterator avp_iterator
Definition: Avp.hpp:78
Definition: DataBlock.hpp:24
const U32 & getEndToEnd() const
Definition: Message.hpp:611
Definition: functions.hpp:118
const U32 & getHopByHop() const
Definition: Message.hpp:605
const U32 & getApplicationId() const
Definition: Message.hpp:599
std::map< int, Avp *> avp_container
Definition: Avp.hpp:74
Avp * addAvp(AvpId id) noexcept(false)
Definition: Message.hpp:457