Lely core libraries 1.9.2
addr.c
Go to the documentation of this file.
1
24#include "io.h"
25#include <lely/io/addr.h>
26#include <lely/io/sock.h>
27#include <lely/util/cmp.h>
28#include <lely/util/errnum.h>
29
30#include <assert.h>
31#include <string.h>
32
33#ifdef _WIN32
34
35#include <ctype.h>
36#include <stdio.h>
37#include <stdlib.h>
38
39static int ba2str(const BTH_ADDR *ba, char *str);
40static int str2ba(const char *str, BTH_ADDR *ba);
41static int bachk(const char *str);
42
43#elif _POSIX_C_SOURCE >= 200112L
44#include <netdb.h>
45#endif
46
47int
48io_addr_cmp(const void *p1, const void *p2)
49{
50 if (p1 == p2)
51 return 0;
52
53 if (__unlikely(!p1))
54 return -1;
55 if (__unlikely(!p2))
56 return 1;
57
58 const io_addr_t *a1 = p1;
59 const io_addr_t *a2 = p2;
60
61 int cmp = memcmp(&a1->addr, &a2->addr, MIN(a1->addrlen, a2->addrlen));
62 if (!cmp)
63 cmp = (a2->addrlen < a1->addrlen) - (a1->addrlen < a2->addrlen);
64 return cmp;
65}
66
67// clang-format off
68#if defined(_WIN32) || (defined(__linux__) \
69 && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
70 && defined(HAVE_BLUETOOTH_RFCOMM_H))
71// clang-format on
72
73int
74io_addr_get_rfcomm_a(const io_addr_t *addr, char *ba, int *port)
75{
76 assert(addr);
77
78#ifdef _WIN32
79 if (__unlikely(addr->addrlen < (int)sizeof(SOCKADDR_BTH))) {
80 WSASetLastError(WSAEINVAL);
81 return -1;
82 }
83
84 const SOCKADDR_BTH *addr_bth = (const SOCKADDR_BTH *)&addr->addr;
85 if (__unlikely(addr_bth->addressFamily != AF_BTH)) {
86 WSASetLastError(WSAEAFNOSUPPORT);
87 return -1;
88 }
89
90 if (port)
91 *port = addr_bth->port == BT_PORT_ANY ? 0 : addr_bth->port;
92 if (ba && __unlikely(ba2str(&addr_bth->btAddr, ba) < 0))
93 return -1;
94#else
95 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_rc))) {
96 errno = EINVAL;
97 return -1;
98 }
99
100 const struct sockaddr_rc *addr_rc =
101 (const struct sockaddr_rc *)&addr->addr;
102 if (__unlikely(addr_rc->rc_family != AF_BLUETOOTH)) {
103 errno = EAFNOSUPPORT;
104 return -1;
105 }
106
107 if (port)
108 *port = btohs(addr_rc->rc_channel);
109 if (ba && __unlikely(ba2str(&addr_rc->rc_bdaddr, ba) < 0))
110 return -1;
111#endif
112
113 return 0;
114}
115
116int
117io_addr_set_rfcomm_a(io_addr_t *addr, const char *ba, int port)
118{
119 assert(addr);
120
121 memset(addr, 0, sizeof(*addr));
122#ifdef _WIN32
123 addr->addrlen = sizeof(SOCKADDR_BTH);
124 SOCKADDR_BTH *addr_bth = (SOCKADDR_BTH *)&addr->addr;
125
126 addr_bth->addressFamily = AF_BTH;
127 addr_bth->port = port ? (ULONG)port : BT_PORT_ANY;
128 addr_bth->btAddr = 0;
129 if (ba && *ba) {
130 if (__unlikely(str2ba(ba, &addr_bth->btAddr) < 0))
131 return -1;
132 }
133#else
134 addr->addrlen = sizeof(struct sockaddr_rc);
135 struct sockaddr_rc *addr_rc = (struct sockaddr_rc *)&addr->addr;
136
137 addr_rc->rc_family = AF_BLUETOOTH;
138 addr_rc->rc_channel = htobs(port);
139 if (ba && *ba) {
140 if (__unlikely(str2ba(ba, &addr_rc->rc_bdaddr) < 0))
141 return -1;
142 } else {
143 bacpy(&addr_rc->rc_bdaddr, BDADDR_ANY);
144 }
145#endif
146
147 return 0;
148}
149
150int
151io_addr_get_rfcomm_n(const io_addr_t *addr, uint8_t ba[6], int *port)
152{
153 assert(addr);
154
155#ifdef _WIN32
156 if (__unlikely(addr->addrlen < (int)sizeof(SOCKADDR_BTH))) {
157 WSASetLastError(WSAEINVAL);
158 return -1;
159 }
160
161 const SOCKADDR_BTH *addr_bth = (const SOCKADDR_BTH *)&addr->addr;
162 if (__unlikely(addr_bth->addressFamily != AF_BTH)) {
163 WSASetLastError(WSAEAFNOSUPPORT);
164 return -1;
165 }
166
167 if (port)
168 *port = addr_bth->port == BT_PORT_ANY ? 0 : addr_bth->port;
169 if (ba) {
170 for (int i = 0; i < 6; i++)
171 ba[i] = (addr_bth->btAddr >> (7 - i) * 8) & 0xff;
172 }
173#else
174 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_rc))) {
175 errno = EINVAL;
176 return -1;
177 }
178
179 const struct sockaddr_rc *addr_rc =
180 (const struct sockaddr_rc *)&addr->addr;
181 if (__unlikely(addr_rc->rc_family != AF_BLUETOOTH)) {
182 errno = EAFNOSUPPORT;
183 return -1;
184 }
185
186 if (port)
187 *port = btohs(addr_rc->rc_channel);
188 if (ba)
189 memcpy(ba, &addr_rc->rc_bdaddr, 6);
190#endif
191
192 return 0;
193}
194
195void
196io_addr_set_rfcomm_n(io_addr_t *addr, const uint8_t ba[6], int port)
197{
198 assert(addr);
199
200 memset(addr, 0, sizeof(*addr));
201#ifdef _WIN32
202 addr->addrlen = sizeof(SOCKADDR_BTH);
203 SOCKADDR_BTH *addr_bth = (SOCKADDR_BTH *)&addr->addr;
204
205 addr_bth->addressFamily = AF_BTH;
206 addr_bth->port = port ? (ULONG)port : BT_PORT_ANY;
207 addr_bth->btAddr = 0;
208 if (ba && *ba) {
209 for (int i = 0; i < 6; i++)
210 addr_bth->btAddr |= (BTH_ADDR)ba[i] << (7 - i) * 8;
211 }
212#else
213 addr->addrlen = sizeof(struct sockaddr_rc);
214 struct sockaddr_rc *addr_rc = (struct sockaddr_rc *)&addr->addr;
215
216 addr_rc->rc_family = AF_BLUETOOTH;
217 addr_rc->rc_channel = htobs(port);
218 if (ba && *ba)
219 memcpy(&addr_rc->rc_bdaddr, ba, 6);
220 else
221 bacpy(&addr_rc->rc_bdaddr, BDADDR_ANY);
222#endif
223}
224
225void
227{
228 assert(addr);
229
230 memset(addr, 0, sizeof(*addr));
231#ifdef _WIN32
232 addr->addrlen = sizeof(SOCKADDR_BTH);
233 SOCKADDR_BTH *addr_bth = (SOCKADDR_BTH *)&addr->addr;
234
235 addr_bth->addressFamily = AF_BTH;
236 addr_bth->port = port ? (ULONG)port : BT_PORT_ANY;
237 addr_bth->btAddr = (BTH_ADDR)0xffffff000000ull;
238#else
239 addr->addrlen = sizeof(struct sockaddr_rc);
240 struct sockaddr_rc *addr_rc = (struct sockaddr_rc *)&addr->addr;
241
242 addr_rc->rc_family = AF_BLUETOOTH;
243 addr_rc->rc_channel = htobs(port);
244 bacpy(&addr_rc->rc_bdaddr, BDADDR_LOCAL);
245#endif
246}
247
248// clang-format off
249#endif // _WIN32 || (__linux__ && HAVE_BLUETOOTH_BLUETOOTH_H && HAVE_BLUETOOTH_RFCOMM_H)
250// clang-format on
251
252#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
253
254int
255io_addr_get_ipv4_a(const io_addr_t *addr, char *ip, int *port)
256{
257 assert(addr);
258
259 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_in))) {
261 return -1;
262 }
263
264 const struct sockaddr_in *addr_in =
265 (const struct sockaddr_in *)&addr->addr;
266 if (__unlikely(addr_in->sin_family != AF_INET)) {
268 return -1;
269 }
270
271 if (port)
272 *port = ntohs(addr_in->sin_port);
273 // clang-format off
274 if (ip && __unlikely(!inet_ntop(AF_INET, (void *)&addr_in->sin_addr, ip,
276 // clang-format on
277 return -1;
278
279 return 0;
280}
281
282int
283io_addr_set_ipv4_a(io_addr_t *addr, const char *ip, int port)
284{
285 assert(addr);
286
287 memset(addr, 0, sizeof(*addr));
288 addr->addrlen = sizeof(struct sockaddr_in);
289 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
290
291 addr_in->sin_family = AF_INET;
292 addr_in->sin_port = htons(port);
293 if (ip && *ip) {
294 if (__unlikely(inet_pton(AF_INET, ip, &addr_in->sin_addr) != 1))
295 return -1;
296 } else {
297 addr_in->sin_addr.s_addr = htonl(INADDR_ANY);
298 }
299
300 return 0;
301}
302
303int
304io_addr_get_ipv4_n(const io_addr_t *addr, uint8_t ip[4], int *port)
305{
306 assert(addr);
307
308 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_in))) {
310 return -1;
311 }
312
313 const struct sockaddr_in *addr_in =
314 (const struct sockaddr_in *)&addr->addr;
315 if (__unlikely(addr_in->sin_family != AF_INET)) {
317 return -1;
318 }
319
320 if (port)
321 *port = ntohs(addr_in->sin_port);
322 if (ip)
323 memcpy(ip, &addr_in->sin_addr.s_addr, 4);
324
325 return 0;
326}
327
328void
329io_addr_set_ipv4_n(io_addr_t *addr, const uint8_t ip[4], int port)
330{
331 assert(addr);
332
333 memset(addr, 0, sizeof(*addr));
334 addr->addrlen = sizeof(struct sockaddr_in);
335 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
336
337 addr_in->sin_family = AF_INET;
338 addr_in->sin_port = htons(port);
339 if (ip)
340 memcpy(&addr_in->sin_addr.s_addr, ip, 4);
341 else
342 addr_in->sin_addr.s_addr = htonl(INADDR_ANY);
343}
344
345void
347{
348 assert(addr);
349
350 memset(addr, 0, sizeof(*addr));
351 addr->addrlen = sizeof(struct sockaddr_in);
352 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
353
354 addr_in->sin_family = AF_INET;
355 addr_in->sin_port = htons(port);
356 addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
357}
358
359void
361{
362 assert(addr);
363
364 memset(addr, 0, sizeof(*addr));
365 addr->addrlen = sizeof(struct sockaddr_in);
366 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
367
368 addr_in->sin_family = AF_INET;
369 addr_in->sin_port = htons(port);
370 addr_in->sin_addr.s_addr = htonl(INADDR_BROADCAST);
371}
372
373int
374io_addr_get_ipv6_a(const io_addr_t *addr, char *ip, int *port)
375{
376 assert(addr);
377
378 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_in6))) {
380 return -1;
381 }
382
383 const struct sockaddr_in6 *addr_in6 =
384 (const struct sockaddr_in6 *)&addr->addr;
385 if (__unlikely(addr_in6->sin6_family != AF_INET6)) {
387 return -1;
388 }
389
390 if (port)
391 *port = ntohs(addr_in6->sin6_port);
392 // clang-format off
393 if (ip && __unlikely(!inet_ntop(AF_INET6, (void *)&addr_in6->sin6_addr,
395 // clang-format on
396 return -1;
397
398 return 0;
399}
400
401int
402io_addr_set_ipv6_a(io_addr_t *addr, const char *ip, int port)
403{
404 assert(addr);
405
406 memset(addr, 0, sizeof(*addr));
407 addr->addrlen = sizeof(struct sockaddr_in6);
408 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr->addr;
409
410 addr_in6->sin6_family = AF_INET6;
411 addr_in6->sin6_port = htons(port);
412 if (ip && *ip) {
413 // clang-format off
414 if (__unlikely(inet_pton(AF_INET6, ip, &addr_in6->sin6_addr)
415 != 1))
416 // clang-format on
417 return -1;
418 } else {
419 addr_in6->sin6_addr = in6addr_any;
420 }
421
422 return 0;
423}
424
425int
426io_addr_get_ipv6_n(const io_addr_t *addr, uint8_t ip[16], int *port)
427{
428 assert(addr);
429
430 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_in6))) {
432 return -1;
433 }
434
435 const struct sockaddr_in6 *addr_in6 =
436 (const struct sockaddr_in6 *)&addr->addr;
437 if (__unlikely(addr_in6->sin6_family != AF_INET6)) {
439 return -1;
440 }
441
442 if (port)
443 *port = ntohs(addr_in6->sin6_port);
444 if (ip)
445 memcpy(ip, &addr_in6->sin6_addr.s6_addr, 16);
446
447 return 0;
448}
449
450void
451io_addr_set_ipv6_n(io_addr_t *addr, const uint8_t ip[16], int port)
452{
453 assert(addr);
454
455 memset(addr, 0, sizeof(*addr));
456 addr->addrlen = sizeof(struct sockaddr_in6);
457 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr->addr;
458
459 addr_in6->sin6_family = AF_INET6;
460 addr_in6->sin6_port = htons(port);
461 if (ip)
462 memcpy(&addr_in6->sin6_addr.s6_addr, ip, 16);
463 else
464 addr_in6->sin6_addr = in6addr_any;
465}
466
467void
469{
470 assert(addr);
471
472 memset(addr, 0, sizeof(*addr));
473 addr->addrlen = sizeof(struct sockaddr_in6);
474 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr->addr;
475
476 addr_in6->sin6_family = AF_INET6;
477 addr_in6->sin6_port = htons(port);
478 addr_in6->sin6_addr = in6addr_loopback;
479}
480
481#endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
482
483#if _POSIX_C_SOURCE >= 200112L
484
485int
486io_addr_get_unix(const io_addr_t *addr, char *path)
487{
488 assert(addr);
489
490 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_un))) {
491 errno = EINVAL;
492 return -1;
493 }
494
495 const struct sockaddr_un *addr_un =
496 (const struct sockaddr_un *)&addr->addr;
497 if (__unlikely(addr_un->sun_family != AF_UNIX)) {
498 errno = EAFNOSUPPORT;
499 return -1;
500 }
501
502 if (path)
503 strncpy(path, addr_un->sun_path, IO_ADDR_UNIX_STRLEN);
504
505 return 0;
506}
507
508void
509io_addr_set_unix(io_addr_t *addr, const char *path)
510{
511 assert(addr);
512 assert(path);
513
514 memset(addr, 0, sizeof(*addr));
515 addr->addrlen = sizeof(struct sockaddr_un);
516 struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr->addr;
517
518 addr_un->sun_family = AF_UNIX;
519
520 size_t n = MIN(strlen(path), sizeof(addr_un->sun_path) - 1);
521 strncpy(addr_un->sun_path, path, n);
522 addr_un->sun_path[n] = '\0';
523}
524
525#endif // _POSIX_C_SOURCE >= 200112L
526
527#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
528
529int
531{
532 assert(addr);
533
534 switch (((const struct sockaddr *)&addr->addr)->sa_family) {
535#ifdef _WIN32
536 case AF_BTH: return IO_SOCK_BTH;
537#elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
538 && defined(HAVE_BLUETOOTH_RFCOMM_H)
539 case AF_BLUETOOTH: return IO_SOCK_BTH;
540#endif
541 case AF_INET: return IO_SOCK_IPV4;
542 case AF_INET6: return IO_SOCK_IPV6;
543#if _POSIX_C_SOURCE >= 200112L
544 case AF_UNIX: return IO_SOCK_UNIX;
545#endif
546 default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
547 }
548}
549
550int
551io_addr_get_port(const io_addr_t *addr, int *port)
552{
553 assert(addr);
554
555 if (__unlikely(addr->addrlen < (int)sizeof(sa_family_t))) {
557 return -1;
558 }
559
560 switch (((const struct sockaddr *)&addr->addr)->sa_family) {
561#ifdef _WIN32
562 case AF_BTH: {
563 if (__unlikely(addr->addrlen < (int)sizeof(SOCKADDR_BTH))) {
564 WSASetLastError(WSAEINVAL);
565 return -1;
566 }
567 const SOCKADDR_BTH *addr_bth =
568 (const SOCKADDR_BTH *)&addr->addr;
569 if (port)
570 // clang-format off
571 *port = addr_bth->port == BT_PORT_ANY
572 ? 0 : addr_bth->port;
573 // clang-format on
574 return 0;
575 }
576#elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
577 && defined(HAVE_BLUETOOTH_RFCOMM_H)
578 case AF_BLUETOOTH: {
579 // clang-format off
580 if (__unlikely(addr->addrlen
581 < (int)sizeof(struct sockaddr_rc))) {
582 // clang-format on
583 errno = EINVAL;
584 return -1;
585 }
586 const struct sockaddr_rc *addr_rc =
587 (const struct sockaddr_rc *)&addr->addr;
588 if (port)
589 *port = btohs(addr_rc->rc_channel);
590 return 0;
591 }
592#endif
593 case AF_INET: {
594 // clang-format off
595 if (__unlikely(addr->addrlen
596 < (int)sizeof(struct sockaddr_in))) {
597 // clang-format on
599 return -1;
600 }
601 const struct sockaddr_in *addr_in =
602 (const struct sockaddr_in *)&addr->addr;
603 if (port)
604 *port = ntohs(addr_in->sin_port);
605 return 0;
606 }
607 case AF_INET6: {
608 // clang-format off
609 if (__unlikely(addr->addrlen
610 < (int)sizeof(struct sockaddr_in6))) {
611 // clang-format on
613 return -1;
614 }
615 const struct sockaddr_in6 *addr_in6 =
616 (const struct sockaddr_in6 *)&addr->addr;
617 if (port)
618 *port = ntohs(addr_in6->sin6_port);
619 return 0;
620 }
621 default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
622 }
623}
624
625int
627{
628 assert(addr);
629
630 if (__unlikely(addr->addrlen < (int)sizeof(sa_family_t))) {
632 return -1;
633 }
634
635 switch (((struct sockaddr *)&addr->addr)->sa_family) {
636#ifdef _WIN32
637 case AF_BTH:
638 if (__unlikely(addr->addrlen < (int)sizeof(SOCKADDR_BTH))) {
639 WSASetLastError(WSAEINVAL);
640 return -1;
641 }
642 ((SOCKADDR_BTH *)&addr->addr)->port =
643 port ? (ULONG)port : BT_PORT_ANY;
644 ;
645 return 0;
646#elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
647 && defined(HAVE_BLUETOOTH_RFCOMM_H)
648 case AF_BLUETOOTH:
649 // clang-format off
650 if (__unlikely(addr->addrlen
651 < (int)sizeof(struct sockaddr_rc))) {
652 // clang-format on
653 errno = EINVAL;
654 return -1;
655 }
656 ((struct sockaddr_rc *)&addr->addr)->rc_channel = htobs(port);
657 return 0;
658#endif
659 case AF_INET:
660 // clang-format off
661 if (__unlikely(addr->addrlen
662 < (int)sizeof(struct sockaddr_in))) {
663 // clang-format on
665 return -1;
666 }
667 ((struct sockaddr_in *)&addr->addr)->sin_port = htons(port);
668 return 0;
669 case AF_INET6:
670 // clang-format off
671 if (__unlikely(addr->addrlen
672 < (int)sizeof(struct sockaddr_in6))) {
673 // clang-format on
675 return -1;
676 }
677 ((struct sockaddr_in6 *)&addr->addr)->sin6_port = htons(port);
678 return 0;
679 default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
680 }
681}
682
683int
685{
686 assert(addr);
687
688 if (__unlikely(addr->addrlen < (int)sizeof(sa_family_t)))
689 return 0;
690
691 switch (((const struct sockaddr *)&addr->addr)->sa_family) {
692 case AF_INET: {
693 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_in)))
694 return 0;
695 const struct sockaddr_in *addr_in =
696 (const struct sockaddr_in *)&addr->addr;
697 return ntohl(addr_in->sin_addr.s_addr) == INADDR_LOOPBACK;
698 }
699 case AF_INET6: {
700 // clang-format off
701 if (__unlikely(addr->addrlen
702 < (int)sizeof(struct sockaddr_in6)))
703 // clang-format on
704 return 0;
705 const struct sockaddr_in6 *addr_in6 =
706 (const struct sockaddr_in6 *)&addr->addr;
707 return !memcmp(&addr_in6->sin6_addr, &in6addr_any,
708 sizeof(in6addr_any));
709 }
710 default: return 0;
711 }
712}
713
714int
716{
717 assert(addr);
718
719 if (__unlikely(addr->addrlen < (int)sizeof(sa_family_t)))
720 return 0;
721
722 switch (((const struct sockaddr *)&addr->addr)->sa_family) {
723 case AF_INET: {
724 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_in)))
725 return 0;
726 const struct sockaddr_in *addr_in =
727 (const struct sockaddr_in *)&addr->addr;
728 return ntohl(addr_in->sin_addr.s_addr) == INADDR_BROADCAST;
729 }
730 default: return 0;
731 }
732}
733
734int
736{
737 assert(addr);
738
739 if (__unlikely(addr->addrlen < (int)sizeof(sa_family_t)))
740 return 0;
741
742 switch (((const struct sockaddr *)&addr->addr)->sa_family) {
743 case AF_INET: {
744 if (__unlikely(addr->addrlen < (int)sizeof(struct sockaddr_in)))
745 return 0;
746 const struct sockaddr_in *addr_in =
747 (const struct sockaddr_in *)&addr->addr;
748 return (ntohl(addr_in->sin_addr.s_addr) >> 28) == 0xe;
749 }
750 case AF_INET6: {
751 // clang-format off
752 if (__unlikely(addr->addrlen
753 < (int)sizeof(struct sockaddr_in6)))
754 // clang-format on
755 return 0;
756 const struct sockaddr_in6 *addr_in6 =
757 (const struct sockaddr_in6 *)&addr->addr;
758 return addr_in6->sin6_addr.s6_addr[0] == 0xff;
759 }
760 default: return 0;
761 }
762}
763
764int
765io_get_addrinfo(int maxinfo, struct io_addrinfo *info, const char *nodename,
766 const char *servname, const struct io_addrinfo *hints)
767{
768 if (!info)
769 maxinfo = 0;
770
771 int ecode = 0;
772
773 struct addrinfo ai_hints = { .ai_family = AF_UNSPEC };
774 if (hints) {
775 switch (hints->domain) {
776 case 0: break;
777 case IO_SOCK_IPV4: ai_hints.ai_family = AF_INET; break;
778 case IO_SOCK_IPV6: ai_hints.ai_family = AF_INET6; break;
779 default: ecode = EAI_FAMILY; break;
780 }
781
782 switch (hints->type) {
783 case 0: break;
784 case IO_SOCK_STREAM: ai_hints.ai_socktype = SOCK_STREAM; break;
785 case IO_SOCK_DGRAM: ai_hints.ai_socktype = SOCK_DGRAM; break;
786 default: ecode = EAI_SOCKTYPE; break;
787 }
788 }
789
790 struct addrinfo *res = NULL;
791 if (__likely(!ecode))
792 ecode = getaddrinfo(nodename, servname, &ai_hints, &res);
793 if (__unlikely(ecode)) {
794 switch (ecode) {
795 case EAI_AGAIN: set_errnum(ERRNUM_AI_AGAIN); break;
796 case EAI_BADFLAGS: set_errnum(ERRNUM_AI_BADFLAGS); break;
797 case EAI_FAIL: set_errnum(ERRNUM_AI_FAIL); break;
798 case EAI_FAMILY: set_errnum(ERRNUM_AI_FAMILY); break;
799 case EAI_MEMORY: set_errnum(ERRNUM_AI_MEMORY); break;
800 case EAI_NONAME: set_errnum(ERRNUM_AI_NONAME); break;
801 case EAI_SERVICE: set_errnum(ERRNUM_AI_SERVICE); break;
802 case EAI_SOCKTYPE: set_errnum(ERRNUM_AI_SOCKTYPE); break;
803#ifdef EAI_SYSTEM
804 case EAI_SYSTEM: break;
805#endif
806 }
807 return -1;
808 }
809 assert(res);
810
811 int ninfo = 0;
812 for (struct addrinfo *ai = res; ai; ai = ai->ai_next) {
813 int domain;
814 switch (ai->ai_family) {
815 case AF_INET: domain = IO_SOCK_IPV4; break;
816 case AF_INET6: domain = IO_SOCK_IPV6; break;
817 default: continue;
818 }
819
820 int type;
821 switch (ai->ai_socktype) {
822 case SOCK_STREAM: type = IO_SOCK_STREAM; break;
823 case SOCK_DGRAM: type = IO_SOCK_DGRAM; break;
824 default: continue;
825 }
826
827 if (ninfo++ < maxinfo) {
828 memset(info, 0, sizeof(*info));
829 info->domain = domain;
830 info->type = type;
831 info->addr.addrlen = ai->ai_addrlen;
832 memcpy(&info->addr.addr, ai->ai_addr, ai->ai_addrlen);
833 info++;
834 }
835 }
836
837 freeaddrinfo(res);
838
839 return ninfo;
840}
841
842#endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
843
844#ifdef _WIN32
845
846static int
847ba2str(const BTH_ADDR *ba, char *str)
848{
849 return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
850 (int)((*ba >> 40) & 0xff), (int)((*ba >> 32) & 0xff),
851 (int)((*ba >> 24) & 0xff), (int)((*ba >> 16) & 0xff),
852 ((int)(*ba >> 8) & 0xff), (int)(*ba & 0xff));
853}
854
855static int
856str2ba(const char *str, BTH_ADDR *ba)
857{
858 if (__unlikely(bachk(str) < 0)) {
859 *ba = 0;
860 return -1;
861 }
862
863 for (int i = 5; i >= 0; i--, str += 3)
864 *ba |= (BTH_ADDR)strtol(str, NULL, 16) << (i * 8);
865
866 return 0;
867}
868
869static int
870bachk(const char *str)
871{
872 assert(str);
873
874 if (__unlikely(strlen(str) != 17))
875 return -1;
876
877 while (*str) {
878 if (__unlikely(!isxdigit(*str++)))
879 return -1;
880 if (__unlikely(!isxdigit(*str++)))
881 return -1;
882 if (!*str)
883 break;
884 if (__unlikely(*str++ != ':'))
885 return -1;
886 }
887
888 return 0;
889}
890
891#endif // _WIN32
int io_addr_get_domain(const io_addr_t *addr)
Obtains the domain of a network address.
Definition: addr.c:530
int io_addr_get_ipv6_n(const io_addr_t *addr, uint8_t ip[16], int *port)
Obtains an IPv6 address and port number from a network address.
Definition: addr.c:426
void io_addr_set_ipv4_n(io_addr_t *addr, const uint8_t ip[4], int port)
Initializes a network address from an IPv4 address and port number.
Definition: addr.c:329
void io_addr_set_ipv6_n(io_addr_t *addr, const uint8_t ip[16], int port)
Initializes a network address from an IPv6 address and port number.
Definition: addr.c:451
int io_addr_is_broadcast(const io_addr_t *addr)
Returns 1 if the network address is a broadcast address, and 0 if not.
Definition: addr.c:715
int io_get_addrinfo(int maxinfo, struct io_addrinfo *info, const char *nodename, const char *servname, const struct io_addrinfo *hints)
Obtains a list of network addresses corresponding to a host and/or service name.
Definition: addr.c:765
void io_addr_set_rfcomm_n(io_addr_t *addr, const uint8_t ba[6], int port)
Initializes a network address from an RFCOMM Bluetooth device address and port number.
Definition: addr.c:196
void io_addr_set_ipv6_loopback(io_addr_t *addr, int port)
Initializes a network address with the IPv6 loopback address and a port number.
Definition: addr.c:468
void io_addr_set_rfcomm_local(io_addr_t *addr, int port)
Initializes a network address with the local Bluetooth (RFCOMM) device address (FF:FF:FF:00:00:00) an...
Definition: addr.c:226
int io_addr_set_port(io_addr_t *addr, int port)
Initializes the port number of an IPv4 or IPv6 network address.
Definition: addr.c:626
int io_addr_is_multicast(const io_addr_t *addr)
Returns 1 if the network address is a multicast address, and 0 if not.
Definition: addr.c:735
int io_addr_cmp(const void *p1, const void *p2)
Compares two network addresses.
Definition: addr.c:48
int io_addr_set_ipv6_a(io_addr_t *addr, const char *ip, int port)
Initializes a network address from an IPv6 address and port number.
Definition: addr.c:402
int io_addr_get_port(const io_addr_t *addr, int *port)
Obtains the port number of an IPv4 or IPv6 network address.
Definition: addr.c:551
int io_addr_get_rfcomm_n(const io_addr_t *addr, uint8_t ba[6], int *port)
Obtains an RFCOMM Bluetooth device address and port number from a network address.
Definition: addr.c:151
void io_addr_set_ipv4_broadcast(io_addr_t *addr, int port)
Initializes a network address with the IPv4 broadcast address and a port number.
Definition: addr.c:360
int io_addr_get_ipv4_a(const io_addr_t *addr, char *ip, int *port)
Obtains an IPv4 address and port number from a network address.
Definition: addr.c:255
int io_addr_get_ipv6_a(const io_addr_t *addr, char *ip, int *port)
Obtains an IPv6 address and port number from a network address.
Definition: addr.c:374
int io_addr_get_ipv4_n(const io_addr_t *addr, uint8_t ip[4], int *port)
Obtains an IPv4 address and port number from a network address.
Definition: addr.c:304
int io_addr_get_rfcomm_a(const io_addr_t *addr, char *ba, int *port)
Obtains an RFCOMM Bluetooth device address and port number from a network address.
Definition: addr.c:74
int io_addr_set_rfcomm_a(io_addr_t *addr, const char *ba, int port)
Initializes a network address from an RFCOMM Bluetooth device address and port number.
Definition: addr.c:117
int io_addr_is_loopback(const io_addr_t *addr)
Returns 1 if the network address is a loopback address, and 0 if not.
Definition: addr.c:684
int io_addr_set_ipv4_a(io_addr_t *addr, const char *ip, int port)
Initializes a network address from an IPv4 address and port number.
Definition: addr.c:283
int io_addr_get_unix(const io_addr_t *addr, char *path)
Obtains a UNIX domain socket path name from a network address.
Definition: addr.c:486
void io_addr_set_unix(io_addr_t *addr, const char *path)
Initializes a network address from a UNIX domain socket path name.
Definition: addr.c:509
void io_addr_set_ipv4_loopback(io_addr_t *addr, int port)
Initializes a network address with the IPv4 loopback address and a port number.
Definition: addr.c:346
This header file is part of the I/O library; it contains the network address declarations.
#define IO_ADDR_IPV6_STRLEN
The maximum number of bytes required to hold the text representation of an IPv6 internet address,...
Definition: addr.h:67
#define IO_ADDR_IPV4_STRLEN
The maximum number of bytes required to hold the text representation of an IPv4 internet address,...
Definition: addr.h:61
#define IO_ADDR_UNIX_STRLEN
The maximum number of bytes required to hold the text representation of a UNIX domain socket path nam...
Definition: addr.h:73
This header file is part of the utilities library; it contains the comparison function definitions.
This header file is part of the utilities library; it contains the native and platform-independent er...
@ ERRNUM_AI_MEMORY
There was a memory allocation failure.
Definition: errnum.h:248
@ ERRNUM_AFNOSUPPORT
Address family not supported.
Definition: errnum.h:84
@ ERRNUM_AI_BADFLAGS
The flags had an invalid value.
Definition: errnum.h:239
@ ERRNUM_AI_SOCKTYPE
The intended socket type was not recognized.
Definition: errnum.h:256
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
@ ERRNUM_AI_AGAIN
The name could not be resolved at this time.
Definition: errnum.h:237
@ ERRNUM_AI_FAIL
A non-recoverable error occurred.
Definition: errnum.h:241
@ ERRNUM_AI_FAMILY
The address family was not recognized or the address length was invalid for the specified family.
Definition: errnum.h:246
@ ERRNUM_AI_SERVICE
The service passed was not recognized for the specified socket type.
Definition: errnum.h:254
@ ERRNUM_AI_NONAME
The name does not resolve for the supplied parameters.
Definition: errnum.h:250
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
This header file is part of the I/O library; it contains the network socket declarations.
@ IO_SOCK_DGRAM
A datagram-oriented, typically connectionless-mode, socket type.
Definition: sock.h:48
@ IO_SOCK_STREAM
A stream-oriented connection-mode socket type.
Definition: sock.h:43
@ IO_SOCK_IPV4
An IPv4 socket.
Definition: sock.h:31
@ IO_SOCK_UNIX
A UNIX domain socket (only supported on POSIX platforms).
Definition: sock.h:35
@ IO_SOCK_IPV6
An IPv6 socket.
Definition: sock.h:33
@ IO_SOCK_BTH
A Bluetooth socket.
Definition: sock.h:29
This is the internal header file of the I/O library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdio....
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
An opaque network address type.
Definition: addr.h:30
int addrlen
The size (in bytes) of addr.
Definition: addr.h:32
union __io_addr::@2 addr
The network address.
A network address info structure.
Definition: addr.h:76
int type
The type of the socket (either IO_SOCK_STREAM or IO_SOCK_DGRAM).
Definition: addr.h:83
int domain
The domain of the socket (only IO_SOCK_IPV4 and IO_SOCK_IPV6 are supported).
Definition: addr.h:81
io_addr_t addr
The network address.
Definition: addr.h:85