563b501bd592b2598ce8995cc2ab975ce1d306a7
[anna.git] / include / anna / diameter / codec / functions.hpp
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_functions_hpp
10 #define anna_diameter_codec_functions_hpp
11
12
13 // Project
14 #include <anna/diameter/defines.hpp>
15 #include <anna/core/RuntimeException.hpp>
16 #include <anna/xml/xml.hpp>
17
18 // STL
19 #include <string>
20 #include <vector>
21
22
23 //------------------------------------------------------------------------------
24 //---------------------------------------------------------------------- #define
25 //------------------------------------------------------------------------------
26
27 // Diameter words are four-byte size. Store n bytes requires 1 word more than former multiple of 4:
28 #define REQUIRED_WORDS(bytes)  ((bytes)/4+((((bytes)%4)!=0)?1:0 ))
29
30
31
32 namespace anna {
33 class DataBlock;
34 }
35
36
37 namespace anna {
38
39 namespace diameter {
40
41 namespace codec {
42
43
44 static const char *MessageDTD = "\
45 <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
46 <!-- Diameter message DTD -->\n\
47 \n\
48 <!ELEMENT message (avp*)>\n\
49 <!ELEMENT avp (avp*)>\n\
50 \n\
51 <!ATTLIST message version CDATA #IMPLIED name CDATA #IMPLIED code CDATA #IMPLIED flags CDATA #IMPLIED p-bit (yes | no) #IMPLIED e-bit (yes | no) #IMPLIED t-bit (yes | no) #IMPLIED application-id CDATA #REQUIRED hop-by-hop-id CDATA #IMPLIED end-to-end-id CDATA #IMPLIED>\n\
52 <!--\n\
53    version: Diameter version. Sets '1' by default\n\
54    name:    Command name within working stack (dictionary identifier)\n\
55    p-bit:   (P)roxiable bit flag (yes, no). By default is 'no'\n\
56    e-bit:   (E)rror bit flag (yes, no). By default is 'no'\n\
57    t-bit:   Potentially re-(T)ransmitted bit flag (yes, no). By default is 'no'\n\
58 \n\
59    In order to get more coding capabilities, command code and flags could be established instead of former fields,\n\
60     but neither of them are allowed if the other are present (and vice versa):\n\
61 \n\
62    code:    Command code\n\
63    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\n\
64 \n\
65 \n\
66    application-id:   Message application id\n\
67    hop-by-hop-id:    Message hop by hop id. Sets '0' by default\n\
68    end-to-end-id:    Message end to end id. Sets '0' by default\n\
69 -->\n\
70 \n\
71 <!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED alias CDATA #IMPLIED>\n\
72 <!--\n\
73    name:   Avp name within working stack (dictionary identifier)\n\
74 \n\
75    In order to get more coding capabilities, avp code, vendor-id and flags could be established instead of former avp name,\n\
76     but neither of them are allowed if 'name' is provided (and vice versa):\n\
77 \n\
78    code:          Avp code\n\
79    vendor-code:   Avp vendor code\n\
80    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)\n\
81    alias:         Descriptive/helper field for certain numeric data values. Aliases are defined at diameter dictionary, but are ignored (not checked) at xml message parsing\n\
82                   The reason to include it in dtd definition, is because xml messages traced by the diameter codec could add alias field for some Avps\n\
83 \n\
84 \n\
85    data:          Natural string representation for avp data. Specially applicable with numbers and printable strings, but also\n\
86                    useful for certain formats which could be easily understandable in such friendly/smart representation. We will\n\
87                    achieve different human-readable strings depending on data format:\n\
88 \n\
89                      [ OctetString ] (if printable, but not recommended)\n\
90                      [ Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64 ] (normal number representation)\n\
91                      [ Time ] (NTP timestamp, normal number representation)\n\
92                      [ Address ] ('<type (IANA Address Family Number)>|<value>' representation; i.e. '1|192.168.0.1'(IPv4), '8|34616279266'(E164), etc.\n\
93                                  Type (and pipe) field could be avoided for IPv4 and IPv6 address types (a light parse checking is done: one colon for\n\
94                                  IPv6, one dot for IPv4). Internal engine always includes type on data field, which is also recommended for inputs.\n\
95                                  Currently, only IPv4, IPv6 and E164 address types have a known printable presentation, anyway using printable format\n\
96                                  for another types will encode the address value directly as E164 does)\n\
97                      [ UTF8String, DiameterIdentity, DiameterURI ] (printable)\n\
98                      [ IPFilterRule, QoSFilterRule ] (uses ASCII charset, printable)\n\
99 \n\
100                      New application formats must define specific natural representation for internal raw data\n\
101 \n\
102    hex-data:      Hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits). Suitable for whatever kind\n\
103                    of diameter format, but mandatory for non printable information. OctetString usually transport non human-readable\n\
104                    data and should better be encoded within this field although being printable. Unknown avps (which fails identifying\n\
105                    provided name or code/vendor-code) must always use this representation.\n\
106 \n\
107    Xml representation for decoded messages shows natural content except for 'OctetString' format and unknown avps. Anyway, when printable,\n\
108     OctetString could show such information at data field apart from hex-data, because many implementations use this format to transport\n\
109     readable-string data. In general, one of the data fields is mandatory except for 'Grouped' type (its data is another level of avps).\n\
110    Application-specific formats must decide the way to represent its contents, being recommended to use a natural representation if possible,\n\
111     because xml is read by humans with testing and monitoring purposes.\n\
112 -->\n\
113 \n\
114 ";
115
116
117
118
119 // Used for alarms, tracing and Failed-AVP construction:
120 typedef struct parent {
121
122   // Used on decoding:
123   anna::diameter::CommandId MessageId;
124   std::string MessageName;
125
126   std::vector<anna::diameter::AvpId> AvpsId;
127   std::vector<std::string> AvpsName;
128
129   void setMessage(const anna::diameter::CommandId & mid, const char *mname = NULL /* well known in validation */) throw();
130   void addAvp(const anna::diameter::AvpId & aid, const char *aname = NULL /* well known in validation */) throw();
131   std::string asString() const throw();
132
133 } parent_t;
134
135
136
137
138 struct functions {
139
140   // getters & helpers
141   static CommandId getCommandId(const anna::DataBlock &) throw(anna::RuntimeException);
142   static ApplicationId getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException);
143   static HopByHop getHopByHop(const anna::DataBlock &) throw(anna::RuntimeException);
144   static EndToEnd getEndToEnd(const anna::DataBlock &) throw(anna::RuntimeException);
145
146   static bool requestBit(const anna::DataBlock &) throw(anna::RuntimeException);
147   static bool proxiableBit(const anna::DataBlock &) throw(anna::RuntimeException);
148   static bool errorBit(const anna::DataBlock &) throw(anna::RuntimeException);
149   static bool potentiallyReTransmittedMessageBit(const anna::DataBlock &) throw(anna::RuntimeException);
150
151   static bool isRequest(const CommandId & cid) throw() { return (cid.second); }
152   static bool isRequest(const anna::DataBlock & db) throw(anna::RuntimeException) { return requestBit(db); }
153
154   static bool isAnswer(const CommandId & cid) throw() { return (!isRequest(cid)); }
155   static bool isAnswer(const anna::DataBlock & db) throw(anna::RuntimeException) { return (!isRequest(db)); }
156
157
158
159   /**
160    * Decodes a Command Header. This helper cannot check boundaries. start pointer must be a valid command context.
161    *
162    * @param start Must be a valid command start (point to the command version byte).
163    * @param version Diameter version.
164    * @param length Message length.
165    * @param flags Command flags.
166    * @param id Command identification (code, request<true,false>).
167    * @param appId Application-ID.
168    * @param hbh Hop-by-Hop Identifier.
169    * @param ete End-to-End Identifier.
170    */
171   static void decodeCommandHeader(const char *start, char & version, U24 & length, char & flags, CommandId & id, int & appId, int & hbh, int & ete) throw(anna::RuntimeException);
172
173   /**
174    * Decodes an AVP. This helper cannot check boundaries. start pointer must be a valid avp context.
175    *
176    * @param start Must be a valid avp start (point to the 32-bits avp code word).
177    * @param id Avp identification (code, vendorId).
178    * @param flags Avp flags byte.
179    * @param length Avp length (includes code, flags, length itself, vendorId if exists and data length).
180    * @param data Avp data part.
181    */
182   static void decodeAVP(const char *start, AvpId & id, char & flags, int & length, std::string & data) throw(anna::RuntimeException);
183
184   /**
185    * Gets the next AVP pointer reference starting from a first-avp data block. It could be the first avp within
186    * a command, or within an grouped avp.
187    *
188    * @param avpsDB AVP data block buffer pointer
189    * @param avpsLen AVP data block buffer length
190    * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word).
191    *
192    * @return Pointer to the next AVP found. NULL if no more.
193    */
194   static const char * nextAVP(const char *avpsDB, int avpsLen, const char *start) throw(anna::RuntimeException);
195
196   //  /**
197   //  * Gets the next AVP pointer reference starting from a first-avp datablock. It could be the first avp within
198   //  * a command, or within an grouped avp.
199   //  *
200   //  * @param avpsDB AVPs set as datablock
201   //  * @param start Point to start the search. Must be a valid avp start (point to the 32-bits avp code word).
202   //  *
203   //  * @return Pointer to the next AVP found. NULL if no more.
204   //  */
205   //  static const char * nextAVP(const anna::DataBlock & avpsDB, const char *start) throw(anna::RuntimeException);
206
207   /**
208    * Gets the next AVP pointer reference within an AVPs set data block with a certain AVP identification.
209    *
210    * @param avpsDB AVP data block buffer pointer
211    * @param avpsLen AVP data block buffer length
212    * @param id Avp identification (code, vendorId).
213    * @param n Ocurrence number (first avp, second avp, etc.). 1 by default.
214    *
215    * @return Pointer to first AVP found with identification provided. NULL if not found.
216    */
217   static const char *findAVP(const char *avpsDB, int avpsLen, const diameter::AvpId & id, int n = 1) throw(anna::RuntimeException);
218
219   //  /**
220   //  * Gets the next AVP pointer reference within an AVPs set datablock with a certain AVP identification.
221   //  *
222   //  * @param avpsDB AVPs set as datablock
223   //  * @param id Avp identification (code, vendorId).
224   //  * @param n Ocurrence number (first avp, second avp, etc.). 1 by default.
225   //  *
226   //  * @return Pointer to first AVP found with identification provided. NULL if not found.
227   //  */
228   //  static const char * findAVP(const anna::DataBlock & avpsDB, const AvpId & id, int n = 1) throw(anna::RuntimeException);
229
230
231
232   // modifiers
233   static void setHopByHop(anna::DataBlock &, HopByHop) throw(anna::RuntimeException);
234   static void setEndToEnd(anna::DataBlock &, EndToEnd) throw(anna::RuntimeException);
235   static void setPotentiallyReTransmittedMessageBit(const anna::DataBlock & db, bool activate = true) throw(anna::RuntimeException);
236
237
238   /**
239      Interpret a xml file in order to create a memory xml document.
240      The xml file is based on this message DTD:
241
242      <pre>
243      <!ELEMENT message (avp*)>
244      <!ELEMENT avp (avp*)>
245
246      <!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-to-end-id CDATA #IMPLIED>
247      <!--
248         version: Diameter version. Sets '1' by default
249         name:    Command name within working stack (dictionary identifier)
250
251         In order to get more coding capabilities, command code and flags could be established instead of former command name,
252          but neither of them are allowed if 'name' is provided (and vice versa):
253
254         code:    Command code
255         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
256
257
258         application-id:   Message application id
259         hop-by-hop-id:    Message hop by hop id. Sets '0' by default
260         end-to-end-id:    Message end to end id. Sets '0' by default
261      -->
262
263      <!ATTLIST avp name CDATA #IMPLIED code CDATA #IMPLIED vendor-code CDATA #IMPLIED flags CDATA #IMPLIED data CDATA #IMPLIED hex-data CDATA #IMPLIED>
264      <!--
265         name:   Avp name within working stack (dictionary identifier)
266
267         In order to get more coding capabilities, avp code, vendor-id and flags could be established instead of former avp name,
268          but neither of them are allowed if 'name' is provided (and vice versa):
269
270         code:          Avp code
271         vendor-code:   Avp vendor code
272         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)
273
274
275         data:          Natural string representation for avp data. Specially applicable with numbers and printable strings, but also
276                         useful for certain formats which could be easily understandable in such friendly/smart representation. We will
277                         achieve different human-readable strings depending on data format:
278
279                           [ OctetString ] (if printable, but not recommended)
280                           [ Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64 ] (normal number representation)
281                           [ Time ] (NTP timestamp, normal number representation)
282                           [ Address ] (auto detects IPv4 or IPv6 address version, then only ip address is specified: IPv4 with dots, IPv6 with colons)
283                           [ UTF8String, DiameterIdentity, DiameterURI ] (printable)
284                           [ IPFilterRule, QoSFilterRule ] (uses ASCII charset, printable)
285
286                           New application formats must define specific natural representation for internal raw data
287
288         hex-data:      Hexadecimal octet sequence representation (i.e. 'af012fb3', with even number of digits). Suitable for whatever kind
289                         of diameter format, but mandatory for non printable information. OctetString usually transport non human-readable
290                         data and should better be encoded within this field although being printable. Unknown avps (which fails identifying
291                         provided name or code/vendor-code) must always use this representation.
292
293         Xml representation for decoded messages shows natural content except for 'OctetString' format and unknown avps. Anyway, when printable,
294          OctetString could show such information at data field apart from hex-data, because many implementations use this format to transport
295          readable-string data. In general, one of the data fields is mandatory except for 'Grouped' type (its data is another level of avps).
296         Application-specific formats must decide the way to represent its contents, being recommended to use a natural representation if possible,
297          because xml is read by humans with testing and monitoring purposes.
298      -->
299      </pre>
300
301      @param xmlDocument XML document allocated by the user of the function (anna::xml::DocumentMemory xmlDocument)
302      @param xmlPathFile Complete path file to the xml document which represents the diameter message
303      @see messageXmlDocumentFromXmlString
304
305      @warning Whatever you will do with the xml document, will be only valid inside the scope of such xml document.
306      For example, you could load the document to be decoded over a codec Message by mean #Message::fromXML (using
307      the xml document #getRootNode) during document lifetime. After that, it could be destroyed.
308    */
309   static void messageXmlDocumentFromXmlFile(anna::xml::DocumentFile &xmlDocument, const std::string & xmlPathFile) throw(anna::RuntimeException);
310
311   /**
312      Interpret xml string representation in order to create a memory xml document.
313      DTD validation is used in the same way that #messageXmlDocumentFromXmlFile does.
314
315      @param xmlDocument XML document allocated by the user of the function (anna::xml::DocumentMemory xmlDocument)
316      @param xmlString XML string representation of the diameter message
317      @see messageXmlDocumentFromXmlFile
318
319      @warning Whatever you will do with the xml document, will be only valid inside the scope of such xml document.
320      For example, you could load the document to be decoded over a codec Message by mean #Message::fromXML (using
321      the xml document #getRootNode) during document lifetime. After that, it could be destroyed.
322    */
323   static void messageXmlDocumentFromXmlString(anna::xml::DocumentFile &xmlDocument, const std::string &xmlString) throw(anna::RuntimeException);
324 };
325
326
327 }
328 }
329 }
330
331
332 #endif
333