1 /* coap_address.c -- representation of network addresses
2 *
3 * Copyright (C) 2015-2016,2019-2023 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
11 /**
12 * @file coap_address.c
13 * @brief Handling of network addresses
14 */
15
16 #include "coap3/coap_internal.h"
17
18 #if !defined(WITH_CONTIKI) && !defined(WITH_LWIP)
19 #ifdef HAVE_ARPA_INET_H
20 #include <arpa/inet.h>
21 #endif
22 #ifdef HAVE_NETINET_IN_H
23 #include <netinet/in.h>
24 #endif
25 #ifdef HAVE_SYS_SOCKET_H
26 #include <sys/socket.h>
27 #endif
28 #ifdef HAVE_NET_IF_H
29 #include <net/if.h>
30 #endif
31 #ifdef HAVE_IFADDRS_H
32 #include <ifaddrs.h>
33 #endif
34 #ifdef HAVE_WS2TCPIP_H
35 #include <ws2tcpip.h>
36 #endif
37
38 #ifdef RIOT_VERSION
39 /* FIXME */
40 #define IN_MULTICAST(Address) (0)
41 #endif /* RIOT_VERSION */
42
43 uint16_t
coap_address_get_port(const coap_address_t * addr)44 coap_address_get_port(const coap_address_t *addr) {
45 assert(addr != NULL);
46 switch (addr->addr.sa.sa_family) {
47 #if COAP_IPV4_SUPPORT
48 case AF_INET:
49 return ntohs(addr->addr.sin.sin_port);
50 #endif /* COAP_IPV4_SUPPORT */
51 #if COAP_IPV6_SUPPORT
52 case AF_INET6:
53 return ntohs(addr->addr.sin6.sin6_port);
54 #endif /* COAP_IPV6_SUPPORT */
55 default: /* undefined */
56 ;
57 }
58 return 0;
59 }
60
61 void
coap_address_set_port(coap_address_t * addr,uint16_t port)62 coap_address_set_port(coap_address_t *addr, uint16_t port) {
63 assert(addr != NULL);
64 switch (addr->addr.sa.sa_family) {
65 #if COAP_IPV4_SUPPORT
66 case AF_INET:
67 addr->addr.sin.sin_port = htons(port);
68 break;
69 #endif /* COAP_IPV4_SUPPORT */
70 #if COAP_IPV6_SUPPORT
71 case AF_INET6:
72 addr->addr.sin6.sin6_port = htons(port);
73 break;
74 #endif /* COAP_IPV6_SUPPORT */
75 default: /* undefined */
76 ;
77 }
78 }
79
80 int
coap_address_equals(const coap_address_t * a,const coap_address_t * b)81 coap_address_equals(const coap_address_t *a, const coap_address_t *b) {
82 assert(a);
83 assert(b);
84
85 if (a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family)
86 return 0;
87
88 /* need to compare only relevant parts of sockaddr_in6 */
89 switch (a->addr.sa.sa_family) {
90 #if COAP_IPV4_SUPPORT
91 case AF_INET:
92 return a->addr.sin.sin_port == b->addr.sin.sin_port &&
93 memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr,
94 sizeof(struct in_addr)) == 0;
95 #endif /* COAP_IPV4_SUPPORT */
96 #if COAP_IPV6_SUPPORT
97 case AF_INET6:
98 return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port &&
99 memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr,
100 sizeof(struct in6_addr)) == 0;
101 #endif /* COAP_IPV6_SUPPORT */
102 default: /* fall through and signal error */
103 ;
104 }
105 return 0;
106 }
107
108 int
coap_is_af_unix(const coap_address_t * a)109 coap_is_af_unix(const coap_address_t *a) {
110 #if COAP_AF_UNIX_SUPPORT
111 return a->addr.sa.sa_family == AF_UNIX;
112 #else /* ! COAP_AF_UNIX_SUPPORT */
113 (void)a;
114 return 0;
115 #endif /* ! COAP_AF_UNIX_SUPPORT */
116 }
117
118 int
coap_is_mcast(const coap_address_t * a)119 coap_is_mcast(const coap_address_t *a) {
120 if (!a)
121 return 0;
122
123 /* Treat broadcast in same way as multicast */
124 if (coap_is_bcast(a))
125 return 1;
126
127 switch (a->addr.sa.sa_family) {
128 #if COAP_IPV4_SUPPORT
129 case AF_INET:
130 return IN_MULTICAST(ntohl(a->addr.sin.sin_addr.s_addr));
131 #endif /* COAP_IPV4_SUPPORT */
132 #if COAP_IPV6_SUPPORT
133 case AF_INET6:
134 #if COAP_IPV4_SUPPORT
135 return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr) ||
136 (IN6_IS_ADDR_V4MAPPED(&a->addr.sin6.sin6_addr) &&
137 IN_MULTICAST(ntohl(a->addr.sin6.sin6_addr.s6_addr[12])));
138 #else /* ! COAP_IPV4_SUPPORT */
139 return a->addr.sin6.sin6_addr.s6_addr[0] == 0xff;
140 #endif /* ! COAP_IPV4_SUPPORT */
141 #endif /* COAP_IPV6_SUPPORT */
142 default: /* fall through and signal not multicast */
143 ;
144 }
145 return 0;
146 }
147
148 #ifndef COAP_BCST_CNT
149 #define COAP_BCST_CNT 15
150 #endif /* COAP_BCST_CNT */
151
152 /* How frequently to refresh the list of valid IPv4 broadcast addresses */
153 #ifndef COAP_BCST_REFRESH_SECS
154 #define COAP_BCST_REFRESH_SECS 30
155 #endif /* COAP_BCST_REFRESH_SECS */
156
157 #ifdef COAP_SUPPORT_SOCKET_BROADCAST
coap_is_bcast(const coap_address_t * a)158 int coap_is_bcast(const coap_address_t *a) {
159 if (a == NULL)
160 return 0;
161 switch(a->addr.sa.sa_family) {
162 case AF_INET:
163 if (a->addr.sin.sin_addr.s_addr == 0xFFFFFFFF)
164 return 1;
165 else
166 return 0;
167 case AF_INET6: /* broadcast not support ipv6 now */
168 default:
169 return 0;
170 }
171 }
172 #else /* !COAP_SUPPORT_SOCKET_BROADCAST */
173 #if COAP_IPV4_SUPPORT && defined(HAVE_IFADDRS_H)
174 static int bcst_cnt = -1;
175 static coap_tick_t last_refresh;
176 static struct in_addr b_ipv4[COAP_BCST_CNT];
177 #endif /* COAP_IPV4_SUPPORT && HAVE_IFADDRS_H */
178
179 int
coap_is_bcast(const coap_address_t * a)180 coap_is_bcast(const coap_address_t *a) {
181 #if COAP_IPV4_SUPPORT
182 struct in_addr ipv4;
183 #if defined(HAVE_IFADDRS_H)
184 int i;
185 coap_tick_t now;
186 #endif /* HAVE_IFADDRS_H */
187 #endif /* COAP_IPV4_SUPPORT */
188
189 if (!a)
190 return 0;
191
192 switch (a->addr.sa.sa_family) {
193 #if COAP_IPV4_SUPPORT
194 case AF_INET:
195 ipv4.s_addr = a->addr.sin.sin_addr.s_addr;
196 break;
197 #endif /* COAP_IPV4_SUPPORT */
198 #if COAP_IPV6_SUPPORT
199 case AF_INET6:
200 #if COAP_IPV4_SUPPORT
201 if (IN6_IS_ADDR_V4MAPPED(&a->addr.sin6.sin6_addr)) {
202 memcpy(&ipv4, &a->addr.sin6.sin6_addr.s6_addr[12], sizeof(ipv4));
203 break;
204 }
205 #endif /* COAP_IPV4_SUPPORT */
206 /* IPv6 does not support broadcast */
207 return 0;
208 #endif /* COAP_IPV6_SUPPORT */
209 default:
210 return 0;
211 }
212 #if COAP_IPV4_SUPPORT
213 #ifndef INADDR_BROADCAST
214 #define INADDR_BROADCAST ((uint32_t)0xffffffffUL)
215 #endif /* !INADDR_BROADCAST */
216 if (ipv4.s_addr == INADDR_BROADCAST)
217 return 1;
218
219 #if defined(HAVE_IFADDRS_H)
220 coap_ticks(&now);
221 if (bcst_cnt == -1 ||
222 (now - last_refresh) > (COAP_BCST_REFRESH_SECS * COAP_TICKS_PER_SECOND)) {
223 /* Determine the list of broadcast interfaces */
224 struct ifaddrs *ifa = NULL;
225 struct ifaddrs *ife;
226
227 if (getifaddrs(&ifa) != 0) {
228 coap_log_warn("coap_is_bcst: Cannot determine any broadcast addresses\n");
229 return 0;
230 }
231 bcst_cnt = 0;
232 last_refresh = now;
233 ife = ifa;
234 while (ife && bcst_cnt < COAP_BCST_CNT) {
235 if (ife->ifa_addr && ife->ifa_addr->sa_family == AF_INET &&
236 ife->ifa_flags & IFF_BROADCAST) {
237 b_ipv4[bcst_cnt].s_addr = ((struct sockaddr_in *)ife->ifa_broadaddr)->sin_addr.s_addr;
238 bcst_cnt++;
239 }
240 ife = ife->ifa_next;
241 }
242 if (ife) {
243 coap_log_warn("coap_is_bcst: Insufficient space for broadcast addresses\n");
244 }
245 freeifaddrs(ifa);
246 }
247 for (i = 0; i < bcst_cnt; i++) {
248 if (ipv4.s_addr == b_ipv4[i].s_addr)
249 return 1;
250 }
251 #endif /* HAVE_IFADDRS_H */
252 return 0;
253 #endif /* COAP_IPV4_SUPPORT */
254 }
255 #endif /* COAP_SUPPORT_SOCKET_BROADCAST */
256 #endif /* !defined(WITH_CONTIKI) && !defined(WITH_LWIP) */
257
258 void
coap_address_init(coap_address_t * addr)259 coap_address_init(coap_address_t *addr) {
260 assert(addr);
261 memset(addr, 0, sizeof(coap_address_t));
262 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
263 /* lwip and Contiki have constant address sizes and don't need the .size part */
264 addr->size = sizeof(addr->addr);
265 #endif
266 }
267
268 void
coap_address_ntop(const coap_address_t * addr,char * dst,int len)269 coap_address_ntop(const coap_address_t *addr, char *dst, int len) {
270 if ((addr == NULL) || (dst == NULL) || (len < INET6_ADDRSTRLEN))
271 return;
272 #if defined(WITH_LWIP)
273 (void)ipaddr_ntoa_r(&(addr->addr), dst, len);
274 #elif defined(WITH_CONTIKI)
275 coap_log_warn("coap_address_ntop: contiki not supported");
276 #else
277 if (addr->addr.sa.sa_family == AF_INET) {
278 const void *addrptr = &addr->addr.sin.sin_addr;
279 (void)inet_ntop(addr->addr.sa.sa_family, addrptr, dst, len);
280 } else {
281 const void *addrptr = &addr->addr.sin6.sin6_addr;
282 (void)inet_ntop(addr->addr.sa.sa_family, addrptr, dst, len);
283 }
284 #endif
285 }
286
287 int
coap_address_set_unix_domain(coap_address_t * addr,const uint8_t * host,size_t host_len)288 coap_address_set_unix_domain(coap_address_t *addr,
289 const uint8_t *host, size_t host_len) {
290 #if COAP_AF_UNIX_SUPPORT
291 size_t i;
292 size_t ofs = 0;
293
294 coap_address_init(addr);
295 addr->addr.cun.sun_family = AF_UNIX;
296 for (i = 0; i < host_len; i++) {
297 if ((host_len - i) >= 3 && host[i] == '%' && host[i+1] == '2' &&
298 (host[i+2] == 'F' || host[i+2] == 'f')) {
299 addr->addr.cun.sun_path[ofs++] = '/';
300 i += 2;
301 } else {
302 addr->addr.cun.sun_path[ofs++] = host[i];
303 }
304 if (ofs == COAP_UNIX_PATH_MAX)
305 break;
306 }
307 if (ofs < COAP_UNIX_PATH_MAX)
308 addr->addr.cun.sun_path[ofs] = '\000';
309 else
310 addr->addr.cun.sun_path[ofs-1] = '\000';
311 return 1;
312 #else /* ! COAP_AF_UNIX_SUPPORT */
313 (void)addr;
314 (void)host;
315 (void)host_len;
316 return 0;
317 #endif /* ! COAP_AF_UNIX_SUPPORT */
318 }
319
320 #if !defined(WITH_CONTIKI)
321 static void
update_port(coap_address_t * addr,uint16_t port,uint16_t default_port,int update_port0)322 update_port(coap_address_t *addr, uint16_t port, uint16_t default_port,
323 int update_port0) {
324 /* Client target port must be set if default of 0 */
325 if (port == 0 && update_port0)
326 port = default_port;
327
328 coap_address_set_port(addr, port);
329 return;
330 }
331
332 #ifdef HAVE_NETDB_H
333 #include <netdb.h>
334 #endif
335
336 uint32_t
coap_get_available_scheme_hint_bits(int have_pki_psk,int ws_check,coap_proto_t use_unix_proto)337 coap_get_available_scheme_hint_bits(int have_pki_psk, int ws_check,
338 coap_proto_t use_unix_proto) {
339 uint32_t scheme_hint_bits = 0;
340 coap_uri_scheme_t scheme;
341
342 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
343 switch (scheme) {
344 case COAP_URI_SCHEME_COAP:
345 scheme_hint_bits |= 1 << scheme;
346 break;
347 case COAP_URI_SCHEME_COAPS:
348 if (!(coap_dtls_is_supported() && have_pki_psk))
349 continue;
350 scheme_hint_bits |= 1 << scheme;
351 break;
352 case COAP_URI_SCHEME_COAP_TCP:
353 if (!coap_tcp_is_supported())
354 continue;
355 scheme_hint_bits |= 1 << scheme;
356 break;
357 case COAP_URI_SCHEME_COAPS_TCP:
358 if (!(coap_tls_is_supported() && have_pki_psk))
359 continue;
360 scheme_hint_bits |= 1 << scheme;
361 break;
362 case COAP_URI_SCHEME_COAP_WS:
363 if (!ws_check || !coap_ws_is_supported())
364 continue;
365 scheme_hint_bits |= 1 << scheme;
366 break;
367 case COAP_URI_SCHEME_COAPS_WS:
368 if (!ws_check || !(coap_wss_is_supported() && have_pki_psk))
369 continue;
370 scheme_hint_bits |= 1 << scheme;
371 break;
372 case COAP_URI_SCHEME_HTTP:
373 case COAP_URI_SCHEME_HTTPS:
374 case COAP_URI_SCHEME_LAST:
375 default:
376 continue;
377 }
378 }
379
380 switch (use_unix_proto) {
381 /* For AF_UNIX, can only listen on a single endpoint */
382 case COAP_PROTO_UDP:
383 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP;
384 break;
385 case COAP_PROTO_TCP:
386 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP_TCP;
387 break;
388 case COAP_PROTO_DTLS:
389 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS;
390 break;
391 case COAP_PROTO_TLS:
392 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS_TCP;
393 break;
394 case COAP_PROTO_WS:
395 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAP_WS;
396 break;
397 case COAP_PROTO_WSS:
398 scheme_hint_bits = 1 << COAP_URI_SCHEME_COAPS_WS;
399 break;
400 case COAP_PROTO_NONE: /* If use_unix_proto was not defined */
401 case COAP_PROTO_LAST:
402 default:
403 break;
404 }
405 return scheme_hint_bits;
406 }
407
408 coap_addr_info_t *
coap_resolve_address_info(const coap_str_const_t * address,uint16_t port,uint16_t secure_port,uint16_t ws_port,uint16_t ws_secure_port,int ai_hints_flags,int scheme_hint_bits,coap_resolve_type_t type)409 coap_resolve_address_info(const coap_str_const_t *address,
410 uint16_t port,
411 uint16_t secure_port,
412 uint16_t ws_port,
413 uint16_t ws_secure_port,
414 int ai_hints_flags,
415 int scheme_hint_bits,
416 coap_resolve_type_t type) {
417 #if !defined(RIOT_VERSION)
418
419 struct addrinfo *res, *ainfo;
420 struct addrinfo hints;
421 static char addrstr[256];
422 int error;
423 coap_addr_info_t *info = NULL;
424 coap_addr_info_t *info_prev = NULL;
425 coap_addr_info_t *info_list = NULL;
426 coap_addr_info_t *info_tmp;
427 coap_uri_scheme_t scheme;
428 coap_proto_t proto = 0;
429
430 #if COAP_AF_UNIX_SUPPORT
431 if (address && coap_host_is_unix_domain(address)) {
432 /* There can only be one unique filename entry for AF_UNIX */
433 if (address->length >= COAP_UNIX_PATH_MAX) {
434 coap_log_err("Unix Domain host too long\n");
435 return NULL;
436 }
437 /* Need to chose the first defined one in scheme_hint_bits */
438 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
439 if (scheme_hint_bits & (1 << scheme)) {
440 break;
441 }
442 }
443 if (scheme == COAP_URI_SCHEME_LAST) {
444 return NULL;
445 }
446 switch (scheme) {
447 case COAP_URI_SCHEME_COAP:
448 proto = COAP_PROTO_UDP;
449 break;
450 case COAP_URI_SCHEME_COAPS:
451 if (!coap_dtls_is_supported())
452 return NULL;
453 proto = COAP_PROTO_DTLS;
454 break;
455 case COAP_URI_SCHEME_COAP_TCP:
456 if (!coap_tcp_is_supported())
457 return NULL;
458 proto = COAP_PROTO_TCP;
459 break;
460 case COAP_URI_SCHEME_COAPS_TCP:
461 if (!coap_tls_is_supported())
462 return NULL;
463 proto = COAP_PROTO_TLS;
464 break;
465 case COAP_URI_SCHEME_HTTP:
466 if (!coap_tcp_is_supported())
467 return NULL;
468 proto = COAP_PROTO_NONE;
469 break;
470 case COAP_URI_SCHEME_HTTPS:
471 if (!coap_tls_is_supported())
472 return NULL;
473 proto = COAP_PROTO_NONE;
474 break;
475 case COAP_URI_SCHEME_COAP_WS:
476 if (!coap_ws_is_supported())
477 return NULL;
478 proto = COAP_PROTO_WS;
479 break;
480 case COAP_URI_SCHEME_COAPS_WS:
481 if (!coap_wss_is_supported())
482 return NULL;
483 proto = COAP_PROTO_WSS;
484 break;
485 case COAP_URI_SCHEME_LAST:
486 default:
487 return NULL;
488 }
489 info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
490 if (info == NULL)
491 return NULL;
492 info->next = NULL;
493 info->proto = proto;
494 info->scheme = scheme;
495
496 coap_address_init(&info->addr);
497 if (!coap_address_set_unix_domain(&info->addr, address->s,
498 address->length)) {
499 coap_free_type(COAP_STRING, info);
500 return NULL;
501 }
502 return info;
503 }
504 #endif /* COAP_AF_UNIX_SUPPORT */
505
506 memset(addrstr, 0, sizeof(addrstr));
507 if (address && address->length)
508 memcpy(addrstr, address->s, address->length);
509 else
510 memcpy(addrstr, "localhost", 9);
511
512 memset((char *)&hints, 0, sizeof(hints));
513 hints.ai_socktype = 0;
514 hints.ai_family = AF_UNSPEC;
515 hints.ai_flags = ai_hints_flags;
516
517 error = getaddrinfo(addrstr, NULL, &hints, &res);
518
519 if (error != 0) {
520 coap_log_warn("getaddrinfo: %s\n", gai_strerror(error));
521 return NULL;
522 }
523
524 for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
525 #if !defined(WITH_LWIP)
526 if (ainfo->ai_addrlen > (socklen_t)sizeof(info->addr.addr))
527 continue;
528 #endif /* ! WITH_LWIP */
529
530 switch (ainfo->ai_family) {
531 #if COAP_IPV4_SUPPORT
532 case AF_INET:
533 #endif /* COAP_IPV4_SUPPORT */
534 #if COAP_IPV6_SUPPORT
535 case AF_INET6:
536 #endif /* COAP_IPV6_SUPPORT */
537 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
538 if (scheme_hint_bits & (1 << scheme)) {
539 switch (scheme) {
540 case COAP_URI_SCHEME_COAP:
541 proto = COAP_PROTO_UDP;
542 break;
543 case COAP_URI_SCHEME_COAPS:
544 if (!coap_dtls_is_supported())
545 continue;
546 proto = COAP_PROTO_DTLS;
547 break;
548 case COAP_URI_SCHEME_COAP_TCP:
549 if (!coap_tcp_is_supported())
550 continue;
551 proto = COAP_PROTO_TCP;
552 break;
553 case COAP_URI_SCHEME_COAPS_TCP:
554 if (!coap_tls_is_supported())
555 continue;
556 proto = COAP_PROTO_TLS;
557 break;
558 case COAP_URI_SCHEME_HTTP:
559 if (!coap_tcp_is_supported())
560 continue;
561 proto = COAP_PROTO_NONE;
562 break;
563 case COAP_URI_SCHEME_HTTPS:
564 if (!coap_tls_is_supported())
565 continue;
566 proto = COAP_PROTO_NONE;
567 break;
568 case COAP_URI_SCHEME_COAP_WS:
569 if (!coap_ws_is_supported())
570 continue;
571 proto = COAP_PROTO_WS;
572 break;
573 case COAP_URI_SCHEME_COAPS_WS:
574 if (!coap_wss_is_supported())
575 continue;
576 proto = COAP_PROTO_WSS;
577 break;
578 case COAP_URI_SCHEME_LAST:
579 default:
580 continue;
581 }
582
583 info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
584 if (info == NULL) {
585 freeaddrinfo(res);
586 /* malloc failure - return what we have so far */
587 return info_list;
588 }
589
590 info->next = NULL;
591 info->scheme = scheme;
592 info->proto = proto;
593 coap_address_init(&info->addr);
594 #if !defined(WITH_LWIP)
595 info->addr.size = (socklen_t)ainfo->ai_addrlen;
596 memcpy(&info->addr.addr, ainfo->ai_addr, ainfo->ai_addrlen);
597 #else /* WITH_LWIP */
598 memset(&info->addr, 0, sizeof(info->addr));
599 switch (ainfo->ai_family) {
600 #if COAP_IPV6_SUPPORT
601 struct sockaddr_in6 *sock6;
602 #endif /* COAP_IPV6_SUPPORT */
603 #if COAP_IPV4_SUPPORT
604 struct sockaddr_in *sock4;
605 case AF_INET:
606 sock4 = (struct sockaddr_in *)ainfo->ai_addr;
607 info->addr.port = ntohs(sock4->sin_port);
608 memcpy(&info->addr.addr, &sock4->sin_addr, 4);
609 #if LWIP_IPV6
610 info->addr.addr.type = IPADDR_TYPE_V4;
611 #endif /* LWIP_IPV6 */
612 break;
613 #endif /* COAP_IPV4_SUPPORT */
614 #if COAP_IPV6_SUPPORT
615 case AF_INET6:
616 sock6 = (struct sockaddr_in6 *)ainfo->ai_addr;
617 info->addr.port = ntohs(sock6->sin6_port);
618 memcpy(&info->addr.addr, &sock6->sin6_addr, 16);
619 #if LWIP_IPV6 && LWIP_IPV4
620 info->addr.addr.type = IPADDR_TYPE_V6;
621 #endif /* LWIP_IPV6 && LWIP_IPV4 */
622 break;
623 #endif /* COAP_IPV6_SUPPORT */
624 default:
625 ;
626 }
627 #endif /* WITH_LWIP */
628 switch (scheme) {
629 case COAP_URI_SCHEME_COAP:
630 update_port(&info->addr, port, COAP_DEFAULT_PORT,
631 type == COAP_RESOLVE_TYPE_LOCAL);
632 break;
633 case COAP_URI_SCHEME_COAPS:
634 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
635 type == COAP_RESOLVE_TYPE_LOCAL);
636 break;
637 case COAP_URI_SCHEME_COAP_TCP:
638 update_port(&info->addr, port, COAP_DEFAULT_PORT,
639 type == COAP_RESOLVE_TYPE_LOCAL);
640 break;
641 case COAP_URI_SCHEME_COAPS_TCP:
642 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
643 type == COAP_RESOLVE_TYPE_LOCAL);
644 break;
645 case COAP_URI_SCHEME_HTTP:
646 update_port(&info->addr, port, 80,
647 type == COAP_RESOLVE_TYPE_LOCAL);
648 break;
649 case COAP_URI_SCHEME_HTTPS:
650 update_port(&info->addr, secure_port, 443,
651 type == COAP_RESOLVE_TYPE_LOCAL);
652 break;
653 case COAP_URI_SCHEME_COAP_WS:
654 update_port(&info->addr, ws_port, 80,
655 type == COAP_RESOLVE_TYPE_LOCAL);
656 break;
657 case COAP_URI_SCHEME_COAPS_WS:
658 update_port(&info->addr, ws_secure_port, 443,
659 type == COAP_RESOLVE_TYPE_LOCAL);
660 break;
661 case COAP_URI_SCHEME_LAST:
662 default:
663 break;
664 }
665
666 /* Check there are no duplications */
667 info_tmp = info_list;
668 while (info_tmp) {
669 if (info_tmp->proto == info->proto &&
670 info_tmp->scheme == info->scheme &&
671 coap_address_equals(&info_tmp->addr, &info->addr)) {
672 break;
673 }
674 info_tmp = info_tmp->next;
675 }
676
677 if (info_tmp) {
678 /* Duplicate */
679 coap_free_type(COAP_STRING, info);
680 } else {
681 /* Need to return in same order as getaddrinfo() */
682 if (!info_prev) {
683 info_list = info;
684 info_prev = info;
685 } else {
686 info_prev->next = info;
687 info_prev = info;
688 }
689 }
690 }
691 }
692 break;
693 default:
694 break;
695 }
696 }
697
698 freeaddrinfo(res);
699 return info_list;
700 #else /* RIOT_VERSION */
701 #if COAP_IPV6_SUPPORT
702 #include "net/utils.h"
703 ipv6_addr_t addr_ipv6;
704 netif_t *netif = NULL;
705 coap_addr_info_t *info = NULL;
706 coap_addr_info_t *info_prev = NULL;
707 coap_addr_info_t *info_list = NULL;
708 coap_uri_scheme_t scheme;
709 coap_proto_t proto = 0;
710 (void)ai_hints_flags;
711
712 if (netutils_get_ipv6(&addr_ipv6, &netif, (const char *)address->s) >= 0) {
713 for (scheme = 0; scheme < COAP_URI_SCHEME_LAST; scheme++) {
714 if (scheme_hint_bits & (1 << scheme)) {
715 switch (scheme) {
716 case COAP_URI_SCHEME_COAP:
717 proto = COAP_PROTO_UDP;
718 break;
719 case COAP_URI_SCHEME_COAPS:
720 if (!coap_dtls_is_supported())
721 continue;
722 proto = COAP_PROTO_DTLS;
723 break;
724 case COAP_URI_SCHEME_COAP_TCP:
725 if (!coap_tcp_is_supported())
726 continue;
727 proto = COAP_PROTO_TCP;
728 break;
729 case COAP_URI_SCHEME_COAPS_TCP:
730 if (!coap_tls_is_supported())
731 continue;
732 proto = COAP_PROTO_TLS;
733 break;
734 case COAP_URI_SCHEME_HTTP:
735 if (!coap_tcp_is_supported())
736 continue;
737 proto = COAP_PROTO_NONE;
738 break;
739 case COAP_URI_SCHEME_HTTPS:
740 if (!coap_tls_is_supported())
741 continue;
742 proto = COAP_PROTO_NONE;
743 break;
744 case COAP_URI_SCHEME_COAP_WS:
745 if (!coap_ws_is_supported())
746 continue;
747 proto = COAP_PROTO_WS;
748 break;
749 case COAP_URI_SCHEME_COAPS_WS:
750 if (!coap_wss_is_supported())
751 continue;
752 proto = COAP_PROTO_WSS;
753 break;
754 case COAP_URI_SCHEME_LAST:
755 default:
756 continue;
757 }
758
759 info = coap_malloc_type(COAP_STRING, sizeof(coap_addr_info_t));
760 if (info == NULL) {
761 /* malloc failure - return what we have so far */
762 return info_list;
763 }
764 info->next = NULL;
765 /* Need to return in same order as getaddrinfo() */
766 if (!info_prev) {
767 info_list = info;
768 info_prev = info;
769 } else {
770 info_prev->next = info;
771 info_prev = info;
772 }
773
774 info->scheme = scheme;
775 info->proto = proto;
776 coap_address_init(&info->addr);
777 info->addr.size = sizeof(struct sockaddr_in6);
778 info->addr.addr.sin6.sin6_family = AF_INET6;
779 memcpy(&info->addr.addr.sin6.sin6_addr, &addr_ipv6,
780 sizeof(info->addr.addr.sin6.sin6_addr));
781 info->addr.addr.sin6.sin6_scope_id = (uint32_t)netif_get_id(netif);
782 switch (scheme) {
783 case COAP_URI_SCHEME_COAP:
784 update_port(&info->addr, port, COAP_DEFAULT_PORT,
785 type == COAP_RESOLVE_TYPE_LOCAL);
786 break;
787 case COAP_URI_SCHEME_COAPS:
788 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
789 type == COAP_RESOLVE_TYPE_LOCAL);
790 break;
791 case COAP_URI_SCHEME_COAP_TCP:
792 update_port(&info->addr, port, COAP_DEFAULT_PORT,
793 type == COAP_RESOLVE_TYPE_LOCAL);
794 break;
795 case COAP_URI_SCHEME_COAPS_TCP:
796 update_port(&info->addr, secure_port, COAPS_DEFAULT_PORT,
797 type == COAP_RESOLVE_TYPE_LOCAL);
798 break;
799 case COAP_URI_SCHEME_HTTP:
800 update_port(&info->addr, port, ws_port,
801 type == COAP_RESOLVE_TYPE_LOCAL);
802 break;
803 case COAP_URI_SCHEME_HTTPS:
804 update_port(&info->addr, secure_port, ws_secure_port,
805 type == COAP_RESOLVE_TYPE_LOCAL);
806 break;
807 case COAP_URI_SCHEME_LAST:
808 default:
809 break;
810 }
811 }
812 }
813 return info_list;
814 }
815 #endif /* COAP_IPV6_SUPPORT */
816 return NULL;
817 #endif /* RIOT_VERSION */
818 }
819 #endif /* !WITH_CONTIKI */
820
821 void
coap_free_address_info(coap_addr_info_t * info)822 coap_free_address_info(coap_addr_info_t *info) {
823 while (info) {
824 coap_addr_info_t *info_next = info->next;
825
826 coap_free_type(COAP_STRING, info);
827 info = info_next;
828 }
829 }
830
831 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
832 void
coap_address_copy(coap_address_t * dst,const coap_address_t * src)833 coap_address_copy(coap_address_t *dst, const coap_address_t *src) {
834 #if defined(WITH_LWIP) || defined(WITH_CONTIKI)
835 memcpy(dst, src, sizeof(coap_address_t));
836 #else
837 memset(dst, 0, sizeof(coap_address_t));
838 dst->size = src->size;
839 #if COAP_IPV6_SUPPORT
840 if (src->addr.sa.sa_family == AF_INET6) {
841 dst->addr.sin6.sin6_family = src->addr.sin6.sin6_family;
842 dst->addr.sin6.sin6_addr = src->addr.sin6.sin6_addr;
843 dst->addr.sin6.sin6_port = src->addr.sin6.sin6_port;
844 dst->addr.sin6.sin6_scope_id = src->addr.sin6.sin6_scope_id;
845 }
846 #endif /* COAP_IPV6_SUPPORT */
847 #if COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT
848 else
849 #endif /* COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT */
850 #if COAP_IPV4_SUPPORT
851 if (src->addr.sa.sa_family == AF_INET) {
852 dst->addr.sin = src->addr.sin;
853 }
854 #endif /* COAP_IPV4_SUPPORT */
855 else {
856 memcpy(&dst->addr, &src->addr, src->size);
857 }
858 #endif
859 }
860
861 int
_coap_address_isany_impl(const coap_address_t * a)862 _coap_address_isany_impl(const coap_address_t *a) {
863 /* need to compare only relevant parts of sockaddr_in6 */
864 switch (a->addr.sa.sa_family) {
865 #if COAP_IPV4_SUPPORT
866 case AF_INET:
867 return a->addr.sin.sin_addr.s_addr == INADDR_ANY;
868 #endif /* COAP_IPV4_SUPPORT */
869 #if COAP_IPV6_SUPPORT
870 case AF_INET6:
871 return memcmp(&in6addr_any,
872 &a->addr.sin6.sin6_addr,
873 sizeof(in6addr_any)) == 0;
874 #endif /* COAP_IPV6_SUPPORT */
875 default:
876 ;
877 }
878
879 return 0;
880 }
881 #endif /* ! WITH_LWIP && ! WITH_CONTIKI */
882