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 
39 static int ba2str(const BTH_ADDR *ba, char *str);
40 static int str2ba(const char *str, BTH_ADDR *ba);
41 static int bachk(const char *str);
42 
43 #elif _POSIX_C_SOURCE >= 200112L
44 #include <netdb.h>
45 #endif
46 
47 int
48 io_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 
73 int
74 io_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 
116 int
117 io_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 
150 int
151 io_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 
195 void
196 io_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 
225 void
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 
254 int
255 io_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 
282 int
283 io_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 
303 int
304 io_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 
328 void
329 io_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 
345 void
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 
359 void
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 
373 int
374 io_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,
394  ip, IO_ADDR_IPV6_STRLEN)))
395  // clang-format on
396  return -1;
397 
398  return 0;
399 }
400 
401 int
402 io_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 
425 int
426 io_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 
450 void
451 io_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 
467 void
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 
485 int
486 io_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 
508 void
509 io_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 
529 int
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 
550 int
551 io_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 
625 int
626 io_addr_set_port(io_addr_t *addr, int port)
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 
683 int
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 
714 int
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 
734 int
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 
764 int
765 io_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 
846 static int
847 ba2str(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 
855 static int
856 str2ba(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 
869 static int
870 bachk(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_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
The intended socket type was not recognized.
Definition: errnum.h:256
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
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
This header file is part of the C11 and POSIX compatibility library; it includes <string.h> and defines any missing functionality.
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
This header file is part of the utilities library; it contains the comparison function definitions...
An IPv6 socket.
Definition: sock.h:33
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
A datagram-oriented, typically connectionless-mode, socket type.
Definition: sock.h:48
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
The address family was not recognized or the address length was invalid for the specified family...
Definition: errnum.h:246
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
An opaque network address type.
Definition: addr.h:30
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
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
A network address info structure.
Definition: addr.h:76
#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
An IPv4 socket.
Definition: sock.h:31
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
This header file is part of the utilities library; it contains the native and platform-independent er...
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
Address family not supported.
Definition: errnum.h:84
The flags had an invalid value.
Definition: errnum.h:239
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
A non-recoverable error occurred.
Definition: errnum.h:241
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
#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
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
int addrlen
The size (in bytes) of addr.
Definition: addr.h:32
int domain
The domain of the socket (only IO_SOCK_IPV4 and IO_SOCK_IPV6 are supported).
Definition: addr.h:81
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
A Bluetooth socket.
Definition: sock.h:29
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_domain(const io_addr_t *addr)
Obtains the domain of a network address.
Definition: addr.c:530
This header file is part of the I/O library; it contains the network socket declarations.
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
Invalid argument.
Definition: errnum.h:129
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_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
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
This is the internal header file of the I/O library.
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
#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
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
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 C11 and POSIX compatibility library; it includes <stdio.h> and defines any missing functionality.
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
io_addr_t addr
The network address.
Definition: addr.h:85
A stream-oriented connection-mode socket type.
Definition: sock.h:43
A UNIX domain socket (only supported on POSIX platforms).
Definition: sock.h:35
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
The service passed was not recognized for the specified socket type.
Definition: errnum.h:254
The name does not resolve for the supplied parameters.
Definition: errnum.h:250
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
The name could not be resolved at this time.
Definition: errnum.h:237
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
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
There was a memory allocation failure.
Definition: errnum.h:248
int type
The type of the socket (either IO_SOCK_STREAM or IO_SOCK_DGRAM).
Definition: addr.h:83
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
This header file is part of the I/O library; it contains the network address declarations.
union __io_addr::@2 addr
The network address.
int io_addr_cmp(const void *p1, const void *p2)
Compares two network addresses.
Definition: addr.c:48