blob: b22da16043c6a734726abdb5ba2dce69c5e1b109 [file] [log] [blame]
Harald Weltedb924d32017-10-12 20:01:54 +08001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <time.h>
6
7#include <netinet/in.h>
8#include <sys/socket.h>
9
10#include <osmocom/core/utils.h>
11#include <osmocom/core/application.h>
12#include <osmocom/core/logging.h>
Neels Hofmeyr1d85bea2017-11-18 18:29:49 +010013#include <osmocom/core/bits.h>
Harald Weltedb924d32017-10-12 20:01:54 +080014
15#include "../../lib/in46_addr.h"
16#include "../../lib/syserr.h"
17
18static const struct in46_addr g_ia4 = {
19 .len = 4,
20 .v4.s_addr = 0x0d0c0b0a,
21};
22
Harald Weltedb924d32017-10-12 20:01:54 +080023static void test_in46a_to_af(void)
24{
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +010025 printf("Testing in46a_to_af() with IPv4 addresses\n");
Harald Weltedb924d32017-10-12 20:01:54 +080026
27 OSMO_ASSERT(in46a_to_af(&g_ia4) == AF_INET);
Harald Weltedb924d32017-10-12 20:01:54 +080028}
29
30static void test_in46a_to_sas(void)
31{
32 struct sockaddr_storage ss;
33 struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
Harald Weltedb924d32017-10-12 20:01:54 +080034
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +010035 printf("Testing in46a_to_sas() with IPv4 addresses\n");
Harald Weltedb924d32017-10-12 20:01:54 +080036
37 memset(&ss, 0, sizeof(ss));
38 OSMO_ASSERT(in46a_to_sas(&ss, &g_ia4) == 0);
39 OSMO_ASSERT(sin->sin_family == AF_INET);
40 OSMO_ASSERT(sin->sin_addr.s_addr == g_ia4.v4.s_addr);
Harald Weltedb924d32017-10-12 20:01:54 +080041}
42
43static void test_in46a_ntop(void)
44{
45 struct in46_addr ia;
46 char buf[256];
47 const char *res;
48
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +010049 printf("Testing in46a_ntop() with IPv4 addresses\n");
Harald Weltedb924d32017-10-12 20:01:54 +080050
51 res = in46a_ntop(NULL, buf, sizeof(buf));
52 OSMO_ASSERT(res && !strcmp(res, "UNDEFINED"));
53 printf("res = %s\n", res);
54
55 ia.len = 0;
56 res = in46a_ntop(&ia, buf, sizeof(buf));
57 printf("res = %s\n", res);
58 OSMO_ASSERT(res && !strcmp(res, "UNDEFINED"));
59
60 ia.len = 4;
61 ia.v4.s_addr = htonl(0x01020304);
62 res = in46a_ntop(&ia, buf, sizeof(buf));
63 OSMO_ASSERT(res && !strcmp(res, "1.2.3.4"));
64 printf("res = %s\n", res);
Harald Weltedb924d32017-10-12 20:01:54 +080065}
66
67static void test_in46p_ntoa(void)
68{
69 const struct in46_prefix ip46 = {
70 .prefixlen = 24,
71 .addr = {
72 .len = 4,
73 .v4.s_addr = htonl(0x10203000),
74 },
75 };
76 printf("in46p_ntoa() returns %s\n", in46p_ntoa(&ip46));
77}
78
79static void test_in46a_equal(void)
80{
81 struct in46_addr b;
82
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +010083 printf("Testing in46a_equal() with IPv4 addresses\n");
Harald Weltedb924d32017-10-12 20:01:54 +080084
85 memset(&b, 0xff, sizeof(b));
86 b.len = g_ia4.len;
87 b.v4.s_addr = g_ia4.v4.s_addr;
88 OSMO_ASSERT(in46a_equal(&g_ia4, &b));
Harald Weltedb924d32017-10-12 20:01:54 +080089}
90
Harald Weltedb924d32017-10-12 20:01:54 +080091static int log_in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net,
92 size_t prefixlen)
93{
94 int rc;
95
96 printf("in46a_within_mask(%s, ", in46a_ntoa(addr));
97 printf("%s, %lu) = ", in46a_ntoa(net), prefixlen);
98
99 rc = in46a_within_mask(addr, net, prefixlen);
100 printf("%d\n", rc);
101
102 return rc;
103}
104
105static void test_in46a_within_mask(void)
106{
107 struct in46_addr addr, mask;
108
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100109 printf("Testing in46a_within_mask() with IPv4 addresses\n");
Harald Weltedb924d32017-10-12 20:01:54 +0800110
111 addr = g_ia4;
112 mask = g_ia4;
113 OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 32));
114
115 mask.v4.s_addr = htonl( ntohl(mask.v4.s_addr) & 0xfffffffC );
116 OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 30));
117
118 mask.v4.s_addr = htonl( ntohl(mask.v4.s_addr) & 0xfff80000 );
119 OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 13));
120
121 addr.v4.s_addr = htonl(ntohl(addr.v4.s_addr) + 1);
122 mask = g_ia4;
123 OSMO_ASSERT(!log_in46a_within_mask(&addr, &mask, 32));
124 mask.v4.s_addr = htonl( ntohl(mask.v4.s_addr) & 0xfffffffC );
125 OSMO_ASSERT(log_in46a_within_mask(&addr, &mask, 30));
126}
127
128static void test_in46a_to_eua(void)
129{
Harald Weltedb924d32017-10-12 20:01:54 +0800130 struct ul66_t eua;
131
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100132 printf("testing in46a_to_eua() with IPv4 addresses\n");
Harald Weltedb924d32017-10-12 20:01:54 +0800133
134#if 0 /* triggers assert in current implementation */
135 const struct in46_addr ia_invalid = { .len = 3, };
136 OSMO_ASSERT(in46a_to_eua(&ia_invalid, &eua) < 0);
137#endif
138
139 /* IPv4 address */
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100140 OSMO_ASSERT(in46a_to_eua(&g_ia4, 1, &eua) == 0);
Harald Weltedb924d32017-10-12 20:01:54 +0800141 OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
142 OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4);
Neels Hofmeyr1d85bea2017-11-18 18:29:49 +0100143 OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
Harald Weltedb924d32017-10-12 20:01:54 +0800144}
145
146static void test_in46a_from_eua(void)
147{
148 struct in46_addr ia;
149 struct ul66_t eua;
150 const uint8_t v4_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4 };
151 const uint8_t v4_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4, 1,2,3,4 };
Harald Weltedb924d32017-10-12 20:01:54 +0800152 memset(&eua, 0, sizeof(eua));
153
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100154 printf("Testing in46a_from_eua() with IPv4 addresses\n");
Harald Weltedb924d32017-10-12 20:01:54 +0800155
156 /* default: v4 unspec */
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100157 OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
Harald Weltedb924d32017-10-12 20:01:54 +0800158 OSMO_ASSERT(ia.len == 4);
159 OSMO_ASSERT(ia.v4.s_addr == 0);
160
161 /* invalid */
162 eua.v[0] = 0x23;
163 eua.v[1] = PDP_EUA_TYPE_v4;
164 eua.l = 6;
165 OSMO_ASSERT(in46a_from_eua(&eua, &ia) < 0);
166
167 /* invalid */
168 eua.v[0] = PDP_EUA_ORG_IETF;
169 eua.v[1] = 0x23;
170 eua.l = 6;
171 OSMO_ASSERT(in46a_from_eua(&eua, &ia) < 0);
172
173 /* unspecified V4 */
174 memcpy(eua.v, v4_unspec, sizeof(v4_unspec));
175 eua.l = sizeof(v4_unspec);
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100176 OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
Harald Weltedb924d32017-10-12 20:01:54 +0800177 OSMO_ASSERT(ia.len == 4);
178 OSMO_ASSERT(ia.v4.s_addr == 0);
179
180 /* specified V4 */
181 memcpy(eua.v, v4_spec, sizeof(v4_spec));
182 eua.l = sizeof(v4_spec);
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100183 OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
Harald Weltedb924d32017-10-12 20:01:54 +0800184 OSMO_ASSERT(ia.len == 4);
185 OSMO_ASSERT(ia.v4.s_addr == htonl(0x01020304));
Harald Weltedb924d32017-10-12 20:01:54 +0800186}
187
Pau Espin Pedrol2e7b9ff2017-10-16 14:27:32 +0200188static void test_in46a_netmasklen(void)
189{
190 struct in46_addr netmask;
191 unsigned int len;
192
193 printf("Testing in46a_netmasklen() with IPv4 addresses\n");
194 netmask.len = 4;
195
196 netmask.v4.s_addr = 0xffffffff;
197 len = in46a_netmasklen(&netmask);
198 OSMO_ASSERT(len == 32);
199
200 netmask.v4.s_addr = 0x00ffffff;
201 len = in46a_netmasklen(&netmask);
202 OSMO_ASSERT(len == 24);
203
204 netmask.v4.s_addr = 0x00f0ffff;
205 len = in46a_netmasklen(&netmask);
206 OSMO_ASSERT(len == 20);
207
208 netmask.v4.s_addr = 0x000000fe;
209 len = in46a_netmasklen(&netmask);
210 OSMO_ASSERT(len == 7);
211
212 netmask.v4.s_addr = 0x00000000;
213 len = in46a_netmasklen(&netmask);
214 OSMO_ASSERT(len == 0);
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100215}
Pau Espin Pedrol2e7b9ff2017-10-16 14:27:32 +0200216
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100217/* IPv6 specific tests */
218
219static const struct in46_addr g_ia6 = {
220 .len = 16,
221 .v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
222};
223
224static void test_in46a_to_af_v6(void)
225{
226 struct in46_addr ia;
227
228 printf("Testing in46a_to_af() with IPv6 addresses\n");
229
230 OSMO_ASSERT(in46a_to_af(&g_ia6) == AF_INET6);
231
232 ia.len = 8;
233 OSMO_ASSERT(in46a_to_af(&ia) == AF_INET6);
234}
235
236static void test_in46a_to_sas_v6(void)
237{
238 struct sockaddr_storage ss;
239 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
240
241 printf("Testing in46a_to_sas() with IPv6 addresses\n");
242
243 memset(&ss, 0, sizeof(ss));
244 OSMO_ASSERT(in46a_to_sas(&ss, &g_ia6) == 0);
245 OSMO_ASSERT(sin6->sin6_family == AF_INET6);
246 OSMO_ASSERT(!memcmp(&sin6->sin6_addr, &g_ia6.v6, sizeof(sin6->sin6_addr)));
247}
248
249static void test_in46a_ntop_v6(void)
250{
251 char buf[256];
252 const char *res;
253
254 printf("Testing in46a_ntop() with IPv6 addresses\n");
255
256 res = in46a_ntop(&g_ia6, buf, sizeof(buf));
257 OSMO_ASSERT(res && !strcmp(res, "102:304:506:708:90a:b0c:d0e:f10"));
258 printf("res = %s\n", res);
259}
260
261static void test_in46a_equal_v6(void)
262{
263 struct in46_addr b;
264
265 printf("Testing in46a_equal() with IPv6 addresses\n");
266
267 memset(&b, 0xff, sizeof(b));
268 b.len = g_ia6.len;
269 b.v6 = g_ia6.v6;
270 OSMO_ASSERT(in46a_equal(&g_ia6, &b));
271}
272
273static void test_in46a_to_eua_v6(void)
274{
275 const struct in46_addr ia_v6_8 = {
276 .len = 8,
277 .v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
278 };
279 struct ul66_t eua;
280
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100281 printf("Testing in46a_to_eua() with IPv6 addresses\n");
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100282
283 /* IPv6 address */
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100284 OSMO_ASSERT(in46a_to_eua(&g_ia6, 1, &eua) == 0);
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100285 OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
286 OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
287 OSMO_ASSERT(!memcmp(&eua.v[2], &g_ia6.v6, 16));
288
289 /* IPv6 address with prefix / length 8 */
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100290 OSMO_ASSERT(in46a_to_eua(&ia_v6_8, 1, &eua) == 0);
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100291 OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
292 OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v6);
293 OSMO_ASSERT(!memcmp(&eua.v[2], &ia_v6_8.v6, 16));
294}
295
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100296static void test_in46a_to_eua_v4v6() {
297 const struct in46_addr ia_v4v6[2] = {
298 {
299 .len = 16,
300 .v6.s6_addr = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 },
301 },
302 {
303 .len = 4,
304 .v4.s_addr = 0x0d0c0b0a,
305 }
306 };
307 struct ul66_t eua;
308 printf("Testing in46a_to_eua() with IPv4v6 addresses\n");
309
310 /* IPv4 address */
311 OSMO_ASSERT(in46a_to_eua(ia_v4v6, 2, &eua) == 0);
312 OSMO_ASSERT(eua.v[0] == PDP_EUA_ORG_IETF);
313 OSMO_ASSERT(eua.v[1] == PDP_EUA_TYPE_v4v6);
314 OSMO_ASSERT(osmo_load32le(&eua.v[2]) == g_ia4.v4.s_addr);
315 OSMO_ASSERT(!memcmp(&eua.v[6], &g_ia6.v6, 16));
316}
317
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100318static void test_in46a_from_eua_v6(void)
319{
320 struct in46_addr ia;
321 struct ul66_t eua;
322 const uint8_t v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6 };
323 const uint8_t v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6,
324 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
325
326 memset(&eua, 0, sizeof(eua));
327
328 printf("Testing in46a_from_eua() with IPv6 addresses\n");
329
330 /* unspecified V6 */
331 memcpy(eua.v, v6_unspec, sizeof(v6_unspec));
332 eua.l = sizeof(v6_unspec);
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100333 OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100334 OSMO_ASSERT(ia.len == 16);
335 OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia.v6));
336
337 /* specified V6 */
338 memcpy(eua.v, v6_spec, sizeof(v6_spec));
339 eua.l = sizeof(v6_spec);
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100340 OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100341 OSMO_ASSERT(ia.len == 16);
342 OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len));
343}
344
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100345static void test_in46a_from_eua_v4v6(void) {
346 struct in46_addr ia[2];
347 struct ul66_t eua;
348 const uint8_t v4_unspec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6 };
349 const uint8_t v4_spec_v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4 };
350 const uint8_t v4_unspec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
351 const uint8_t v4_spec_v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4v6, 1,2,3,4, 1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10 };
352
353 memset(&eua, 0, sizeof(eua));
354
355 printf("Testing in46a_from_eua() with IPv4v6 addresses\n");
356
357 /* unspecified V4 & V6 */
358 memcpy(eua.v, v4_unspec_v6_unspec, sizeof(v4_unspec_v6_unspec));
359 eua.l = sizeof(v4_unspec_v6_unspec);
360 OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
361 OSMO_ASSERT(ia[0].len == 4);
362 OSMO_ASSERT(ia[1].len == 16);
363 OSMO_ASSERT(ia[0].v4.s_addr == 0);
364 OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
365
366 /* specified V4, unspecified V6 */
367 memcpy(eua.v, v4_spec_v6_unspec, sizeof(v4_spec_v6_unspec));
368 eua.l = sizeof(v4_spec_v6_unspec);
369 OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
370 OSMO_ASSERT(ia[0].len == 4);
371 OSMO_ASSERT(ia[1].len == 16);
372 OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
373 OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[1].v6));
374
375 /* unspecified V4, specified V6 */
376 memcpy(eua.v, v4_unspec_v6_spec, sizeof(v4_unspec_v6_spec));
377 eua.l = sizeof(v4_unspec_v6_spec);
378 OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
379 OSMO_ASSERT(ia[0].len == 4);
380 OSMO_ASSERT(ia[1].len == 16);
381 OSMO_ASSERT(ia[0].v4.s_addr == 0);
382 OSMO_ASSERT(!memcmp(&ia[1].v6, v4_unspec_v6_spec+2, ia[1].len));
383
384 /* specified V4, specified V6 */
385 memcpy(eua.v, v4_spec_v6_spec, sizeof(v4_spec_v6_spec));
386 eua.l = sizeof(v4_spec_v6_spec);
387 OSMO_ASSERT(in46a_from_eua(&eua, ia) == 2);
388 OSMO_ASSERT(ia[0].len == 4);
389 OSMO_ASSERT(ia[1].len == 16);
390 OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
391 OSMO_ASSERT(!memcmp(&ia[1].v6, v4_spec_v6_spec+6, ia[1].len));
392}
393
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100394static void test_in46a_netmasklen_v6(void)
395{
396 unsigned int len;
Pau Espin Pedrol2e7b9ff2017-10-16 14:27:32 +0200397 printf("Testing in46a_netmasklen() with IPv6 addresses\n");
398 const struct in46_addr netmaskA = {
399 .len = 16,
400 .v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
401 };
402 len = in46a_netmasklen(&netmaskA);
403 OSMO_ASSERT(len == 128);
404
405 const struct in46_addr netmaskB = {
406 .len = 16,
407 .v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00},
408 };
409 len = in46a_netmasklen(&netmaskB);
410 OSMO_ASSERT(len == 104);
411
412 const struct in46_addr netmaskC = {
413 .len = 16,
414 .v6.s6_addr = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x00,0x00,0x00},
415 };
416 len = in46a_netmasklen(&netmaskC);
417 OSMO_ASSERT(len == 103);
418
419 const struct in46_addr netmaskD = {
420 .len = 16,
421 .v6.s6_addr = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
422 };
423 len = in46a_netmasklen(&netmaskD);
424 OSMO_ASSERT(len == 0);
425}
426
Harald Weltedb924d32017-10-12 20:01:54 +0800427int main(int argc, char **argv)
428{
429 osmo_init_logging(&log_info);
430 log_set_use_color(osmo_stderr_target, 0);
431 log_set_print_filename(osmo_stderr_target, 0);
432
433 srand(time(NULL));
434
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100435 if (argc < 2 || strcmp(argv[1], "-v6")) {
436 test_in46a_to_af();
437 test_in46a_to_sas();
438 test_in46a_ntop();
439 test_in46p_ntoa();
440 test_in46a_equal();
441 test_in46a_within_mask();
442 test_in46a_to_eua();
443 test_in46a_from_eua();
444 test_in46a_netmasklen();
445 } else {
446 test_in46a_to_af_v6();
447 test_in46a_to_sas_v6();
448 test_in46a_ntop_v6();
449 test_in46a_equal_v6();
450 test_in46a_to_eua_v6();
451 test_in46a_from_eua_v6();
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +0100452 test_in46a_to_eua_v4v6();
453 test_in46a_from_eua_v4v6();
Pau Espin Pedrol9c0f4f42017-12-04 12:52:23 +0100454 test_in46a_netmasklen_v6();
455 }
Neels Hofmeyrdabb8b42017-10-29 01:53:50 +0200456 return 0;
Harald Weltedb924d32017-10-12 20:01:54 +0800457}