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() noexcept(false) {
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) noexcept(false) {
118 // First: User will update child class members
120 iana_address_t address;
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("|");
130 if(pipePos != std::string::npos) {
132 throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source: missing type before pipe (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
134 std::string beforePipe(printableString, pipePos);
135 address.Version = atoi(beforePipe.c_str());
136 address.Value.assign(printableString, pipePos + 1, source.size() - pipePos - 1);
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);
145 throw anna::RuntimeException("Address::fromPrintableString | Unreconized printable source (see 'Diameter message DTD' for [ Address ] printable format)", ANNA_FILE_LOCATION);
149 setIANAAddress(address);
153 //------------------------------------------------------------------------------
154 //------------------------------------------------ Address::setPrintableString()
155 //------------------------------------------------------------------------------
156 std::string anna::diameter::codec::basetypes::Address::asPrintableString() noexcept(false) {
157 bool knownPrintablePresentation = (a_address.isIPv4() || a_address.isIPv6() || a_address.isE164());
159 if(!knownPrintablePresentation)
160 throw anna::RuntimeException("Address::asPrintableString | Only IPv4, IPv6 and E164 have a known printable presentation", ANNA_FILE_LOCATION);
162 return anna::functions::asString("%d|%s", a_address.getVersion(), a_address.getValue());
166 //------------------------------------------------------------------------------
167 //------------------------------------------------------------ Address::decode()
168 //------------------------------------------------------------------------------
169 void anna::diameter::codec::basetypes::Address::decode(const char* buffer, const int size) noexcept(false) {
171 throw anna::RuntimeException("Address::decode | Null Buffer provided", ANNA_FILE_LOCATION);
173 char str[INET6_ADDRSTRLEN];
177 throw anna::RuntimeException("Address::decode | At least 2 bytes needed to decode address version", ANNA_FILE_LOCATION);
179 a_address.Version = (((U16)buffer[0] << 8) & 0xFF00) +
180 ((U16)buffer[1] & 0x00FF); // two first octets
183 if(a_address.isIPv4()) { // 6 bytes
185 throw anna::RuntimeException("Address::decode | 2+4(=6) bytes needed to decode IPv4 address", ANNA_FILE_LOCATION);
187 if(a_abbreviatePresentation) {
188 if(inet_ntop(AF_INET, buffer + 2, str, INET_ADDRSTRLEN) != NULL) {
189 a_address.Value = str;
191 throw anna::RuntimeException("Address::decode | Error decoding IPv4 address", ANNA_FILE_LOCATION);
194 a_address.Value = anna::functions::asString("%d.%d.%d.%d", (U8)buffer[2], (U8)buffer[3], (U8)buffer[4], (U8)buffer[5]);
196 } else if(a_address.isIPv6()) { // 18 bytes
198 throw anna::RuntimeException("Address::decode | 2+16(=18) bytes needed to decode IPv6 address", ANNA_FILE_LOCATION);
200 if(a_abbreviatePresentation) {
201 if(inet_ntop(AF_INET6, buffer + 2, str, INET6_ADDRSTRLEN) != NULL) {
202 a_address.Value = str;
204 throw anna::RuntimeException("Address::decode | Error decoding IPv6 address", ANNA_FILE_LOCATION);
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));
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);
231 // Base class decode()
232 OctetString::decode(buffer, size);