summaryrefslogtreecommitdiff
path: root/toxcore/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/network.c')
-rw-r--r--toxcore/network.c692
1 files changed, 668 insertions, 24 deletions
diff --git a/toxcore/network.c b/toxcore/network.c
index c6c4965e..4b6dc3be 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -26,6 +26,7 @@
26#endif 26#endif
27 27
28#include "network.h" 28#include "network.h"
29#include "util.h"
29 30
30/* return current UNIX time in microseconds (us). */ 31/* return current UNIX time in microseconds (us). */
31uint64_t current_time(void) 32uint64_t current_time(void)
@@ -62,17 +63,83 @@ uint32_t random_int(void)
62#endif 63#endif
63} 64}
64 65
66#ifdef LOGGING
67static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res);
68#endif
69
65/* Basic network functions: 70/* Basic network functions:
66 * Function to send packet(data) of length length to ip_port. 71 * Function to send packet(data) of length length to ip_port.
67 */ 72 */
68#ifdef WIN32 73int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length)
69int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length) 74{
75#ifdef TOX_ENABLE_IPV6
76
77 /* socket AF_INET, but target IP NOT: can't send */
78 if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET))
79 return -1;
80
81#endif
82
83 struct sockaddr_storage addr;
84 size_t addrsize = 0;
85
86#ifdef TOX_ENABLE_IPV6
87
88 if (ip_port.ip.family == AF_INET) {
89 if (net->family == AF_INET6) {
90 /* must convert to IPV4-in-IPV6 address */
91 addrsize = sizeof(struct sockaddr_in6);
92 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
93 addr6->sin6_family = AF_INET6;
94 addr6->sin6_port = ip_port.port;
95
96 /* there should be a macro for this in a standards compliant
97 * environment, not found */
98 IP6 ip6;
99
100 ip6.uint32[0] = 0;
101 ip6.uint32[1] = 0;
102 ip6.uint32[2] = htonl(0xFFFF);
103 ip6.uint32[3] = ip_port.ip.ip4.uint32;
104 addr6->sin6_addr = ip6.in6_addr;
105
106 addr6->sin6_flowinfo = 0;
107 addr6->sin6_scope_id = 0;
108 } else {
109 IP4 ip4 = ip_port.ip.ip4;
70#else 110#else
71int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length) 111 IP4 ip4 = ip_port.ip;
72#endif 112#endif
73{ 113 addrsize = sizeof(struct sockaddr_in);
74 ADDR addr = {AF_INET, ip_port.port, ip_port.ip, {0}}; 114 struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
75 return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr)); 115 addr4->sin_family = AF_INET;
116 addr4->sin_addr = ip4.in_addr;
117 addr4->sin_port = ip_port.port;
118#ifdef TOX_ENABLE_IPV6
119 }
120 } else if (ip_port.ip.family == AF_INET6)
121 {
122 addrsize = sizeof(struct sockaddr_in6);
123 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
124 addr6->sin6_family = AF_INET6;
125 addr6->sin6_port = ip_port.port;
126 addr6->sin6_addr = ip_port.ip.ip6.in6_addr;
127
128 addr6->sin6_flowinfo = 0;
129 addr6->sin6_scope_id = 0;
130 } else
131 {
132 /* unknown address type*/
133 return -1;
134 }
135
136#endif
137
138 int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
139#ifdef LOGGING
140 loglogdata("O=>", data, length, &ip_port, res);
141#endif
142 return res;
76} 143}
77 144
78/* Function to receive data 145/* Function to receive data
@@ -81,13 +148,9 @@ int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length)
81 * Packet length is put into length. 148 * Packet length is put into length.
82 * Dump all empty packets. 149 * Dump all empty packets.
83 */ 150 */
84#ifdef WIN32 151static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
85static int receivepacket(unsigned int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
86#else
87static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
88#endif
89{ 152{
90 ADDR addr; 153 struct sockaddr_storage addr;
91#ifdef WIN32 154#ifdef WIN32
92 int addrlen = sizeof(addr); 155 int addrlen = sizeof(addr);
93#else 156#else
@@ -95,11 +158,48 @@ static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *le
95#endif 158#endif
96 (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); 159 (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
97 160
98 if (*(int32_t *)length <= 0) 161 if (*(int32_t *)length <= 0) {
162#ifdef LOGGING
163
164 if ((length < 0) && (errno != EWOULDBLOCK)) {
165 sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno));
166 loglog(logbuffer);
167 }
168
169#endif
99 return -1; /* Nothing received or empty packet. */ 170 return -1; /* Nothing received or empty packet. */
171 }
172
173#ifdef TOX_ENABLE_IPV6
174
175 if (addr.ss_family == AF_INET) {
176 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
177 ip_port->ip.family = addr_in->sin_family;
178 ip_port->ip.ip4.in_addr = addr_in->sin_addr;
179 ip_port->port = addr_in->sin_port;
180 } else if (addr.ss_family == AF_INET6) {
181 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr;
182 ip_port->ip.family = addr_in6->sin6_family;
183 ip_port->ip.ip6.in6_addr = addr_in6->sin6_addr;
184 ip_port->port = addr_in6->sin6_port;
185 } else
186 return -1;
187
188#else
189
190 if (addr.ss_family == AF_INET) {
191 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
192 ip_port->ip.in_addr = addr_in->sin_addr;
193 ip_port->port = addr_in->sin_port;
194 } else
195 return -1;
196
197#endif
198
199#ifdef LOGGING
200 loglogdata("=>O", data, MAX_UDP_PACKET_SIZE, ip_port, *length);
201#endif
100 202
101 ip_port->ip = addr.ip;
102 ip_port->port = addr.port;
103 return 0; 203 return 0;
104} 204}
105 205
@@ -118,13 +218,20 @@ void networking_poll(Networking_Core *net)
118 while (receivepacket(net->sock, &ip_port, data, &length) != -1) { 218 while (receivepacket(net->sock, &ip_port, data, &length) != -1) {
119 if (length < 1) continue; 219 if (length < 1) continue;
120 220
121 if (!(net->packethandlers[data[0]].function)) continue; 221 if (!(net->packethandlers[data[0]].function)) {
222#ifdef LOGGING
223 sprintf(logbuffer, "[%02u] -- Packet has no handler.\n", data[0]);
224 loglog(logbuffer);
225#endif
226 continue;
227 }
122 228
123 net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length); 229 net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length);
124 } 230 }
125} 231}
126 232
127uint8_t at_startup_ran; 233
234uint8_t at_startup_ran = 0;
128static int at_startup(void) 235static int at_startup(void)
129{ 236{
130 if (at_startup_ran != 0) 237 if (at_startup_ran != 0)
@@ -163,16 +270,34 @@ static void at_shutdown(void)
163 */ 270 */
164Networking_Core *new_networking(IP ip, uint16_t port) 271Networking_Core *new_networking(IP ip, uint16_t port)
165{ 272{
273#ifdef TOX_ENABLE_IPV6
274
275 /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */
276 if (ip.family != AF_INET && ip.family != AF_INET6) {
277 fprintf(stderr, "Invalid address family: %u\n", ip.family);
278 return NULL;
279 }
280
281#endif
282
166 if (at_startup() != 0) 283 if (at_startup() != 0)
167 return NULL; 284 return NULL;
168 285
169 /* Initialize our socket. */
170 Networking_Core *temp = calloc(1, sizeof(Networking_Core)); 286 Networking_Core *temp = calloc(1, sizeof(Networking_Core));
171 287
172 if (temp == NULL) 288 if (temp == NULL)
173 return NULL; 289 return NULL;
174 290
175 temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 291#ifdef TOX_ENABLE_IPV6
292 temp->family = ip.family;
293#else
294 temp->family = AF_INET;
295#endif
296 temp->port = 0;
297
298 /* Initialize our socket. */
299 /* add log message what we're creating */
300 temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP);
176 301
177 /* Check for socket error. */ 302 /* Check for socket error. */
178#ifdef WIN32 303#ifdef WIN32
@@ -185,6 +310,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
185#else 310#else
186 311
187 if (temp->sock < 0) { 312 if (temp->sock < 0) {
313 fprintf(stderr, "Failed to get a socket?! %u, %s\n", errno, strerror(errno));
188 free(temp); 314 free(temp);
189 return NULL; 315 return NULL;
190 } 316 }
@@ -205,7 +331,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
205 return -1; 331 return -1;
206 */ 332 */
207 333
208 /* Enable broadcast on socket. */ 334 /* Enable broadcast on socket */
209 int broadcast = 1; 335 int broadcast = 1;
210 setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); 336 setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));
211 337
@@ -219,10 +345,140 @@ Networking_Core *new_networking(IP ip, uint16_t port)
219 fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); 345 fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1);
220#endif 346#endif
221 347
222 /* Bind our socket to port PORT and address 0.0.0.0 */ 348#ifdef LOGGING
223 ADDR addr = {AF_INET, htons(port), ip, {0}}; 349 loginit(ntohs(port));
224 bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr)); 350#endif
225 return temp; 351
352 /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
353 uint16_t *portptr = NULL;
354 struct sockaddr_storage addr;
355 size_t addrsize;
356#ifdef TOX_ENABLE_IPV6
357
358 if (temp->family == AF_INET) {
359 IP4 ip4 = ip.ip4;
360#else
361 IP4 ip4 = ip;
362#endif
363 addrsize = sizeof(struct sockaddr_in);
364 struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
365 addr4->sin_family = AF_INET;
366 addr4->sin_port = 0;
367 addr4->sin_addr = ip4.in_addr;
368
369 portptr = &addr4->sin_port;
370#ifdef TOX_ENABLE_IPV6
371 } else if (temp->family == AF_INET6)
372 {
373 addrsize = sizeof(struct sockaddr_in6);
374 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
375 addr6->sin6_family = AF_INET6;
376 addr6->sin6_port = 0;
377 addr6->sin6_addr = ip.ip6.in6_addr;
378
379 addr6->sin6_flowinfo = 0;
380 addr6->sin6_scope_id = 0;
381
382 portptr = &addr6->sin6_port;
383 } else
384 return NULL;
385
386 if (ip.family == AF_INET6)
387 {
388 char ipv6only = 0;
389#ifdef LOGGING
390 int res =
391#endif
392 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only));
393#ifdef LOGGING
394
395 if (res < 0) {
396 sprintf(logbuffer,
397 "Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n",
398 errno, strerror(errno));
399 loglog(logbuffer);
400 } else
401 loglog("Embedded IPv4 addresses enabled successfully.\n");
402
403#endif
404
405 /* multicast local nodes */
406 struct ipv6_mreq mreq;
407 memset(&mreq, 0, sizeof(mreq));
408 mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF;
409 mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;
410 mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
411 mreq.ipv6mr_interface = 0;
412#ifdef LOGGING
413 res =
414#endif
415 setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
416#ifdef LOGGING
417
418 if (res < 0) {
419 sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
420 errno, strerror(errno));
421 loglog(logbuffer);
422 } else
423 loglog("Local multicast group FF02::1 joined successfully.\n");
424
425#endif
426 }
427
428#endif
429
430 /* a hanging program or a different user might block the standard port;
431 * as long as it isn't a parameter coming from the commandline,
432 * try a few ports after it, to see if we can find a "free" one
433 *
434 * if we go on without binding, the first sendto() automatically binds to
435 * a free port chosen by the system (i.e. anything from 1024 to 65535)
436 *
437 * returning NULL after bind fails has both advantages and disadvantages:
438 * advantage:
439 * we can rely on getting the port in the range 33445..33450, which
440 * enables us to tell joe user to open their firewall to a small range
441 *
442 * disadvantage:
443 * some clients might not test return of tox_new(), blindly assuming that
444 * it worked ok (which it did previously without a successful bind)
445 */
446 uint16_t port_to_try = port;
447 *portptr = htons(port_to_try);
448 int tries, res;
449
450 for (tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++)
451 {
452 res = bind(temp->sock, (struct sockaddr *)&addr, addrsize);
453
454 if (!res) {
455 temp->port = *portptr;
456#ifdef LOGGING
457 sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
458 loglog(logbuffer);
459#endif
460
461 /* errno isn't reset on success, only set on failure, the failed
462 * binds with parallel clients yield a -EPERM to the outside if
463 * errno isn't cleared here */
464 if (tries > 0)
465 errno = 0;
466
467 return temp;
468 }
469
470 port_to_try++;
471
472 if (port_to_try > TOX_PORTRANGE_TO)
473 port_to_try = TOX_PORTRANGE_FROM;
474
475 *portptr = htons(port_to_try);
476 }
477
478 fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno,
479 strerror(errno), ip_ntoa(&ip), port);
480 kill_networking(temp);
481 return NULL;
226} 482}
227 483
228/* Function to cleanup networking stuff. */ 484/* Function to cleanup networking stuff. */
@@ -236,3 +492,391 @@ void kill_networking(Networking_Core *net)
236 free(net); 492 free(net);
237 return; 493 return;
238} 494}
495
496/* ip_equal
497 * compares two IPAny structures
498 * unset means unequal
499 *
500 * returns 0 when not equal or when uninitialized
501 */
502int ip_equal(IP *a, IP *b)
503{
504 if (!a || !b)
505 return 0;
506
507#ifdef TOX_ENABLE_IPV6
508
509 /* same family */
510 if (a->family == b->family) {
511 if (a->family == AF_INET)
512 return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr);
513 else if (a->family == AF_INET6)
514 return IN6_ARE_ADDR_EQUAL(&a->ip6.in6_addr, &b->ip6.in6_addr);
515 else
516 return 0;
517 }
518
519 /* different family: check on the IPv6 one if it is the IPv4 one embedded */
520 if ((a->family == AF_INET) && (b->family == AF_INET6)) {
521 if (IN6_IS_ADDR_V4MAPPED(&b->ip6.in6_addr))
522 return (a->ip4.in_addr.s_addr == b->ip6.uint32[3]);
523 } else if ((a->family == AF_INET6) && (b->family == AF_INET)) {
524 if (IN6_IS_ADDR_V4MAPPED(&a->ip6.in6_addr))
525 return (a->ip6.uint32[3] == b->ip4.in_addr.s_addr);
526 }
527
528 return 0;
529#else
530 return (a->uint32 == b->uint32);
531#endif
532};
533
534/* ipport_equal
535 * compares two IPAny_Port structures
536 * unset means unequal
537 *
538 * returns 0 when not equal or when uninitialized
539 */
540int ipport_equal(IP_Port *a, IP_Port *b)
541{
542 if (!a || !b)
543 return 0;
544
545 if (!a->port || (a->port != b->port))
546 return 0;
547
548 return ip_equal(&a->ip, &b->ip);
549};
550
551/* nulls out ip */
552void ip_reset(IP *ip)
553{
554 if (!ip)
555 return;
556
557#ifdef TOX_ENABLE_IPV6
558 memset(ip, 0, sizeof(IP));
559#else
560 ip->uint32 = 0;
561#endif
562};
563
564/* nulls out ip, sets family according to flag */
565void ip_init(IP *ip, uint8_t ipv6enabled)
566{
567 if (!ip)
568 return;
569
570#ifdef TOX_ENABLE_IPV6
571 memset(ip, 0, sizeof(IP));
572 ip->family = ipv6enabled ? AF_INET6 : AF_INET;
573#else
574 ip->uint32 = 0;
575#endif
576};
577
578/* checks if ip is valid */
579int ip_isset(IP *ip)
580{
581 if (!ip)
582 return 0;
583
584#ifdef TOX_ENABLE_IPV6
585 return (ip->family != 0);
586#else
587 return (ip->uint32 != 0);
588#endif
589};
590
591/* checks if ip is valid */
592int ipport_isset(IP_Port *ipport)
593{
594 if (!ipport)
595 return 0;
596
597 if (!ipport->port)
598 return 0;
599
600 return ip_isset(&ipport->ip);
601};
602
603/* copies an ip structure (careful about direction!) */
604void ip_copy(IP *target, IP *source)
605{
606 if (!source || !target)
607 return;
608
609 memcpy(target, source, sizeof(IP));
610};
611
612/* copies an ip_port structure (careful about direction!) */
613void ipport_copy(IP_Port *target, IP_Port *source)
614{
615 if (!source || !target)
616 return;
617
618 memcpy(target, source, sizeof(IP_Port));
619};
620
621/* ip_ntoa
622 * converts ip into a string
623 * uses a static buffer, so mustn't used multiple times in the same output
624 */
625/* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */
626static char addresstext[96];
627const char *ip_ntoa(IP *ip)
628{
629 if (ip) {
630#ifdef TOX_ENABLE_IPV6
631
632 if (ip->family == AF_INET) {
633 addresstext[0] = 0;
634 struct in_addr *addr = (struct in_addr *)&ip->ip4;
635 inet_ntop(ip->family, addr, addresstext, sizeof(addresstext));
636 } else if (ip->family == AF_INET6) {
637 addresstext[0] = '[';
638 struct in6_addr *addr = (struct in6_addr *)&ip->ip6;
639 inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3);
640 size_t len = strlen(addresstext);
641 addresstext[len] = ']';
642 addresstext[len + 1] = 0;
643 } else
644 snprintf(addresstext, sizeof(addresstext), "(IP invalid, family %u)", ip->family);
645
646#else
647 addresstext[0] = 0;
648 struct in_addr *addr = (struct in_addr *)&ip;
649 inet_ntop(AF_INET, addr, addresstext, sizeof(addresstext));
650#endif
651 } else
652 snprintf(addresstext, sizeof(addresstext), "(IP invalid: NULL)");
653
654 /* brute force protection against lacking termination */
655 addresstext[sizeof(addresstext) - 1] = 0;
656 return addresstext;
657};
658
659/*
660 * addr_parse_ip
661 * directly parses the input into an IP structure
662 * tries IPv4 first, then IPv6
663 *
664 * input
665 * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)
666 *
667 * output
668 * IP: family and the value is set on success
669 *
670 * returns 1 on success, 0 on failure
671 */
672
673int addr_parse_ip(const char *address, IP *to)
674{
675 if (!address || !to)
676 return 0;
677
678#ifdef TOX_ENABLE_IPV6
679 struct in_addr addr4;
680
681 if (1 == inet_pton(AF_INET, address, &addr4)) {
682 to->family = AF_INET;
683 to->ip4.in_addr = addr4;
684 return 1;
685 };
686
687 struct in6_addr addr6;
688
689 if (1 == inet_pton(AF_INET6, address, &addr6)) {
690 to->family = AF_INET6;
691 to->ip6.in6_addr = addr6;
692 return 1;
693 };
694
695#else
696 struct in_addr addr4;
697
698 if (1 == inet_pton(AF_INET, address, &addr4)) {
699 to->in_addr = addr4;
700 return 1;
701 };
702
703#endif
704
705 return 0;
706};
707
708/*
709 * addr_resolve():
710 * uses getaddrinfo to resolve an address into an IP address
711 * uses the first IPv4/IPv6 addresses returned by getaddrinfo
712 *
713 * input
714 * address: a hostname (or something parseable to an IP address)
715 * to: to.family MUST be initialized, either set to a specific IP version
716 * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
717 * IP versions are acceptable
718 * extra can be NULL and is only set in special circumstances, see returns
719 *
720 * returns in *to a valid IPAny (v4/v6),
721 * prefers v6 if ip.family was AF_UNSPEC and both available
722 * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6
723 * returns 0 on failure
724 */
725
726int addr_resolve(const char *address, IP *to, IP *extra)
727{
728 if (!address || !to)
729 return 0;
730
731 sa_family_t family;
732#ifdef TOX_ENABLE_IPV6
733 family = to->family;
734#else
735 family = AF_INET;
736#endif
737
738 struct addrinfo *server = NULL;
739 struct addrinfo *walker = NULL;
740 struct addrinfo hints;
741 int rc;
742
743 memset(&hints, 0, sizeof(hints));
744 hints.ai_family = family;
745 hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
746
747 if (at_startup() != 0)
748 return 0;
749
750 rc = getaddrinfo(address, NULL, &hints, &server);
751
752 // Lookup failed.
753 if (rc != 0) {
754 return 0;
755 }
756
757#ifdef TOX_ENABLE_IPV6
758 IP4 ip4;
759 memset(&ip4, 0, sizeof(ip4));
760 IP6 ip6;
761 memset(&ip6, 0, sizeof(ip6));
762#endif
763
764 for (walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) {
765 switch (walker->ai_family) {
766 case AF_INET:
767 if (walker->ai_family == family) { /* AF_INET requested, done */
768 struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
769#ifdef TOX_ENABLE_IPV6
770 to->ip4.in_addr = addr->sin_addr;
771#else
772 to->in_addr = addr->sin_addr;
773#endif
774 rc = 3;
775 }
776
777#ifdef TOX_ENABLE_IPV6
778 else if (!(rc & 1)) { /* AF_UNSPEC requested, store away */
779 struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
780 ip4.in_addr = addr->sin_addr;
781 rc |= 1;
782 }
783
784#endif
785 break; /* switch */
786#ifdef TOX_ENABLE_IPV6
787
788 case AF_INET6:
789 if (walker->ai_family == family) { /* AF_INET6 requested, done */
790 if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
791 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
792 to->ip6.in6_addr = addr->sin6_addr;
793 rc = 3;
794 }
795 } else if (!(rc & 2)) { /* AF_UNSPEC requested, store away */
796 if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
797 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
798 ip6.in6_addr = addr->sin6_addr;
799 rc |= 2;
800 }
801 }
802
803 break; /* switch */
804#endif
805 }
806 }
807
808#ifdef TOX_ENABLE_IPV6
809
810 if (to->family == AF_UNSPEC) {
811 if (rc & 2) {
812 to->family = AF_INET6;
813 to->ip6 = ip6;
814
815 if ((rc & 1) && (extra != NULL)) {
816 extra->family = AF_INET;
817 extra->ip4 = ip4;
818 }
819 } else if (rc & 1) {
820 to->family = AF_INET;
821 to->ip4 = ip4;
822 } else
823 rc = 0;
824 }
825
826#endif
827
828
829 freeaddrinfo(server);
830 return rc;
831}
832
833/*
834 * addr_resolve_or_parse_ip
835 * resolves string into an IP address
836 *
837 * address: a hostname (or something parseable to an IP address)
838 * to: to.family MUST be initialized, either set to a specific IP version
839 * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
840 * IP versions are acceptable
841 * extra can be NULL and is only set in special circumstances, see returns
842 *
843 * returns in *tro a matching address (IPv6 or IPv4)
844 * returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC
845 * returns 1 on success
846 * returns 0 on failure
847 */
848int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra)
849{
850 if (!addr_resolve(address, to, extra))
851 if (!addr_parse_ip(address, to))
852 return 0;
853
854 return 1;
855};
856
857#ifdef LOGGING
858static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res)
859{
860 if (res < 0)
861 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
862 buffer[0], message, buflen < 999 ? buflen : 999, 'E',
863 ip_ntoa(&ip_port->ip), ntohs(ip_port->port), errno,
864 strerror(errno), buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
865 buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
866 else if ((res > 0) && (res <= buflen))
867 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x\n",
868 buffer[0], message, res < 999 ? res : 999, res < buflen ? '<' : '=',
869 ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
870 "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
871 buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
872 else /* empty or overwrite */
873 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %s %u%c%u %s:%u (%u: %s) | %04x%04x\n",
874 buffer[0], message, res, !res ? '0' : '>', buflen,
875 ip_ntoa(&ip_port->ip), ntohs(ip_port->port), 0,
876 "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
877 buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
878
879 logbuffer[sizeof(logbuffer) - 1] = 0;
880 loglog(logbuffer);
881}
882#endif