Remove warnings
[anna.git] / source / diameter / codec / basetypes / Address.cpp
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 // Local
10 #include <anna/diameter/codec/basetypes/Address.hpp>
11
12 // Standard
13 #include <arpa/inet.h>
14
15 #include <anna/core/functions.hpp>
16
17
18 //------------------------------------------------------------------------------
19 //------------------------------------------------------- Address::updateBasic()
20 //------------------------------------------------------------------------------
21 void anna::diameter::codec::basetypes::Address::updateBasic() throw(anna::RuntimeException) {
22   std::string result;
23   // address version
24   result.push_back((S8)(a_address.Version >> 8));
25   result.push_back((S8)a_address.Version);
26
27   // address value
28   if(a_address.isIPv4()) {
29     if(a_abbreviatePresentation) {
30       unsigned char buf[sizeof(struct in6_addr)];
31       int s = inet_pton(AF_INET, a_address.Value.c_str(), buf);
32
33       if(s > 0) {
34         result.push_back((S8) buf[0]);
35         result.push_back((S8) buf[1]);
36         result.push_back((S8) buf[2]);
37         result.push_back((S8) buf[3]);
38       } else {
39         if(s < 0) perror("inet_pton");
40
41         throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION);
42       }
43     } else {
44       if(!anna::functions::isIPv4(a_address.Value))
45         throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION);
46
47       int dec1, dec2, dec3, dec4; // U32 type is valid, 'int' better: argument for %d must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
48       sscanf(a_address.Value.c_str(), "%d.%d.%d.%d", &dec1, &dec2, &dec3, &dec4);
49       result.push_back((S8) dec1);
50       result.push_back((S8) dec2);
51       result.push_back((S8) dec3);
52       result.push_back((S8) dec4);
53     }
54   } else if(a_address.isIPv6()) {
55     if(a_abbreviatePresentation) {
56       unsigned char buf[sizeof(struct in6_addr)];
57       int s = inet_pton(AF_INET6, a_address.Value.c_str(), buf);
58
59       if(s > 0) {
60         result.push_back((S8) buf[0]);
61         result.push_back((S8) buf[1]);
62         result.push_back((S8) buf[2]);
63         result.push_back((S8) buf[3]);
64         result.push_back((S8) buf[4]);
65         result.push_back((S8) buf[5]);
66         result.push_back((S8) buf[6]);
67         result.push_back((S8) buf[7]);
68         result.push_back((S8) buf[8]);
69         result.push_back((S8) buf[9]);
70         result.push_back((S8) buf[10]);
71         result.push_back((S8) buf[11]);
72         result.push_back((S8) buf[12]);
73         result.push_back((S8) buf[13]);
74         result.push_back((S8) buf[14]);
75         result.push_back((S8) buf[15]);
76       } else {
77         if(s < 0) perror("inet_pton");
78
79         throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION);
80       }
81     } else {
82       if(!anna::functions::isIPv6(a_address.Value))
83         throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION);
84
85       int hex1, hex2, hex3, hex4, hex5, hex6, hex7, hex8; // U16 type is not valid: argument for %X must be 'int *' (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/)
86       sscanf(a_address.Value.c_str(), "%X:%X:%X:%X:%X:%X:%X:%X", &hex1, &hex2, &hex3, &hex4, &hex5, &hex6, &hex7, &hex8);
87       result.push_back((S8)(hex1 >> 8));
88       result.push_back((S8)(hex1 & 0x00FF));
89       result.push_back((S8)(hex2 >> 8));
90       result.push_back((S8)(hex2 & 0x00FF));
91       result.push_back((S8)(hex3 >> 8));
92       result.push_back((S8)(hex3 & 0x00FF));
93       result.push_back((S8)(hex4 >> 8));
94       result.push_back((S8)(hex4 & 0x00FF));
95       result.push_back((S8)(hex5 >> 8));
96       result.push_back((S8)(hex5 & 0x00FF));
97       result.push_back((S8)(hex6 >> 8));
98       result.push_back((S8)(hex6 & 0x00FF));
99       result.push_back((S8)(hex7 >> 8));
100       result.push_back((S8)(hex7 & 0x00FF));
101       result.push_back((S8)(hex8 >> 8));
102       result.push_back((S8)(hex8 & 0x00FF));
103     }
104   } else if(a_address.isE164()) {
105     result += a_address.Value; // direct assignment
106   } else {
107     result += a_address.Value; // direct assignment
108   }
109
110   OctetString::setValue(result);
111 }
112
113
114 //------------------------------------------------------------------------------
115 //------------------------------------------------ Address::setPrintableString()
116 //------------------------------------------------------------------------------
117 void anna::diameter::codec::basetypes::Address::setPrintableString(const char * printableString) throw(anna::RuntimeException) {
118   // First: User will update child class members
119   // Auxiliary
120   iana_address_t address;
121   std::string value;
122   // From message.dtd:
123   // [ Address ] ('<type (IANA Address Family Number)>|<value>' representation; i.e. '1|192.168.0.1'(IPv4), '8|34616279266'(E164), etc.
124   //             Type (and pipe) field could be avoided for IPv4 and IPv6 address types (a light parse checking is done: one colon for
125   //             IPv6, one dot for IPv4). Internal engine always includes type on data field, which is also recommended for inputs.
126   //             Currently, only IPv4, IPv6 and E164 address types have a known printable presentation)
127   std::string source = printableString;
128   size_t pipePos = source.find("|");
129
130   if(pipePos != std::string::npos) {
131     if(pipePos == 0)
132       throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source: missing type before pipe (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
133
134     std::string beforePipe(printableString, pipePos);
135     address.Version = atoi(beforePipe.c_str());
136     address.Value.assign(printableString, pipePos + 1, source.size() - pipePos - 1);
137   }
138   // For backward compatibility (configurations, tests cases, etc.)
139   else { // only IPv4/v6 addresses are supported with a light checking (version pre-assumption): dot for IPv4, colon for IPv6. Anyway, updateBasic() will do regexp for supposed version
140     if(strstr(printableString, ":"))
141       address.setIPv6(printableString);
142     else if(strstr(printableString, "."))
143       address.setIPv4(printableString);
144     else
145       throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
146   }
147
148   // Assignments
149   setIANAAddress(address);
150 }
151
152
153 //------------------------------------------------------------------------------
154 //------------------------------------------------ Address::setPrintableString()
155 //------------------------------------------------------------------------------
156 std::string anna::diameter::codec::basetypes::Address::asPrintableString() throw(anna::RuntimeException) {
157   bool knownPrintablePresentation = (a_address.isIPv4() || a_address.isIPv6() || a_address.isE164());
158
159   if(!knownPrintablePresentation)
160     throw anna::RuntimeException("Address::asPrintableString | Only IPv4, IPv6 and E164 have a known printable presentation", ANNA_FILE_LOCATION);
161
162   return anna::functions::asString("%d|%s", a_address.getVersion(), a_address.getValue());
163 }
164
165
166 //------------------------------------------------------------------------------
167 //------------------------------------------------------------ Address::decode()
168 //------------------------------------------------------------------------------
169 void anna::diameter::codec::basetypes::Address::decode(const char* buffer, const int size) throw(anna::RuntimeException) {
170   if(!buffer)
171     throw anna::RuntimeException("Address::decode | Null Buffer provided", ANNA_FILE_LOCATION);
172
173   char str[INET6_ADDRSTRLEN];
174
175   // IP Version
176   if(size < 2)
177     throw anna::RuntimeException("Address::decode | At least 2 bytes needed to decode address version", ANNA_FILE_LOCATION);
178
179   a_address.Version = (((U16)buffer[0] << 8) & 0xFF00) +
180                       ((U16)buffer[1]        & 0x00FF); // two first octets
181
182   // IP Address
183   if(a_address.isIPv4()) {  // 6 bytes
184     if(size != 6)
185       throw anna::RuntimeException("Address::decode | 2+4(=6) bytes needed to decode IPv4 address", ANNA_FILE_LOCATION);
186
187     if(a_abbreviatePresentation) {
188       if(inet_ntop(AF_INET, buffer + 2, str, INET_ADDRSTRLEN) != NULL) {
189         a_address.Value = str;
190       } else {
191         throw anna::RuntimeException("Address::decode | Error decoding IPv4 address", ANNA_FILE_LOCATION);
192       }
193     } else {
194       a_address.Value = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[2], (U8)buffer[3], (U8)buffer[4], (U8)buffer[5]);
195     }
196   } else if(a_address.isIPv6()) {  // 18 bytes
197     if(size != 18)
198       throw anna::RuntimeException("Address::decode | 2+16(=18) bytes needed to decode IPv6 address", ANNA_FILE_LOCATION);
199
200     if(a_abbreviatePresentation) {
201       if(inet_ntop(AF_INET6, buffer + 2, str, INET6_ADDRSTRLEN) != NULL) {
202         a_address.Value = str;
203       } else {
204         throw anna::RuntimeException("Address::decode | Error decoding IPv6 address", ANNA_FILE_LOCATION);
205       }
206     } else {
207       a_address.Value = anna::functions::asString("%X:%X:%X:%X:%X:%X:%X:%X",
208                         ((((U8)buffer[2]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
209                         (((U8)buffer[3])        & 0x00FF),
210                         ((((U8)buffer[4]) << 8) & 0xFF00) +
211                         (((U8)buffer[5])        & 0x00FF),
212                         ((((U8)buffer[6]) << 8) & 0xFF00) +
213                         (((U8)buffer[7])        & 0x00FF),
214                         ((((U8)buffer[8]) << 8) & 0xFF00) +
215                         (((U8)buffer[9])        & 0x00FF),
216                         ((((U8)buffer[10]) << 8) & 0xFF00) +
217                         (((U8)buffer[11])        & 0x00FF),
218                         ((((U8)buffer[12]) << 8) & 0xFF00) +
219                         (((U8)buffer[13])        & 0x00FF),
220                         ((((U8)buffer[14]) << 8) & 0xFF00) +
221                         (((U8)buffer[15])        & 0x00FF),
222                         ((((U8)buffer[16]) << 8) & 0xFF00) +
223                         (((U8)buffer[17])        & 0x00FF));
224     }
225   } else if(a_address.isE164()) {  // n bytes = 2 + address length
226     a_address.Value.assign(buffer + 2, size - 2);  // Direct assignment
227   } else { // Generic decoding (could support non printable addresses but they must be...)
228     a_address.Value.assign(buffer + 2, size - 2);
229   }
230
231   // Base class decode()
232   OctetString::decode(buffer, size);
233 }