1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
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 //
10 #include <anna/diameter/codec/basetypes/Address.hpp>
13 #include <arpa/inet.h>
15 #include <anna/core/functions.hpp>
18 //------------------------------------------------------------------------------
19 //------------------------------------------------------- Address::updateBasic()
20 //------------------------------------------------------------------------------
21 void anna::diameter::codec::basetypes::Address::updateBasic() throw(anna::RuntimeException) {
24 result.push_back((S8)(a_address.Version >> 8));
25 result.push_back((S8)a_address.Version);
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);
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]);
39 if(s < 0) perror("inet_pton");
41 throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION);
44 if(!anna::functions::isIPv4(a_address.Value))
45 throw anna::RuntimeException("Address::setValue | Wrong IPv4 address format", ANNA_FILE_LOCATION);
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);
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);
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]);
77 if(s < 0) perror("inet_pton");
79 throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION);
82 if(!anna::functions::isIPv6(a_address.Value))
83 throw anna::RuntimeException("Address::setValue | Wrong IPv6 address format", ANNA_FILE_LOCATION);
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));
104 } else if(a_address.isE164()) {
105 result += a_address.Value; // direct assignment
107 result += a_address.Value; // direct assignment
110 OctetString::setValue(result);
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
120 iana_address_t address;
124 // [ Address ] ('<type (IANA Address Family Number)>|<value>' representation; i.e. '1|192.168.0.1'(IPv4), '8|34616279266'(E164), etc.
125 // Type (and pipe) field could be avoided for IPv4 and IPv6 address types (a light parse checking is done: one colon for
126 // IPv6, one dot for IPv4). Internal engine always includes type on data field, which is also recommended for inputs.
127 // Currently, only IPv4, IPv6 and E164 address types have a known printable presentation)
128 std::string source = printableString;
129 size_t pipePos = source.find("|");
131 if(pipePos != std::string::npos) {
133 throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source: missing type before pipe (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
135 std::string beforePipe(printableString, pipePos);
136 address.Version = atoi(beforePipe.c_str());
137 address.Value.assign(printableString, pipePos + 1, source.size() - pipePos - 1);
139 // For backward compatibility (configurations, tests cases, etc.)
140 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
141 if(strstr(printableString, ":"))
142 address.setIPv6(printableString);
143 else if(strstr(printableString, "."))
144 address.setIPv4(printableString);
146 throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
150 setIANAAddress(address);
154 //------------------------------------------------------------------------------
155 //------------------------------------------------ Address::setPrintableString()
156 //------------------------------------------------------------------------------
157 std::string anna::diameter::codec::basetypes::Address::asPrintableString() throw(anna::RuntimeException) {
158 bool knownPrintablePresentation = (a_address.isIPv4() || a_address.isIPv6() || a_address.isE164());
160 if(!knownPrintablePresentation)
161 throw anna::RuntimeException("Address::asPrintableString | Only IPv4, IPv6 and E164 have a known printable presentation", ANNA_FILE_LOCATION);
163 return anna::functions::asString("%d|%s", a_address.getVersion(), a_address.getValue());
167 //------------------------------------------------------------------------------
168 //------------------------------------------------------------ Address::decode()
169 //------------------------------------------------------------------------------
170 void anna::diameter::codec::basetypes::Address::decode(const char* buffer, const int size) throw(anna::RuntimeException) {
172 throw anna::RuntimeException("Address::decode | Null Buffer provided", ANNA_FILE_LOCATION);
174 char str[INET6_ADDRSTRLEN];
178 throw anna::RuntimeException("Address::decode | At least 2 bytes needed to decode address version", ANNA_FILE_LOCATION);
180 a_address.Version = (((U16)buffer[0] << 8) & 0xFF00) +
181 ((U16)buffer[1] & 0x00FF); // two first octets
184 if(a_address.isIPv4()) { // 6 bytes
186 throw anna::RuntimeException("Address::decode | 2+4(=6) bytes needed to decode IPv4 address", ANNA_FILE_LOCATION);
188 if(a_abbreviatePresentation) {
189 if(inet_ntop(AF_INET, buffer + 2, str, INET_ADDRSTRLEN) != NULL) {
190 a_address.Value = str;
192 throw anna::RuntimeException("Address::decode | Error decoding IPv4 address", ANNA_FILE_LOCATION);
195 a_address.Value = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[2], (U8)buffer[3], (U8)buffer[4], (U8)buffer[5]);
197 } else if(a_address.isIPv6()) { // 18 bytes
199 throw anna::RuntimeException("Address::decode | 2+16(=18) bytes needed to decode IPv6 address", ANNA_FILE_LOCATION);
201 if(a_abbreviatePresentation) {
202 if(inet_ntop(AF_INET6, buffer + 2, str, INET6_ADDRSTRLEN) != NULL) {
203 a_address.Value = str;
205 throw anna::RuntimeException("Address::decode | Error decoding IPv6 address", ANNA_FILE_LOCATION);
208 a_address.Value = anna::functions::asString("%X:%X:%X:%X:%X:%X:%X:%X",
209 ((((U8)buffer[2]) << 8) & 0xFF00 /* same as (U16 cast)*/) +
210 (((U8)buffer[3]) & 0x00FF),
211 ((((U8)buffer[4]) << 8) & 0xFF00) +
212 (((U8)buffer[5]) & 0x00FF),
213 ((((U8)buffer[6]) << 8) & 0xFF00) +
214 (((U8)buffer[7]) & 0x00FF),
215 ((((U8)buffer[8]) << 8) & 0xFF00) +
216 (((U8)buffer[9]) & 0x00FF),
217 ((((U8)buffer[10]) << 8) & 0xFF00) +
218 (((U8)buffer[11]) & 0x00FF),
219 ((((U8)buffer[12]) << 8) & 0xFF00) +
220 (((U8)buffer[13]) & 0x00FF),
221 ((((U8)buffer[14]) << 8) & 0xFF00) +
222 (((U8)buffer[15]) & 0x00FF),
223 ((((U8)buffer[16]) << 8) & 0xFF00) +
224 (((U8)buffer[17]) & 0x00FF));
226 } else if(a_address.isE164()) { // n bytes = 2 + address length
227 a_address.Value.assign(buffer + 2, size - 2); // Direct assignment
228 } else { // Generic decoding (could support non printable addresses but they must be...)
229 a_address.Value.assign(buffer + 2, size - 2);
232 // Base class decode()
233 OctetString::decode(buffer, size);