Lely core libraries  2.3.4
addr.c
Go to the documentation of this file.
1 
24 #include "io.h"
25 
26 #if !LELY_NO_STDIO
27 
28 #include <lely/io/addr.h>
29 #include <lely/io/sock.h>
30 #include <lely/util/cmp.h>
31 #include <lely/util/errnum.h>
32 
33 #include <assert.h>
34 #include <string.h>
35 
36 #if _WIN32
37 
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 
42 static int ba2str(const BTH_ADDR *ba, char *str);
43 static int str2ba(const char *str, BTH_ADDR *ba);
44 static int bachk(const char *str);
45 
46 #elif _POSIX_C_SOURCE >= 200112L
47 #include <netdb.h>
48 #endif
49 
50 int
51 io_addr_cmp(const void *p1, const void *p2)
52 {
53  if (p1 == p2)
54  return 0;
55 
56  if (!p1)
57  return -1;
58  if (!p2)
59  return 1;
60 
61  const io_addr_t *a1 = p1;
62  const io_addr_t *a2 = p2;
63 
64  int cmp = memcmp(&a1->addr, &a2->addr, MIN(a1->addrlen, a2->addrlen));
65  if (!cmp)
66  cmp = (a2->addrlen < a1->addrlen) - (a1->addrlen < a2->addrlen);
67  return cmp;
68 }
69 
70 // clang-format off
71 #if _WIN32 || (defined(__linux__) \
72  && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
73  && defined(HAVE_BLUETOOTH_RFCOMM_H))
74 // clang-format on
75 
76 int
77 io_addr_get_rfcomm_a(const io_addr_t *addr, char *ba, int *port)
78 {
79  assert(addr);
80 
81 #if _WIN32
82  if (addr->addrlen < (int)sizeof(SOCKADDR_BTH)) {
83  WSASetLastError(WSAEINVAL);
84  return -1;
85  }
86 
87  const SOCKADDR_BTH *addr_bth = (const SOCKADDR_BTH *)&addr->addr;
88  if (addr_bth->addressFamily != AF_BTH) {
89  WSASetLastError(WSAEAFNOSUPPORT);
90  return -1;
91  }
92 
93  if (port)
94  *port = addr_bth->port == BT_PORT_ANY ? 0 : addr_bth->port;
95  if (ba && ba2str(&addr_bth->btAddr, ba) < 0)
96  return -1;
97 #else
98  if (addr->addrlen < (int)sizeof(struct sockaddr_rc)) {
99  errno = EINVAL;
100  return -1;
101  }
102 
103  const struct sockaddr_rc *addr_rc =
104  (const struct sockaddr_rc *)&addr->addr;
105  if (addr_rc->rc_family != AF_BLUETOOTH) {
106  errno = EAFNOSUPPORT;
107  return -1;
108  }
109 
110  if (port)
111  *port = btohs(addr_rc->rc_channel);
112  if (ba && ba2str(&addr_rc->rc_bdaddr, ba) < 0)
113  return -1;
114 #endif
115 
116  return 0;
117 }
118 
119 int
120 io_addr_set_rfcomm_a(io_addr_t *addr, const char *ba, int port)
121 {
122  assert(addr);
123 
124  memset(addr, 0, sizeof(*addr));
125 #if _WIN32
126  addr->addrlen = sizeof(SOCKADDR_BTH);
127  SOCKADDR_BTH *addr_bth = (SOCKADDR_BTH *)&addr->addr;
128 
129  addr_bth->addressFamily = AF_BTH;
130  addr_bth->port = port ? (ULONG)port : BT_PORT_ANY;
131  addr_bth->btAddr = 0;
132  if (ba && *ba) {
133  if (str2ba(ba, &addr_bth->btAddr) < 0)
134  return -1;
135  }
136 #else
137  addr->addrlen = sizeof(struct sockaddr_rc);
138  struct sockaddr_rc *addr_rc = (struct sockaddr_rc *)&addr->addr;
139 
140  addr_rc->rc_family = AF_BLUETOOTH;
141  addr_rc->rc_channel = htobs(port);
142  if (ba && *ba) {
143  if (str2ba(ba, &addr_rc->rc_bdaddr) < 0)
144  return -1;
145  } else {
146  bacpy(&addr_rc->rc_bdaddr, BDADDR_ANY);
147  }
148 #endif
149 
150  return 0;
151 }
152 
153 int
154 io_addr_get_rfcomm_n(const io_addr_t *addr, uint8_t ba[6], int *port)
155 {
156  assert(addr);
157 
158 #if _WIN32
159  if (addr->addrlen < (int)sizeof(SOCKADDR_BTH)) {
160  WSASetLastError(WSAEINVAL);
161  return -1;
162  }
163 
164  const SOCKADDR_BTH *addr_bth = (const SOCKADDR_BTH *)&addr->addr;
165  if (addr_bth->addressFamily != AF_BTH) {
166  WSASetLastError(WSAEAFNOSUPPORT);
167  return -1;
168  }
169 
170  if (port)
171  *port = addr_bth->port == BT_PORT_ANY ? 0 : addr_bth->port;
172  if (ba) {
173  for (int i = 0; i < 6; i++)
174  ba[i] = (addr_bth->btAddr >> (7 - i) * 8) & 0xff;
175  }
176 #else
177  if (addr->addrlen < (int)sizeof(struct sockaddr_rc)) {
178  errno = EINVAL;
179  return -1;
180  }
181 
182  const struct sockaddr_rc *addr_rc =
183  (const struct sockaddr_rc *)&addr->addr;
184  if (addr_rc->rc_family != AF_BLUETOOTH) {
185  errno = EAFNOSUPPORT;
186  return -1;
187  }
188 
189  if (port)
190  *port = btohs(addr_rc->rc_channel);
191  if (ba)
192  memcpy(ba, &addr_rc->rc_bdaddr, 6);
193 #endif
194 
195  return 0;
196 }
197 
198 void
199 io_addr_set_rfcomm_n(io_addr_t *addr, const uint8_t ba[6], int port)
200 {
201  assert(addr);
202 
203  memset(addr, 0, sizeof(*addr));
204 #if _WIN32
205  addr->addrlen = sizeof(SOCKADDR_BTH);
206  SOCKADDR_BTH *addr_bth = (SOCKADDR_BTH *)&addr->addr;
207 
208  addr_bth->addressFamily = AF_BTH;
209  addr_bth->port = port ? (ULONG)port : BT_PORT_ANY;
210  addr_bth->btAddr = 0;
211  if (ba && *ba) {
212  for (int i = 0; i < 6; i++)
213  addr_bth->btAddr |= (BTH_ADDR)ba[i] << (7 - i) * 8;
214  }
215 #else
216  addr->addrlen = sizeof(struct sockaddr_rc);
217  struct sockaddr_rc *addr_rc = (struct sockaddr_rc *)&addr->addr;
218 
219  addr_rc->rc_family = AF_BLUETOOTH;
220  addr_rc->rc_channel = htobs(port);
221  if (ba && *ba)
222  memcpy(&addr_rc->rc_bdaddr, ba, 6);
223  else
224  bacpy(&addr_rc->rc_bdaddr, BDADDR_ANY);
225 #endif
226 }
227 
228 void
230 {
231  assert(addr);
232 
233  memset(addr, 0, sizeof(*addr));
234 #if _WIN32
235  addr->addrlen = sizeof(SOCKADDR_BTH);
236  SOCKADDR_BTH *addr_bth = (SOCKADDR_BTH *)&addr->addr;
237 
238  addr_bth->addressFamily = AF_BTH;
239  addr_bth->port = port ? (ULONG)port : BT_PORT_ANY;
240  addr_bth->btAddr = (BTH_ADDR)0xffffff000000ull;
241 #else
242  addr->addrlen = sizeof(struct sockaddr_rc);
243  struct sockaddr_rc *addr_rc = (struct sockaddr_rc *)&addr->addr;
244 
245  addr_rc->rc_family = AF_BLUETOOTH;
246  addr_rc->rc_channel = htobs(port);
247  bacpy(&addr_rc->rc_bdaddr, BDADDR_LOCAL);
248 #endif
249 }
250 
251 // clang-format off
252 #endif // _WIN32 || (__linux__ && HAVE_BLUETOOTH_BLUETOOTH_H && HAVE_BLUETOOTH_RFCOMM_H)
253 // clang-format on
254 
255 #if _WIN32 || _POSIX_C_SOURCE >= 200112L
256 
257 int
258 io_addr_get_ipv4_a(const io_addr_t *addr, char *ip, int *port)
259 {
260  assert(addr);
261 
262  if (addr->addrlen < (int)sizeof(struct sockaddr_in)) {
264  return -1;
265  }
266 
267  const struct sockaddr_in *addr_in =
268  (const struct sockaddr_in *)&addr->addr;
269  if (addr_in->sin_family != AF_INET) {
271  return -1;
272  }
273 
274  if (port)
275  *port = ntohs(addr_in->sin_port);
276  // clang-format off
277  if (ip && !inet_ntop(AF_INET, (void *)&addr_in->sin_addr, ip,
279  // clang-format on
280  return -1;
281 
282  return 0;
283 }
284 
285 int
286 io_addr_set_ipv4_a(io_addr_t *addr, const char *ip, int port)
287 {
288  assert(addr);
289 
290  memset(addr, 0, sizeof(*addr));
291  addr->addrlen = sizeof(struct sockaddr_in);
292  struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
293 
294  addr_in->sin_family = AF_INET;
295  addr_in->sin_port = htons(port);
296  if (ip && *ip) {
297  if (inet_pton(AF_INET, ip, &addr_in->sin_addr) != 1)
298  return -1;
299  } else {
300  addr_in->sin_addr.s_addr = htonl(INADDR_ANY);
301  }
302 
303  return 0;
304 }
305 
306 int
307 io_addr_get_ipv4_n(const io_addr_t *addr, uint8_t ip[4], int *port)
308 {
309  assert(addr);
310 
311  if (addr->addrlen < (int)sizeof(struct sockaddr_in)) {
313  return -1;
314  }
315 
316  const struct sockaddr_in *addr_in =
317  (const struct sockaddr_in *)&addr->addr;
318  if (addr_in->sin_family != AF_INET) {
320  return -1;
321  }
322 
323  if (port)
324  *port = ntohs(addr_in->sin_port);
325  if (ip)
326  memcpy(ip, &addr_in->sin_addr.s_addr, 4);
327 
328  return 0;
329 }
330 
331 void
332 io_addr_set_ipv4_n(io_addr_t *addr, const uint8_t ip[4], int port)
333 {
334  assert(addr);
335 
336  memset(addr, 0, sizeof(*addr));
337  addr->addrlen = sizeof(struct sockaddr_in);
338  struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
339 
340  addr_in->sin_family = AF_INET;
341  addr_in->sin_port = htons(port);
342  if (ip)
343  memcpy(&addr_in->sin_addr.s_addr, ip, 4);
344  else
345  addr_in->sin_addr.s_addr = htonl(INADDR_ANY);
346 }
347 
348 void
350 {
351  assert(addr);
352 
353  memset(addr, 0, sizeof(*addr));
354  addr->addrlen = sizeof(struct sockaddr_in);
355  struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
356 
357  addr_in->sin_family = AF_INET;
358  addr_in->sin_port = htons(port);
359  addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
360 }
361 
362 void
364 {
365  assert(addr);
366 
367  memset(addr, 0, sizeof(*addr));
368  addr->addrlen = sizeof(struct sockaddr_in);
369  struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr->addr;
370 
371  addr_in->sin_family = AF_INET;
372  addr_in->sin_port = htons(port);
373  addr_in->sin_addr.s_addr = htonl(INADDR_BROADCAST);
374 }
375 
376 int
377 io_addr_get_ipv6_a(const io_addr_t *addr, char *ip, int *port)
378 {
379  assert(addr);
380 
381  if (addr->addrlen < (int)sizeof(struct sockaddr_in6)) {
383  return -1;
384  }
385 
386  const struct sockaddr_in6 *addr_in6 =
387  (const struct sockaddr_in6 *)&addr->addr;
388  if (addr_in6->sin6_family != AF_INET6) {
390  return -1;
391  }
392 
393  if (port)
394  *port = ntohs(addr_in6->sin6_port);
395  // clang-format off
396  if (ip && !inet_ntop(AF_INET6, (void *)&addr_in6->sin6_addr, ip,
398  // clang-format on
399  return -1;
400 
401  return 0;
402 }
403 
404 int
405 io_addr_set_ipv6_a(io_addr_t *addr, const char *ip, int port)
406 {
407  assert(addr);
408 
409  memset(addr, 0, sizeof(*addr));
410  addr->addrlen = sizeof(struct sockaddr_in6);
411  struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr->addr;
412 
413  addr_in6->sin6_family = AF_INET6;
414  addr_in6->sin6_port = htons(port);
415  if (ip && *ip) {
416  if (inet_pton(AF_INET6, ip, &addr_in6->sin6_addr) != 1)
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 (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 (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 (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 (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  memcpy(addr_un->sun_path, path, n);
522  addr_un->sun_path[n] = '\0';
523 }
524 
525 #endif // _POSIX_C_SOURCE >= 200112L
526 
527 #if _WIN32 || _POSIX_C_SOURCE >= 200112L
528 
529 int
531 {
532  assert(addr);
533 
534  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
535 #if _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 (addr->addrlen < (int)sizeof(sa_family_t)) {
557  return -1;
558  }
559 
560  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
561 #if _WIN32
562  case AF_BTH: {
563  if (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  if (addr->addrlen < (int)sizeof(struct sockaddr_rc)) {
580  errno = EINVAL;
581  return -1;
582  }
583  const struct sockaddr_rc *addr_rc =
584  (const struct sockaddr_rc *)&addr->addr;
585  if (port)
586  *port = btohs(addr_rc->rc_channel);
587  return 0;
588  }
589 #endif
590  case AF_INET: {
591  if (addr->addrlen < (int)sizeof(struct sockaddr_in)) {
593  return -1;
594  }
595  const struct sockaddr_in *addr_in =
596  (const struct sockaddr_in *)&addr->addr;
597  if (port)
598  *port = ntohs(addr_in->sin_port);
599  return 0;
600  }
601  case AF_INET6: {
602  if (addr->addrlen < (int)sizeof(struct sockaddr_in6)) {
604  return -1;
605  }
606  const struct sockaddr_in6 *addr_in6 =
607  (const struct sockaddr_in6 *)&addr->addr;
608  if (port)
609  *port = ntohs(addr_in6->sin6_port);
610  return 0;
611  }
612  default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
613  }
614 }
615 
616 int
617 io_addr_set_port(io_addr_t *addr, int port)
618 {
619  assert(addr);
620 
621  if (addr->addrlen < (int)sizeof(sa_family_t)) {
623  return -1;
624  }
625 
626  switch (((struct sockaddr *)&addr->addr)->sa_family) {
627 #if _WIN32
628  case AF_BTH:
629  if (addr->addrlen < (int)sizeof(SOCKADDR_BTH)) {
630  WSASetLastError(WSAEINVAL);
631  return -1;
632  }
633  ((SOCKADDR_BTH *)&addr->addr)->port =
634  port ? (ULONG)port : BT_PORT_ANY;
635  ;
636  return 0;
637 #elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
638  && defined(HAVE_BLUETOOTH_RFCOMM_H)
639  case AF_BLUETOOTH:
640  if (addr->addrlen < (int)sizeof(struct sockaddr_rc)) {
641  errno = EINVAL;
642  return -1;
643  }
644  ((struct sockaddr_rc *)&addr->addr)->rc_channel = htobs(port);
645  return 0;
646 #endif
647  case AF_INET:
648  if (addr->addrlen < (int)sizeof(struct sockaddr_in)) {
650  return -1;
651  }
652  ((struct sockaddr_in *)&addr->addr)->sin_port = htons(port);
653  return 0;
654  case AF_INET6:
655  if (addr->addrlen < (int)sizeof(struct sockaddr_in6)) {
657  return -1;
658  }
659  ((struct sockaddr_in6 *)&addr->addr)->sin6_port = htons(port);
660  return 0;
661  default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
662  }
663 }
664 
665 int
667 {
668  assert(addr);
669 
670  if (addr->addrlen < (int)sizeof(sa_family_t))
671  return 0;
672 
673  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
674  case AF_INET: {
675  if (addr->addrlen < (int)sizeof(struct sockaddr_in))
676  return 0;
677  const struct sockaddr_in *addr_in =
678  (const struct sockaddr_in *)&addr->addr;
679  return ntohl(addr_in->sin_addr.s_addr) == INADDR_LOOPBACK;
680  }
681  case AF_INET6: {
682  if (addr->addrlen < (int)sizeof(struct sockaddr_in6))
683  return 0;
684  const struct sockaddr_in6 *addr_in6 =
685  (const struct sockaddr_in6 *)&addr->addr;
686  return !memcmp(&addr_in6->sin6_addr, &in6addr_any,
687  sizeof(in6addr_any));
688  }
689  default: return 0;
690  }
691 }
692 
693 int
695 {
696  assert(addr);
697 
698  if (addr->addrlen < (int)sizeof(sa_family_t))
699  return 0;
700 
701  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
702  case AF_INET: {
703  if (addr->addrlen < (int)sizeof(struct sockaddr_in))
704  return 0;
705  const struct sockaddr_in *addr_in =
706  (const struct sockaddr_in *)&addr->addr;
707  return ntohl(addr_in->sin_addr.s_addr) == INADDR_BROADCAST;
708  }
709  default: return 0;
710  }
711 }
712 
713 int
715 {
716  assert(addr);
717 
718  if (addr->addrlen < (int)sizeof(sa_family_t))
719  return 0;
720 
721  switch (((const struct sockaddr *)&addr->addr)->sa_family) {
722  case AF_INET: {
723  if (addr->addrlen < (int)sizeof(struct sockaddr_in))
724  return 0;
725  const struct sockaddr_in *addr_in =
726  (const struct sockaddr_in *)&addr->addr;
727  return (ntohl(addr_in->sin_addr.s_addr) >> 28) == 0xe;
728  }
729  case AF_INET6: {
730  if (addr->addrlen < (int)sizeof(struct sockaddr_in6))
731  return 0;
732  const struct sockaddr_in6 *addr_in6 =
733  (const struct sockaddr_in6 *)&addr->addr;
734  return addr_in6->sin6_addr.s6_addr[0] == 0xff;
735  }
736  default: return 0;
737  }
738 }
739 
740 int
741 io_get_addrinfo(int maxinfo, struct io_addrinfo *info, const char *nodename,
742  const char *servname, const struct io_addrinfo *hints)
743 {
744  if (!info)
745  maxinfo = 0;
746 
747  int ecode = 0;
748 
749  struct addrinfo ai_hints = { .ai_family = AF_UNSPEC };
750  if (hints) {
751  switch (hints->domain) {
752  case 0: break;
753  case IO_SOCK_IPV4: ai_hints.ai_family = AF_INET; break;
754  case IO_SOCK_IPV6: ai_hints.ai_family = AF_INET6; break;
755  default: ecode = EAI_FAMILY; break;
756  }
757 
758  switch (hints->type) {
759  case 0: break;
760  case IO_SOCK_STREAM: ai_hints.ai_socktype = SOCK_STREAM; break;
761  case IO_SOCK_DGRAM: ai_hints.ai_socktype = SOCK_DGRAM; break;
762  default: ecode = EAI_SOCKTYPE; break;
763  }
764  }
765 
766  struct addrinfo *res = NULL;
767  if (!ecode)
768  ecode = getaddrinfo(nodename, servname, &ai_hints, &res);
769  if (ecode) {
770  switch (ecode) {
771  case EAI_AGAIN: set_errnum(ERRNUM_AI_AGAIN); break;
772  case EAI_BADFLAGS: set_errnum(ERRNUM_AI_BADFLAGS); break;
773  case EAI_FAIL: set_errnum(ERRNUM_AI_FAIL); break;
774  case EAI_FAMILY: set_errnum(ERRNUM_AI_FAMILY); break;
775  case EAI_MEMORY: set_errnum(ERRNUM_AI_MEMORY); break;
776  case EAI_NONAME: set_errnum(ERRNUM_AI_NONAME); break;
777  case EAI_SERVICE: set_errnum(ERRNUM_AI_SERVICE); break;
778  case EAI_SOCKTYPE: set_errnum(ERRNUM_AI_SOCKTYPE); break;
779 #ifdef EAI_SYSTEM
780  case EAI_SYSTEM: break;
781 #endif
782  }
783  return -1;
784  }
785  assert(res);
786 
787  int ninfo = 0;
788  for (struct addrinfo *ai = res; ai; ai = ai->ai_next) {
789  int domain;
790  switch (ai->ai_family) {
791  case AF_INET: domain = IO_SOCK_IPV4; break;
792  case AF_INET6: domain = IO_SOCK_IPV6; break;
793  default: continue;
794  }
795 
796  int type;
797  switch (ai->ai_socktype) {
798  case SOCK_STREAM: type = IO_SOCK_STREAM; break;
799  case SOCK_DGRAM: type = IO_SOCK_DGRAM; break;
800  default: continue;
801  }
802 
803  if (ninfo++ < maxinfo) {
804  memset(info, 0, sizeof(*info));
805  info->domain = domain;
806  info->type = type;
807  info->addr.addrlen = ai->ai_addrlen;
808  memcpy(&info->addr.addr, ai->ai_addr, ai->ai_addrlen);
809  info++;
810  }
811  }
812 
813  freeaddrinfo(res);
814 
815  return ninfo;
816 }
817 
818 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
819 
820 #if _WIN32
821 
822 static int
823 ba2str(const BTH_ADDR *ba, char *str)
824 {
825  return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
826  (int)((*ba >> 40) & 0xff), (int)((*ba >> 32) & 0xff),
827  (int)((*ba >> 24) & 0xff), (int)((*ba >> 16) & 0xff),
828  ((int)(*ba >> 8) & 0xff), (int)(*ba & 0xff));
829 }
830 
831 static int
832 str2ba(const char *str, BTH_ADDR *ba)
833 {
834  if (bachk(str) < 0) {
835  *ba = 0;
836  return -1;
837  }
838 
839  for (int i = 5; i >= 0; i--, str += 3)
840  *ba |= (BTH_ADDR)strtol(str, NULL, 16) << (i * 8);
841 
842  return 0;
843 }
844 
845 static int
846 bachk(const char *str)
847 {
848  assert(str);
849 
850  if (strlen(str) != 17)
851  return -1;
852 
853  while (*str) {
854  if (!isxdigit(*str++))
855  return -1;
856  if (!isxdigit(*str++))
857  return -1;
858  if (!*str)
859  break;
860  if (*str++ != ':')
861  return -1;
862  }
863 
864  return 0;
865 }
866 
867 #endif // _WIN32
868 
869 #endif // !LELY_NO_STDIO
io_addr_cmp
int io_addr_cmp(const void *p1, const void *p2)
Compares two network addresses.
Definition: addr.c:51
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:332
ERRNUM_AI_NONAME
@ ERRNUM_AI_NONAME
The name does not resolve for the supplied parameters.
Definition: errnum.h:253
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:77
io_addr_get_domain
int io_addr_get_domain(const io_addr_t *addr)
Obtains the domain of a network address.
Definition: addr.c:530
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:363
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:714
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:349
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:120
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:249
ERRNUM_AFNOSUPPORT
@ ERRNUM_AFNOSUPPORT
Address family not supported.
Definition: errnum.h:87
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:551
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:451
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:257
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:741
set_errnum
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:424
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:617
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:258
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:694
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:229
ERRNUM_AI_MEMORY
@ ERRNUM_AI_MEMORY
There was a memory allocation failure.
Definition: errnum.h:251
addr.h
errnum.h
ERRNUM_INVAL
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:132
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:486
__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:244
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:405
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:307
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:509
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:199
ERRNUM_AI_AGAIN
@ ERRNUM_AI_AGAIN
The name could not be resolved at this time.
Definition: errnum.h:240
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:468
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:286
__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:259
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:154
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:666
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:242
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:377
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:426