comparison libfdproto/dictionary_functions.c @ 922:c7bf1a7a4e90

Split the encoders/interpreters for the dictionary types into a different file for better reusability, add decoder/interpreter for Time type based on code from Thomas Klausner
author Sebastien Decugis <sdecugis@freediameter.net>
date Thu, 14 Feb 2013 15:43:36 +0100
parents
children 6a4d08e239bd
comparison
equal deleted inserted replaced
921:a0ab56aa089f 922:c7bf1a7a4e90
1 /*********************************************************************************************************
2 * Software License Agreement (BSD License) *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net> *
4 * *
5 * Copyright (c) 2013, WIDE Project and NICT *
6 * All rights reserved. *
7 * *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are *
9 * permitted provided that the following conditions are met: *
10 * *
11 * * Redistributions of source code must retain the above *
12 * copyright notice, this list of conditions and the *
13 * following disclaimer. *
14 * *
15 * * Redistributions in binary form must reproduce the above *
16 * copyright notice, this list of conditions and the *
17 * following disclaimer in the documentation and/or other *
18 * materials provided with the distribution. *
19 * *
20 * * Neither the name of the WIDE Project or NICT nor the *
21 * names of its contributors may be used to endorse or *
22 * promote products derived from this software without *
23 * specific prior written permission of WIDE Project and *
24 * NICT. *
25 * *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34 *********************************************************************************************************/
35
36 #include "fdproto-internal.h"
37
38 /* This file contains helpers functions to be reused as callbacks in the struct dict_type_data structure.
39 There are three callbacks there:
40
41 - type_encode :
42 - type_interpret :
43 Those two callbacks allow to manipulate more natural structures of data in the code, and to
44 map transparently these natural structures with the AVP-encoded format by calling the functions
45 msg_avp_value_encode or msg_avp_value_interpret.
46 - type_dump :
47 This callback if provided gives a more human-readable debug information.
48
49 */
50
51 /****************************/
52 /* Address AVP type */
53 /****************************/
54
55 /* The interpret and encode functions work with a "struct sockaddr_storage" pointer for mapping
56 the contents of the AVP */
57
58 int fd_dictfct_Address_encode(void * data, union avp_value * avp_value)
59 {
60 sSS * ss = (sSS *) data;
61 uint16_t AddressType = 0;
62 size_t size = 0;
63 unsigned char * buf = NULL;
64
65 TRACE_ENTRY("%p %p", data, avp_value);
66 CHECK_PARAMS( data && avp_value );
67
68 switch (ss->ss_family) {
69 case AF_INET:
70 {
71 /* We are encoding an IP address */
72 sSA4 * sin = (sSA4 *)ss;
73
74 AddressType = 1;/* see http://www.iana.org/assignments/address-family-numbers/ */
75 size = 6; /* 2 for AddressType + 4 for data */
76
77 CHECK_MALLOC( buf = malloc(size) );
78
79 /* may not work because of alignment: *(uint32_t *)(buf+2) = htonl(sin->sin_addr.s_addr); */
80 memcpy(buf + 2, &sin->sin_addr.s_addr, 4);
81 }
82 break;
83
84 case AF_INET6:
85 {
86 /* We are encoding an IPv6 address */
87 sSA6 * sin6 = (sSA6 *)ss;
88
89 AddressType = 2;/* see http://www.iana.org/assignments/address-family-numbers/ */
90 size = 18; /* 2 for AddressType + 16 for data */
91
92 CHECK_MALLOC( buf = malloc(size) );
93
94 /* The order is already good here */
95 memcpy(buf + 2, &sin6->sin6_addr.s6_addr, 16);
96 }
97 break;
98
99 default:
100 CHECK_PARAMS( AddressType = 0 );
101 }
102
103 *(uint16_t *)buf = htons(AddressType);
104
105 avp_value->os.len = size;
106 avp_value->os.data = buf;
107
108 return 0;
109 }
110
111 int fd_dictfct_Address_interpret(union avp_value * avp_value, void * interpreted)
112 {
113 uint16_t AddressType = 0;
114 unsigned char * buf;
115
116 TRACE_ENTRY("%p %p", avp_value, interpreted);
117
118 CHECK_PARAMS( avp_value && interpreted && (avp_value->os.len >= 2) );
119
120 AddressType = ntohs(*(uint16_t *)avp_value->os.data);
121 buf = &avp_value->os.data[2];
122
123 switch (AddressType) {
124 case 1 /* IP */:
125 {
126 sSA4 * sin = (sSA4 *)interpreted;
127
128 CHECK_PARAMS( avp_value->os.len == 6 );
129
130 sin->sin_family = AF_INET;
131 /* sin->sin_addr.s_addr = ntohl( * (uint32_t *) buf); -- may not work because of bad alignment */
132 memcpy(&sin->sin_addr.s_addr, buf, 4);
133 }
134 break;
135
136 case 2 /* IP6 */:
137 {
138 sSA6 * sin6 = (sSA6 *)interpreted;
139
140 CHECK_PARAMS( avp_value->os.len == 18 );
141
142 sin6->sin6_family = AF_INET6;
143 memcpy(&sin6->sin6_addr.s6_addr, buf, 16);
144 }
145 break;
146
147 default:
148 CHECK_PARAMS( AddressType = 0 );
149 }
150
151 return 0;
152 }
153
154 /* Dump the content of an Address AVP */
155 char * fd_dictfct_Address_dump(union avp_value * avp_value)
156 {
157 char * ret;
158 #define STR_LEN 1024
159 union {
160 sSA sa;
161 sSS ss;
162 sSA4 sin;
163 sSA6 sin6;
164 } s;
165 uint16_t fam;
166
167 memset(&s, 0, sizeof(s));
168
169 CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
170
171 /* The first two octets represent the address family, http://www.iana.org/assignments/address-family-numbers/ */
172 if (avp_value->os.len < 2) {
173 snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
174 return ret;
175 }
176
177 /* Following octets are the address in network byte order already */
178 fam = avp_value->os.data[0] << 8 | avp_value->os.data[1];
179 switch (fam) {
180 case 1:
181 /* IP */
182 s.sa.sa_family = AF_INET;
183 if (avp_value->os.len != 6) {
184 snprintf(ret, STR_LEN, "[invalid IP length: %zd]", avp_value->os.len);
185 return ret;
186 }
187 memcpy(&s.sin.sin_addr.s_addr, avp_value->os.data + 2, 4);
188 break;
189 case 2:
190 /* IP6 */
191 s.sa.sa_family = AF_INET6;
192 if (avp_value->os.len != 18) {
193 snprintf(ret, STR_LEN, "[invalid IP6 length: %zd]", avp_value->os.len);
194 return ret;
195 }
196 memcpy(&s.sin6.sin6_addr.s6_addr, avp_value->os.data + 2, 16);
197 break;
198 default:
199 snprintf(ret, STR_LEN, "[unsupported family: 0x%hx]", fam);
200 return ret;
201 }
202
203 {
204 int rc = getnameinfo(&s.sa, sSAlen(&s.sa), ret, STR_LEN, NULL, 0, NI_NUMERICHOST);
205 if (rc)
206 snprintf(ret, STR_LEN, "%s", (char *)gai_strerror(rc));
207 }
208
209 return ret;
210 }
211
212
213
214 /*******************************/
215 /* UTF8String AVP type */
216 /*******************************/
217
218 /* Dump the AVP in a natural human-readable format */
219 char * fd_dictfct_UTF8String_dump(union avp_value * avp_value)
220 {
221 #define TRUNC_LEN 42 /* avoid very long strings */
222 char * ret = strndup((char *)avp_value->os.data, TRUNC_LEN);
223 if (ret && (*ret != '\0')) {
224 /* We sanitize the returned string to avoid UTF8 boundary problem.
225 We do this whether the string is trucated at TRUNC_LEN or not, to avoid potential problem
226 with malformed AVP */
227
228 char * end = strchr(ret, '\0');
229
230
231 }
232 return ret;
233 }
234
235
236 /*******************************/
237 /* Time AVP type */
238 /*******************************/
239
240 /* The interpret and encode functions work with a "time_t" pointer for mapping
241 the contents of the AVP */
242
243 /* Unix Epoch starts 1970-01-01, NTP 0 is at 1900-01-01 */
244 #define DIFF_EPOCH_TO_NTP ((365*(1970-1900) + 17ul) * 24 * 60 * 60)
245
246 static int diameter_string_to_time_t(const char *str, size_t len, time_t *result) {
247 time_t time_stamp;
248 CHECK_PARAMS(len == 4);
249
250 time_stamp = (((unsigned long)(str[0]&0xff))<<24) + ((str[1]&0xff)<<16) + ((str[2]&0xff)<<8) + ((str[3]&0xff));
251 time_stamp -= DIFF_EPOCH_TO_NTP;
252 #ifdef FIX__NEEDED_FOR_YEAR_2036_AND_LATER
253 /* NTP overflows in 2036; after that, values start at zero again */
254 #define NTP_OVERFLOW_CORRECTION (0x100000000ull)
255 /* XXX: debug and find correct conversion */
256 if (str[0] & 0x80 == 0x00) {
257 time_stamp += NTP_OVERFLOW_CORRECTION;
258 }
259 #endif
260 *result = time_stamp;
261 return 0;
262 }
263
264 static int time_t_to_diameter_string(time_t time_stamp, char **result) {
265 uint64_t out = time_stamp;
266 char *conv;
267 /* XXX: 2036 fix */
268 out += DIFF_EPOCH_TO_NTP;
269 CHECK_PARAMS( (out & 0xffffffff00000000) == 0);
270
271 CHECK_MALLOC(conv=(char *)malloc(5));
272
273 conv[0] = (out>>24) & 0xff;
274 conv[1] = (out>>16) & 0xff;
275 conv[2] = (out>> 8) & 0xff;
276 conv[3] = out & 0xff;
277 conv[4] = '\0';
278 *result = conv;
279 return 0;
280 }
281
282 int fd_dictfct_Time_encode(void * data, union avp_value * avp_value)
283 {
284 char * buf;
285 size_t len;
286
287 TRACE_ENTRY("%p %p", data, avp_value);
288 CHECK_PARAMS( data && avp_value );
289
290 CHECK_FCT( time_t_to_diameter_string( *((time_t *)data), &buf) );
291 /* FIXME: return len from the function above? */ len = 4;
292
293 avp_value->os.len = len;
294 avp_value->os.data = buf;
295 return 0;
296 }
297
298 int fd_dictfct_Time_interpret(union avp_value * avp_value, void * interpreted)
299 {
300 TRACE_ENTRY("%p %p", avp_value, interpreted);
301
302 CHECK_PARAMS( avp_value && interpreted );
303
304 return diameter_string_to_time_t(avp_value->os.data, avp_value->os.len, interpreted);
305 }
306
307 char * fd_dictfct_Time_dump(union avp_value * avp_value)
308 {
309 char * ret;
310 CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
311 if (avp_value->os.len != 4) {
312 snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
313 return ret;
314 }
315 /* TODO: display the time as human-readable */
316 snprintf(ret, STR_LEN, "[TODO Time dump: 0x%02hhx%02hhx%02hhx%02hhx]", avp_value->os.data[0], avp_value->os.data[1], avp_value->os.data[2], avp_value->os.data[3]);
317 return ret;
318 }
319
"Welcome to our mercurial repository"