First commit
[anna.git] / include / anna / diameter / codec / basetypes / AvpData.hpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
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 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.
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_basetypes_AvpData_hpp
38 #define anna_diameter_codec_basetypes_AvpData_hpp
39
40
41 #include <anna/core/RuntimeException.hpp>
42 #include <anna/core/DataBlock.hpp>
43 #include <anna/core/functions.hpp>
44
45 #include <anna/core/functions.hpp>
46
47 // STL
48 #include <string>
49
50
51 namespace anna {
52
53 namespace diameter {
54
55 namespace codec {
56
57 namespace basetypes {
58
59 /**
60 * Diameter avp abstract data container
61 *
62 * All diameter types inherit from this class. Basic types with one level, derived ones with two levels.
63 * Three or more inheritance levels have no sense. Each level has own private members and updateBasic()
64 * will be implemented at derived types to keep coherence towards parent ones. This coherence implies to
65 * call updateBasic when private members are updated.
66 *
67 *<pre>
68 * Basic diameter types are:      OctetString, Integer32, Integer64, Unsigned32, Unsigned64, Float32, Float64
69 * Derived diameter types are:    Address, Time, UTF8String, DiameterIdentity, DiameterURI, IPFilterRule, QoSFilterRule (derived from OctetString)
70 *                                Enumerated (derived from Integer32)
71 * Printable derived types are:   UTF8String, DiameterIdentity, DiameterURI, IPFilterRule, QoSFilterRule
72 *
73 * User application could create new diameter types derived for any basic one, and reimplement the methods to adjust its behaviour.
74 *
75 *</pre>
76 *
77 * There are setters/getters at any level, and a lot of helpers to decode/interpret the stored data.
78 * Then, this class could be used as container and/or helper tool.
79 * Parent setters won't modify child members and vice versa, but helpers syncronizes both levels through parent 'code()' and child 'decode()' methods.
80 *
81 * Derived types with own members, must use protected or private inheritance, and export base class methods desired (using declaration).
82 * This mechanism guarantees private members coherence between different levels: a derived type instance couldn't directly manipulate base class own members.
83 */
84 class AvpData {
85
86   /**
87   * Encodes the avp data part over target buffer.
88   * THIS WILL BE IMPLEMENTED AT BASIC TYPES because works with parent members
89   *
90   * @param buffer Raw data to be encoded
91   * @param size Size of raw data to be encoded
92   */
93   virtual void codeBasic(char* buffer, int &size) throw(anna::RuntimeException) = 0;
94
95   /**
96   * Updates parent members from child ones to keep coherence between levels.
97   * Neither of diameter basic types need to be checked and have no parents,
98   * then THIS WILL BE IMPLEMENTED AT DERIVED TYPES WITH NEW MEMBERS (not, i.e. at Enumerated)
99   * and will be called after child members modification (setters).
100   * Basic types implementation will be empty.
101   */
102   virtual void updateBasic() throw(anna::RuntimeException) {;}
103
104   /**
105   * Sets own members from natural/smart string representation
106   * String argument is never provided NULL (internally checked)
107   *
108   * @param printableString avp data in natural/smart string representation (human-readable)
109   */
110   virtual void setPrintableString(const char * printableString) throw(anna::RuntimeException) = 0;
111
112
113 protected:
114
115   /**
116   * Asserts printable nature for buffer provided and launch exception if not.
117   * Must be invoked from 'updateBasic() and decode()' at derived diameter types, when buffer should be printable
118   *
119   * @param buffer Raw avp data
120   * @param size Raw avp data length
121   *
122   * @return Printable string or <null> if not printable
123   */
124   std::string assertPrintable(const char* buffer, const int size) const throw(anna::RuntimeException) {
125     std::string result;
126
127     if(size == 0) return result;
128
129     bool printable;
130     result = anna::functions::asAsciiString(buffer, size, printable);
131
132     if(!printable) {
133       std::string ex = getFormatName();
134       ex += "::assertPrintable | Non-printable data provided";
135       throw anna::RuntimeException(ex, ANNA_FILE_LOCATION);
136     }
137
138     return result;
139   }
140
141 public:
142
143   /**
144   * Default constructor
145   */
146   AvpData() {};
147
148
149   // gets
150
151   /**
152   * Gets the avp data format name
153   *
154   * @return avp data format name
155   */
156   virtual std::string getFormatName() const throw() = 0;
157
158   /**
159   * Gets the avp data size based on basic container.
160   * The AVP Data field is zero or more octets.
161   *
162   * @return avp data size
163   */
164   virtual int getSize() const throw() = 0;
165
166
167   // helpers
168
169   /**
170   * Encodes avp data part over buffer externally allocated
171   *
172   * @param buffer Raw data to be encoded
173   * @param size Size of raw data to be encoded
174   */
175   void code(char* buffer, int &size) throw(anna::RuntimeException) {
176     codeBasic(buffer, size);
177   }
178
179
180   /**
181   * Gets the natural/smart string representation for avp data (format-dependent content)
182   * Used in diameter message 'data' field
183   * Default implementation launch exception when data is not printable
184   *
185   * @return Natural/smart string representation for avp data
186   */
187   virtual std::string asPrintableString() throw(anna::RuntimeException) {
188     int size = getSize();
189     char buffer[size];
190     code(buffer, size);
191     return (assertPrintable(buffer, size));
192   }
193
194   /**
195   * Gets DataBlock binary block and ascii representation
196   *
197   * @return String with DataBlock representation
198   */
199   std::string asDataBlockString() throw(anna::RuntimeException) {
200     int size = getSize();
201     char buffer[size];
202     code(buffer, size);
203     anna::DataBlock db(buffer, size);
204     return(db.asString());
205   }
206
207   /**
208   * Class string representation
209   * Default implementation invokes raw DataBlock 'asString' method,
210   * but it should be different specially with complex application data types.
211   *
212   * @return String with class content
213   */
214   virtual std::string asString() throw(anna::RuntimeException) {
215     return(asDataBlockString());
216   }
217
218   /**
219   * Gets the hexadecimal string representation for avp data
220   * Used in diameter message 'hex-data' field
221   *
222   * @return Hexadecimal string representation for avp data
223   */
224   std::string asHexString() throw(anna::RuntimeException) {
225     int size = getSize();
226     char buffer[size];
227     code(buffer, size);
228     anna::DataBlock db(buffer, size);
229     return anna::functions::asHexString(db);
230   }
231
232
233   // sets
234
235   /**
236   * Decodes provided buffer/size
237   *
238   * Derived types must invoke base class 'decode()' at the end in order to keep coherence with parent members.
239   * This base class decodification actually sets the base class members with the same buffer provided, being
240   * more comfortable than using base class setters.
241   *
242   * @param buffer Raw avp data
243   * @param size Raw avp data length
244   */
245   virtual void decode(const char* buffer, const int size) throw(anna::RuntimeException) = 0;
246
247   /**
248   * Initializes members from natural/smart string representation
249   *
250   * @param printableString avp data in natural/smart string representation (human-readable)
251   */
252   void fromPrintableString(const char * printableString) throw(anna::RuntimeException) {
253     if(!printableString) {
254       std::string ex = getFormatName();
255       ex += "::fromPrintableString | Null printableString provided";
256       throw anna::RuntimeException(ex, ANNA_FILE_LOCATION);
257     }
258
259     /*std::string dummy =*/assertPrintable(printableString, strlen(printableString));
260     setPrintableString(printableString);
261   }
262
263   /**
264   * Initializes members from hexadecimal string representation. I.e.: af1233fb01 (even number of digits).
265   *
266   * @param hexString Raw avp data in hexadecimal string representation
267   */
268   void fromHexString(const std::string& hexString) throw(anna::RuntimeException) {
269     anna::DataBlock db(true);
270     anna::functions::fromHexString(hexString, db);
271     decode(db.getData(), db.getSize());
272   }
273 };
274
275 }
276 }
277 }
278 }
279
280
281 #endif