/* Initialize networking. * Bind to ip and port. * ip must be in network order EX: 127.0.0.1 = (7F000001). * port is in host byte order (this means don't worry about it). * * return Networking_Core object if no problems * return NULL if there are problems. */ Networking_Core *new_networking(IP ip, uint16_t port) { #ifdef TOX_ENABLE_IPV6 /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */ if (ip.family != AF_INET && ip.family != AF_INET6) { #ifdef DEBUG fprintf(stderr, "Invalid address family: %u\n", ip.family); #endif return NULL; } #endif if (at_startup() != 0) return NULL; Networking_Core *temp = calloc(1, sizeof(Networking_Core)); if (temp == NULL) return NULL; #ifdef TOX_ENABLE_IPV6 temp->family = ip.family; #else temp->family = AF_INET; #endif temp->port = 0; /* Initialize our socket. */ /* add log message what we're creating */ temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP); /* Check for socket error. */ #ifdef WIN32 if (temp->sock == INVALID_SOCKET) { /* MSDN recommends this. */ free(temp); return NULL; } #else if (temp->sock < 0) { #ifdef DEBUG fprintf(stderr, "Failed to get a socket?! %u, %s\n", errno, strerror(errno)); #endif free(temp); return NULL; } #endif /* Functions to increase the size of the send and receive UDP buffers. */ int n = 1024 * 1024 * 2; setsockopt(temp->sock, SOL_SOCKET, SO_RCVBUF, (char *)&n, sizeof(n)); setsockopt(temp->sock, SOL_SOCKET, SO_SNDBUF, (char *)&n, sizeof(n)); /* Enable broadcast on socket */ int broadcast = 1; setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); /* Set socket nonblocking. */ #ifdef WIN32 /* I think this works for Windows. */ u_long mode = 1; /* ioctl(sock, FIONBIO, &mode); */ ioctlsocket(temp->sock, FIONBIO, &mode); #else fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); #endif /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */ uint16_t *portptr = NULL; struct sockaddr_storage addr; size_t addrsize; #ifdef TOX_ENABLE_IPV6 if (temp->family == AF_INET) { IP4 ip4 = ip.ip4; #else IP4 ip4 = ip; #endif addrsize = sizeof(struct sockaddr_in); struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; addr4->sin_family = AF_INET; addr4->sin_port = 0; addr4->sin_addr = ip4.in_addr; portptr = &addr4->sin_port; #ifdef TOX_ENABLE_IPV6 } else if (temp->family == AF_INET6) { addrsize = sizeof(struct sockaddr_in6); struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; addr6->sin6_family = AF_INET6; addr6->sin6_port = 0; addr6->sin6_addr = ip.ip6.in6_addr; addr6->sin6_flowinfo = 0; addr6->sin6_scope_id = 0; portptr = &addr6->sin6_port; } else return NULL; if (ip.family == AF_INET6) { char ipv6only = 0; #ifdef LOGGING errno = 0; int res = #endif setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only)); #ifdef LOGGING if (res < 0) { sprintf(logbuffer, "Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n", errno, strerror(errno)); loglog(logbuffer); } else loglog("Embedded IPv4 addresses enabled successfully.\n"); #endif /* multicast local nodes */ struct ipv6_mreq mreq; memset(&mreq, 0, sizeof(mreq)); mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF; mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02; mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; mreq.ipv6mr_interface = 0; #ifdef LOGGING errno = 0; res = #endif setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); #ifdef LOGGING if (res < 0) { sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n", errno, strerror(errno)); loglog(logbuffer); } else loglog("Local multicast group FF02::1 joined successfully.\n"); #endif } #endif /* a hanging program or a different user might block the standard port; * as long as it isn't a parameter coming from the commandline, * try a few ports after it, to see if we can find a "free" one * * if we go on without binding, the first sendto() automatically binds to * a free port chosen by the system (i.e. anything from 1024 to 65535) * * returning NULL after bind fails has both advantages and disadvantages: * advantage: * we can rely on getting the port in the range 33445..33450, which * enables us to tell joe user to open their firewall to a small range * * disadvantage: * some clients might not test return of tox_new(), blindly assuming that * it worked ok (which it did previously without a successful bind) */ uint16_t port_to_try = port; *portptr = htons(port_to_try); int tries, res; for (tries = TOX_PORTRANGE_FROM; tries <= TOX_PORTRANGE_TO; tries++) { res = bind(temp->sock, (struct sockaddr *)&addr, addrsize); if (!res) { temp->port = *portptr; #ifdef LOGGING loginit(temp->port); sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port)); loglog(logbuffer); #endif /* errno isn't reset on success, only set on failure, the failed * binds with parallel clients yield a -EPERM to the outside if * errno isn't cleared here */ if (tries > 0) errno = 0; return temp; } port_to_try++; if (port_to_try > TOX_PORTRANGE_TO) port_to_try = TOX_PORTRANGE_FROM; *portptr = htons(port_to_try); } #ifdef DEBUG fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno, strerror(errno), ip_ntoa(&ip), port); #endif kill_networking(temp); return NULL; }
int addr_resolve(const char *address, IP *to, IP *extra) { if (!address || !to) return 0; sa_family_t family; #ifdef TOX_ENABLE_IPV6 family = to->family; #else family = AF_INET; #endif struct addrinfo *server = NULL; struct addrinfo *walker = NULL; struct addrinfo hints; int rc; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. if (at_startup() != 0) return 0; rc = getaddrinfo(address, NULL, &hints, &server); // Lookup failed. if (rc != 0) { return 0; } #ifdef TOX_ENABLE_IPV6 IP4 ip4; memset(&ip4, 0, sizeof(ip4)); IP6 ip6; memset(&ip6, 0, sizeof(ip6)); #endif for (walker = server; (walker != NULL) && (rc != 3); walker = walker->ai_next) { switch (walker->ai_family) { case AF_INET: if (walker->ai_family == family) { /* AF_INET requested, done */ struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; #ifdef TOX_ENABLE_IPV6 to->ip4.in_addr = addr->sin_addr; #else to->in_addr = addr->sin_addr; #endif rc = 3; } #ifdef TOX_ENABLE_IPV6 else if (!(rc & 1)) { /* AF_UNSPEC requested, store away */ struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; ip4.in_addr = addr->sin_addr; rc |= 1; } #endif break; /* switch */ #ifdef TOX_ENABLE_IPV6 case AF_INET6: if (walker->ai_family == family) { /* AF_INET6 requested, done */ if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; to->ip6.in6_addr = addr->sin6_addr; rc = 3; } } else if (!(rc & 2)) { /* AF_UNSPEC requested, store away */ if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; ip6.in6_addr = addr->sin6_addr; rc |= 2; } } break; /* switch */ #endif } } #ifdef TOX_ENABLE_IPV6 if (to->family == AF_UNSPEC) { if (rc & 2) { to->family = AF_INET6; to->ip6 = ip6; if ((rc & 1) && (extra != NULL)) { extra->family = AF_INET; extra->ip4 = ip4; } } else if (rc & 1) { to->family = AF_INET; to->ip4 = ip4; } else rc = 0; } #endif freeaddrinfo(server); return rc; }
/* Initialize networking. * Bind to ip and port. * ip must be in network order EX: 127.0.0.1 = (7F000001). * port is in host byte order (this means don't worry about it). * * returns Networking_Core object if no problems * returns NULL if there are problems. */ Networking_Core *new_networking(IP ip, uint16_t port) { if (at_startup() != 0) return NULL; /* Initialize our socket. */ Networking_Core *temp = calloc(1, sizeof(Networking_Core)); if (temp == NULL) return NULL; temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Check for socket error. */ #ifdef WIN32 if (temp->sock == INVALID_SOCKET) { /* MSDN recommends this. */ free(temp); return NULL; } #else if (temp->sock < 0) { free(temp); return NULL; } #endif /* Functions to increase the size of the send and receive UDP buffers. * NOTE: Uncomment if necessary. */ /* int n = 1024 * 1024 * 2; if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&n, sizeof(n)) == -1) { return -1; } if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&n, sizeof(n)) == -1) return -1; */ /* Enable broadcast on socket. */ int broadcast = 1; setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); /* Set socket nonblocking. */ #ifdef WIN32 /* I think this works for Windows. */ u_long mode = 1; /* ioctl(sock, FIONBIO, &mode); */ ioctlsocket(temp->sock, FIONBIO, &mode); #else fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); #endif /* Bind our socket to port PORT and address 0.0.0.0 */ ADDR addr = {AF_INET, htons(port), ip}; bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr)); return temp; }