Lely core libraries  2.2.5
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 (!p1)
54  return -1;
55  if (!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 (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 (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 && ba2str(&addr_bth->btAddr, ba) < 0)
93  return -1;
94 #else
95  if (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 (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 && 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 (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 (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 (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 (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 (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 (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 (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 (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 && !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 (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 (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 (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 (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 (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 && !inet_ntop(AF_INET6, (void *)&addr_in6->sin6_addr, ip,
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  if (inet_pton(AF_INET6, ip, &addr_in6->sin6_addr) != 1)
414  return -1;
415  } else {
416  addr_in6->sin6_addr = in6addr_any;
417  }
418 
419  return 0;
420 }
421 
422 int
423 io_addr_get_ipv6_n(const io_addr_t *addr, uint8_t ip[16], int *port)
424 {
425  assert(addr);
426 
427  if (addr->addrlen < (int)sizeof(struct sockaddr_in6)) {
429  return -1;
430  }
431 
432  const struct sockaddr_in6 *addr_in6 =
433  (const struct sockaddr_in6 *)&addr->addr;
434  if (addr_in6->sin6_family != AF_INET6) {
436  return -1;
437  }
438 
439  if (port)
440  *port = ntohs(addr_in6->sin6_port);
441  if (ip)
442  memcpy(ip, &addr_in6->sin6_addr.s6_addr, 16);
443 
444  return 0;
445 }
446 
447 void
448 io_addr_set_ipv6_n(io_addr_t *addr, const uint8_t ip[16], int port)
449 {
450  assert(addr);
451 
452  memset(addr, 0, sizeof(*addr));
453  addr->addrlen = sizeof(struct sockaddr_in6);
454  struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr->addr;
455 
456  addr_in6->sin6_family = AF_INET6;
457  addr_in6->sin6_port = htons(port);
458  if (ip)
459  memcpy(&addr_in6->sin6_addr.s6_addr, ip, 16);
460  else
461  addr_in6->sin6_addr = in6addr_any;
462 }
463 
464 void
466 {
467  assert(addr);
468 
469  memset(addr, 0, sizeof(*addr));
470  addr->addrlen = sizeof(struct sockaddr_in6);
471  struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr->addr;
472 
473  addr_in6->sin6_family = AF_INET6;
474  addr_in6->sin6_port = htons(port);
475  addr_in6->sin6_addr = in6addr_loopback;
476 }
477 
478 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
479 
480 #if _POSIX_C_SOURCE >= 200112L
481 
482 int
483 io_addr_get_unix(const io_addr_t *addr, char *path)
484 {
485  assert(addr);
486 
487  if (addr->addrlen < (int)sizeof(struct sockaddr_un)) {
488  errno = EINVAL;
489  return -1;
490  }
491 
492  const struct sockaddr_un *addr_un =
493  (const struct sockaddr_un *)&addr->addr;
494  if (addr_un->sun_family != AF_UNIX) {
495  errno = EAFNOSUPPORT;
496  return -1;
497  }
498 
499  if (path)
500  strncpy(path, addr_un->sun_path, IO_ADDR_UNIX_STRLEN);
501 
502  return 0;
503 }
504 
505 void
506 io_addr_set_unix(io_addr_t *addr, const char *path)
507 {
508  assert(addr);
509  assert(path);
510 
511  memset(addr, 0, sizeof(*addr));
512  addr->addrlen = sizeof(struct sockaddr_un);
513  struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr->addr;
514 
515  addr_un->sun_family = AF_UNIX;
516 
517  size_t n = MIN(strlen(path), sizeof(addr_un->sun_path) - 1);
518  strncpy(addr_un->sun_path, path, n);
519  addr_un->sun_path[n] = '\0';
520 }
521 
522 #endif // _POSIX_C_SOURCE >= 200112L
523 
524 #if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
525 
526 int
528 {
529  assert(addr);
530 
531  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
532 #ifdef _WIN32
533  case AF_BTH: return IO_SOCK_BTH;
534 #elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
535  && defined(HAVE_BLUETOOTH_RFCOMM_H)
536  case AF_BLUETOOTH: return IO_SOCK_BTH;
537 #endif
538  case AF_INET: return IO_SOCK_IPV4;
539  case AF_INET6: return IO_SOCK_IPV6;
540 #if _POSIX_C_SOURCE >= 200112L
541  case AF_UNIX: return IO_SOCK_UNIX;
542 #endif
543  default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
544  }
545 }
546 
547 int
548 io_addr_get_port(const io_addr_t *addr, int *port)
549 {
550  assert(addr);
551 
552  if (addr->addrlen < (int)sizeof(sa_family_t)) {
554  return -1;
555  }
556 
557  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
558 #ifdef _WIN32
559  case AF_BTH: {
560  if (addr->addrlen < (int)sizeof(SOCKADDR_BTH)) {
561  WSASetLastError(WSAEINVAL);
562  return -1;
563  }
564  const SOCKADDR_BTH *addr_bth =
565  (const SOCKADDR_BTH *)&addr->addr;
566  if (port)
567  // clang-format off
568  *port = addr_bth->port == BT_PORT_ANY
569  ? 0 : addr_bth->port;
570  // clang-format on
571  return 0;
572  }
573 #elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
574  && defined(HAVE_BLUETOOTH_RFCOMM_H)
575  case AF_BLUETOOTH: {
576  if (addr->addrlen < (int)sizeof(struct sockaddr_rc)) {
577  errno = EINVAL;
578  return -1;
579  }
580  const struct sockaddr_rc *addr_rc =
581  (const struct sockaddr_rc *)&addr->addr;
582  if (port)
583  *port = btohs(addr_rc->rc_channel);
584  return 0;
585  }
586 #endif
587  case AF_INET: {
588  if (addr->addrlen < (int)sizeof(struct sockaddr_in)) {
590  return -1;
591  }
592  const struct sockaddr_in *addr_in =
593  (const struct sockaddr_in *)&addr->addr;
594  if (port)
595  *port = ntohs(addr_in->sin_port);
596  return 0;
597  }
598  case AF_INET6: {
599  if (addr->addrlen < (int)sizeof(struct sockaddr_in6)) {
601  return -1;
602  }
603  const struct sockaddr_in6 *addr_in6 =
604  (const struct sockaddr_in6 *)&addr->addr;
605  if (port)
606  *port = ntohs(addr_in6->sin6_port);
607  return 0;
608  }
609  default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
610  }
611 }
612 
613 int
614 io_addr_set_port(io_addr_t *addr, int port)
615 {
616  assert(addr);
617 
618  if (addr->addrlen < (int)sizeof(sa_family_t)) {
620  return -1;
621  }
622 
623  switch (((struct sockaddr *)&addr->addr)->sa_family) {
624 #ifdef _WIN32
625  case AF_BTH:
626  if (addr->addrlen < (int)sizeof(SOCKADDR_BTH)) {
627  WSASetLastError(WSAEINVAL);
628  return -1;
629  }
630  ((SOCKADDR_BTH *)&addr->addr)->port =
631  port ? (ULONG)port : BT_PORT_ANY;
632  ;
633  return 0;
634 #elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
635  && defined(HAVE_BLUETOOTH_RFCOMM_H)
636  case AF_BLUETOOTH:
637  if (addr->addrlen < (int)sizeof(struct sockaddr_rc)) {
638  errno = EINVAL;
639  return -1;
640  }
641  ((struct sockaddr_rc *)&addr->addr)->rc_channel = htobs(port);
642  return 0;
643 #endif
644  case AF_INET:
645  if (addr->addrlen < (int)sizeof(struct sockaddr_in)) {
647  return -1;
648  }
649  ((struct sockaddr_in *)&addr->addr)->sin_port = htons(port);
650  return 0;
651  case AF_INET6:
652  if (addr->addrlen < (int)sizeof(struct sockaddr_in6)) {
654  return -1;
655  }
656  ((struct sockaddr_in6 *)&addr->addr)->sin6_port = htons(port);
657  return 0;
658  default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
659  }
660 }
661 
662 int
664 {
665  assert(addr);
666 
667  if (addr->addrlen < (int)sizeof(sa_family_t))
668  return 0;
669 
670  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
671  case AF_INET: {
672  if (addr->addrlen < (int)sizeof(struct sockaddr_in))
673  return 0;
674  const struct sockaddr_in *addr_in =
675  (const struct sockaddr_in *)&addr->addr;
676  return ntohl(addr_in->sin_addr.s_addr) == INADDR_LOOPBACK;
677  }
678  case AF_INET6: {
679  if (addr->addrlen < (int)sizeof(struct sockaddr_in6))
680  return 0;
681  const struct sockaddr_in6 *addr_in6 =
682  (const struct sockaddr_in6 *)&addr->addr;
683  return !memcmp(&addr_in6->sin6_addr, &in6addr_any,
684  sizeof(in6addr_any));
685  }
686  default: return 0;
687  }
688 }
689 
690 int
692 {
693  assert(addr);
694 
695  if (addr->addrlen < (int)sizeof(sa_family_t))
696  return 0;
697 
698  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
699  case AF_INET: {
700  if (addr->addrlen < (int)sizeof(struct sockaddr_in))
701  return 0;
702  const struct sockaddr_in *addr_in =
703  (const struct sockaddr_in *)&addr->addr;
704  return ntohl(addr_in->sin_addr.s_addr) == INADDR_BROADCAST;
705  }
706  default: return 0;
707  }
708 }
709 
710 int
712 {
713  assert(addr);
714 
715  if (addr->addrlen < (int)sizeof(sa_family_t))
716  return 0;
717 
718  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
719  case AF_INET: {
720  if (addr->addrlen < (int)sizeof(struct sockaddr_in))
721  return 0;
722  const struct sockaddr_in *addr_in =
723  (const struct sockaddr_in *)&addr->addr;
724  return (ntohl(addr_in->sin_addr.s_addr) >> 28) == 0xe;
725  }
726  case AF_INET6: {
727  if (addr->addrlen < (int)sizeof(struct sockaddr_in6))
728  return 0;
729  const struct sockaddr_in6 *addr_in6 =
730  (const struct sockaddr_in6 *)&addr->addr;
731  return addr_in6->sin6_addr.s6_addr[0] == 0xff;
732  }
733  default: return 0;
734  }
735 }
736 
737 int
738 io_get_addrinfo(int maxinfo, struct io_addrinfo *info, const char *nodename,
739  const char *servname, const struct io_addrinfo *hints)
740 {
741  if (!info)
742  maxinfo = 0;
743 
744  int ecode = 0;
745 
746  struct addrinfo ai_hints = { .ai_family = AF_UNSPEC };
747  if (hints) {
748  switch (hints->domain) {
749  case 0: break;
750  case IO_SOCK_IPV4: ai_hints.ai_family = AF_INET; break;
751  case IO_SOCK_IPV6: ai_hints.ai_family = AF_INET6; break;
752  default: ecode = EAI_FAMILY; break;
753  }
754 
755  switch (hints->type) {
756  case 0: break;
757  case IO_SOCK_STREAM: ai_hints.ai_socktype = SOCK_STREAM; break;
758  case IO_SOCK_DGRAM: ai_hints.ai_socktype = SOCK_DGRAM; break;
759  default: ecode = EAI_SOCKTYPE; break;
760  }
761  }
762 
763  struct addrinfo *res = NULL;
764  if (!ecode)
765  ecode = getaddrinfo(nodename, servname, &ai_hints, &res);
766  if (ecode) {
767  switch (ecode) {
768  case EAI_AGAIN: set_errnum(ERRNUM_AI_AGAIN); break;
769  case EAI_BADFLAGS: set_errnum(ERRNUM_AI_BADFLAGS); break;
770  case EAI_FAIL: set_errnum(ERRNUM_AI_FAIL); break;
771  case EAI_FAMILY: set_errnum(ERRNUM_AI_FAMILY); break;
772  case EAI_MEMORY: set_errnum(ERRNUM_AI_MEMORY); break;
773  case EAI_NONAME: set_errnum(ERRNUM_AI_NONAME); break;
774  case EAI_SERVICE: set_errnum(ERRNUM_AI_SERVICE); break;
775  case EAI_SOCKTYPE: set_errnum(ERRNUM_AI_SOCKTYPE); break;
776 #ifdef EAI_SYSTEM
777  case EAI_SYSTEM: break;
778 #endif
779  }
780  return -1;
781  }
782  assert(res);
783 
784  int ninfo = 0;
785  for (struct addrinfo *ai = res; ai; ai = ai->ai_next) {
786  int domain;
787  switch (ai->ai_family) {
788  case AF_INET: domain = IO_SOCK_IPV4; break;
789  case AF_INET6: domain = IO_SOCK_IPV6; break;
790  default: continue;
791  }
792 
793  int type;
794  switch (ai->ai_socktype) {
795  case SOCK_STREAM: type = IO_SOCK_STREAM; break;
796  case SOCK_DGRAM: type = IO_SOCK_DGRAM; break;
797  default: continue;
798  }
799 
800  if (ninfo++ < maxinfo) {
801  memset(info, 0, sizeof(*info));
802  info->domain = domain;
803  info->type = type;
804  info->addr.addrlen = ai->ai_addrlen;
805  memcpy(&info->addr.addr, ai->ai_addr, ai->ai_addrlen);
806  info++;
807  }
808  }
809 
810  freeaddrinfo(res);
811 
812  return ninfo;
813 }
814 
815 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
816 
817 #ifdef _WIN32
818 
819 static int
820 ba2str(const BTH_ADDR *ba, char *str)
821 {
822  return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
823  (int)((*ba >> 40) & 0xff), (int)((*ba >> 32) & 0xff),
824  (int)((*ba >> 24) & 0xff), (int)((*ba >> 16) & 0xff),
825  ((int)(*ba >> 8) & 0xff), (int)(*ba & 0xff));
826 }
827 
828 static int
829 str2ba(const char *str, BTH_ADDR *ba)
830 {
831  if (bachk(str) < 0) {
832  *ba = 0;
833  return -1;
834  }
835 
836  for (int i = 5; i >= 0; i--, str += 3)
837  *ba |= (BTH_ADDR)strtol(str, NULL, 16) << (i * 8);
838 
839  return 0;
840 }
841 
842 static int
843 bachk(const char *str)
844 {
845  assert(str);
846 
847  if (strlen(str) != 17)
848  return -1;
849 
850  while (*str) {
851  if (!isxdigit(*str++))
852  return -1;
853  if (!isxdigit(*str++))
854  return -1;
855  if (!*str)
856  break;
857  if (*str++ != ':')
858  return -1;
859  }
860 
861  return 0;
862 }
863 
864 #endif // _WIN32
io_addr_cmp
int io_addr_cmp(const void *p1, const void *p2)
Compares two network addresses.
Definition: addr.c:48
io_addr_set_ipv4_n
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
ERRNUM_AI_NONAME
@ ERRNUM_AI_NONAME
The name does not resolve for the supplied parameters.
Definition: errnum.h:250
cmp.h
io_addr_get_rfcomm_a
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
io_addr_get_domain
int io_addr_get_domain(const io_addr_t *addr)
Obtains the domain of a network address.
Definition: addr.c:527
io_addr_set_ipv4_broadcast
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
io_addrinfo::type
int type
The type of the socket (either IO_SOCK_STREAM or IO_SOCK_DGRAM).
Definition: addr.h:83
io_addr_is_multicast
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:711
io_addr_set_ipv4_loopback
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
string.h
IO_SOCK_UNIX
@ IO_SOCK_UNIX
A UNIX domain socket (only supported on POSIX platforms).
Definition: sock.h:35
io_addr_set_rfcomm_a
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
MIN
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
__io_addr
An opaque network address type.
Definition: addr.h:30
ERRNUM_AI_FAMILY
@ ERRNUM_AI_FAMILY
The address family was not recognized or the address length was invalid for the specified family.
Definition: errnum.h:246
ERRNUM_AFNOSUPPORT
@ ERRNUM_AFNOSUPPORT
Address family not supported.
Definition: errnum.h:84
io_addr_get_port
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:548
io_addr_set_ipv6_n
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:448
io_addrinfo::domain
int domain
The domain of the socket (only IO_SOCK_IPV4 and IO_SOCK_IPV6 are supported).
Definition: addr.h:81
io_addrinfo::addr
io_addr_t addr
The network address.
Definition: addr.h:85
IO_SOCK_BTH
@ IO_SOCK_BTH
A Bluetooth socket.
Definition: sock.h:29
ERRNUM_AI_SERVICE
@ ERRNUM_AI_SERVICE
The service passed was not recognized for the specified socket type.
Definition: errnum.h:254
io_get_addrinfo
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:738
set_errnum
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
io_addr_set_port
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:614
io.h
io_addr_get_ipv4_a
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
io_addr_is_broadcast
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:691
IO_ADDR_UNIX_STRLEN
#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
io_addr_set_rfcomm_local
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
ERRNUM_AI_MEMORY
@ ERRNUM_AI_MEMORY
There was a memory allocation failure.
Definition: errnum.h:248
addr.h
errnum.h
ERRNUM_INVAL
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
stdio.h
io_addr_get_unix
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:483
__io_addr::addr
union __io_addr::@5 addr
The network address.
ERRNUM_AI_FAIL
@ ERRNUM_AI_FAIL
A non-recoverable error occurred.
Definition: errnum.h:241
io_addrinfo
A network address info structure.
Definition: addr.h:76
io_addr_set_ipv6_a
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
io_addr_get_ipv4_n
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
io_addr_set_unix
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:506
IO_ADDR_IPV4_STRLEN
#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
io_addr_set_rfcomm_n
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
ERRNUM_AI_AGAIN
@ ERRNUM_AI_AGAIN
The name could not be resolved at this time.
Definition: errnum.h:237
io_addr_set_ipv6_loopback
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:465
io_addr_set_ipv4_a
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
__io_addr::addrlen
int addrlen
The size (in bytes) of addr.
Definition: addr.h:32
ERRNUM_AI_SOCKTYPE
@ ERRNUM_AI_SOCKTYPE
The intended socket type was not recognized.
Definition: errnum.h:256
io_addr_get_rfcomm_n
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
IO_SOCK_DGRAM
@ IO_SOCK_DGRAM
A datagram-oriented, typically connectionless-mode, socket type.
Definition: sock.h:48
io_addr_is_loopback
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:663
stdlib.h
IO_SOCK_IPV6
@ IO_SOCK_IPV6
An IPv6 socket.
Definition: sock.h:33
ERRNUM_AI_BADFLAGS
@ ERRNUM_AI_BADFLAGS
The flags had an invalid value.
Definition: errnum.h:239
IO_SOCK_IPV4
@ IO_SOCK_IPV4
An IPv4 socket.
Definition: sock.h:31
IO_ADDR_IPV6_STRLEN
#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
io_addr_get_ipv6_a
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
sock.h
IO_SOCK_STREAM
@ IO_SOCK_STREAM
A stream-oriented connection-mode socket type.
Definition: sock.h:43
io_addr_get_ipv6_n
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:423