diff options
author | George Hazan <ghazan@miranda.im> | 2022-07-24 16:44:24 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2022-07-24 16:44:24 +0300 |
commit | e55d071e5485a937efd427d159b76c208cccdcce (patch) | |
tree | 48d09dc5cf1df2581fd6471b5ccf1560015fa3a4 /protocols/Tox/libtox/src/toxcore/network.c | |
parent | f36629f67153bc500c828cf51de31988122a1024 (diff) |
fixes #3118 (Update toxcore to 0.2.18)
Diffstat (limited to 'protocols/Tox/libtox/src/toxcore/network.c')
-rw-r--r-- | protocols/Tox/libtox/src/toxcore/network.c | 1041 |
1 files changed, 602 insertions, 439 deletions
diff --git a/protocols/Tox/libtox/src/toxcore/network.c b/protocols/Tox/libtox/src/toxcore/network.c index 8569fc17e5..35893b73dc 100644 --- a/protocols/Tox/libtox/src/toxcore/network.c +++ b/protocols/Tox/libtox/src/toxcore/network.c @@ -92,16 +92,11 @@ #include <sodium.h> #endif +#include "ccompat.h" #include "logger.h" #include "mono_time.h" #include "util.h" -//!TOKSTYLE- -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -#include "../testing/fuzzing/fuzz_adapter.h" -#endif -//!TOKSTYLE+ - // Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD #if !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 @@ -113,6 +108,12 @@ #endif #endif +static_assert(sizeof(IP4) == SIZE_IP4, "IP4 size must be 4"); + +// TODO(iphydf): Stop relying on this. We memcpy this struct (and IP4 above) +// into packets but really should be serialising it properly. +static_assert(sizeof(IP6) == SIZE_IP6, "IP6 size must be 16"); + #if !defined(OS_WIN32) static bool should_ignore_recv_error(int err) @@ -120,21 +121,30 @@ static bool should_ignore_recv_error(int err) return err == EWOULDBLOCK; } +static bool should_ignore_connect_error(int err) +{ + return err == EWOULDBLOCK || err == EINPROGRESS; +} + +non_null() static const char *inet_ntop4(const struct in_addr *addr, char *buf, size_t bufsize) { return inet_ntop(AF_INET, addr, buf, bufsize); } +non_null() static const char *inet_ntop6(const struct in6_addr *addr, char *buf, size_t bufsize) { return inet_ntop(AF_INET6, addr, buf, bufsize); } +non_null() static int inet_pton4(const char *addrString, struct in_addr *addrbuf) { return inet_pton(AF_INET, addrString, addrbuf); } +non_null() static int inet_pton6(const char *addrString, struct in6_addr *addrbuf) { return inet_pton(AF_INET6, addrString, addrbuf); @@ -152,6 +162,12 @@ static bool should_ignore_recv_error(int err) return err == WSAEWOULDBLOCK || err == WSAECONNRESET; } +static bool should_ignore_connect_error(int err) +{ + return err == WSAEWOULDBLOCK || err == WSAEINPROGRESS; +} + +non_null() static const char *inet_ntop4(const struct in_addr *addr, char *buf, size_t bufsize) { struct sockaddr_in saddr = {0}; @@ -168,6 +184,7 @@ static const char *inet_ntop4(const struct in_addr *addr, char *buf, size_t bufs return buf; } +non_null() static const char *inet_ntop6(const struct in6_addr *addr, char *buf, size_t bufsize) { struct sockaddr_in6 saddr = {0}; @@ -184,6 +201,7 @@ static const char *inet_ntop6(const struct in6_addr *addr, char *buf, size_t buf return buf; } +non_null() static int inet_pton4(const char *addrString, struct in_addr *addrbuf) { struct sockaddr_in saddr = {0}; @@ -199,6 +217,7 @@ static int inet_pton4(const char *addrString, struct in_addr *addrbuf) return 1; } +non_null() static int inet_pton6(const char *addrString, struct in6_addr *addrbuf) { struct sockaddr_in6 saddr = {0}; @@ -221,7 +240,6 @@ static_assert(TOX_INET6_ADDRSTRLEN >= INET6_ADDRSTRLEN, static_assert(TOX_INET_ADDRSTRLEN >= INET_ADDRSTRLEN, "TOX_INET_ADDRSTRLEN should be greater or equal to INET_ADDRSTRLEN (#INET_ADDRSTRLEN)"); -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION static int make_proto(int proto) { switch (proto) { @@ -249,7 +267,6 @@ static int make_socktype(int type) return type; } } -#endif // FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION static int make_family(Family tox_family) { @@ -268,42 +285,58 @@ static int make_family(Family tox_family) } } +static const Family family_unspec = {TOX_AF_UNSPEC}; +static const Family family_ipv4 = {TOX_AF_INET}; +static const Family family_ipv6 = {TOX_AF_INET6}; +static const Family family_tcp_server = {TCP_SERVER_FAMILY}; +static const Family family_tcp_client = {TCP_CLIENT_FAMILY}; +static const Family family_tcp_ipv4 = {TCP_INET}; +static const Family family_tcp_ipv6 = {TCP_INET6}; +static const Family family_tox_tcp_ipv4 = {TOX_TCP_INET}; +static const Family family_tox_tcp_ipv6 = {TOX_TCP_INET6}; + static const Family *make_tox_family(int family) { switch (family) { case AF_INET: - return &net_family_ipv4; + return &family_ipv4; case AF_INET6: - return &net_family_ipv6; + return &family_ipv6; case AF_UNSPEC: - return &net_family_unspec; + return &family_unspec; default: return nullptr; } } +non_null() static void get_ip4(IP4 *result, const struct in_addr *addr) { + static_assert(sizeof(result->uint32) == sizeof(addr->s_addr), + "Tox and operating system don't agree on size of IPv4 addresses"); result->uint32 = addr->s_addr; } +non_null() static void get_ip6(IP6 *result, const struct in6_addr *addr) { - assert(sizeof(result->uint8) == sizeof(addr->s6_addr)); + static_assert(sizeof(result->uint8) == sizeof(addr->s6_addr), + "Tox and operating system don't agree on size of IPv6 addresses"); memcpy(result->uint8, addr->s6_addr, sizeof(result->uint8)); } +non_null() static void fill_addr4(const IP4 *ip, struct in_addr *addr) { addr->s_addr = ip->uint32; } +non_null() static void fill_addr6(const IP6 *ip, struct in6_addr *addr) { - assert(sizeof(ip->uint8) == sizeof(addr->s6_addr)); memcpy(addr->s6_addr, ip->uint8, sizeof(ip->uint8)); } @@ -311,6 +344,9 @@ static void fill_addr6(const IP6 *ip, struct in6_addr *addr) #define INADDR_LOOPBACK 0x7f000001 #endif +static const IP empty_ip = {{0}}; +const IP_Port empty_ip_port = {{{0}}}; + const IP4 ip4_broadcast = { INADDR_BROADCAST }; const IP6 ip6_broadcast = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } @@ -326,7 +362,12 @@ IP4 get_ip4_loopback(void) IP6 get_ip6_loopback(void) { IP6 loopback; +#ifdef ESP_PLATFORM + loopback = empty_ip_port.ip.ip.v6; + loopback.uint8[15] = 1; +#else get_ip6(&loopback, &in6addr_loopback); +#endif return loopback; } @@ -336,134 +377,262 @@ IP6 get_ip6_loopback(void) const Socket net_invalid_socket = { (int)INVALID_SOCKET }; -const Family net_family_unspec = {TOX_AF_UNSPEC}; -const Family net_family_ipv4 = {TOX_AF_INET}; -const Family net_family_ipv6 = {TOX_AF_INET6}; -const Family net_family_tcp_family = {TCP_FAMILY}; -const Family net_family_tcp_onion = {TCP_ONION_FAMILY}; -const Family net_family_tcp_ipv4 = {TCP_INET}; -const Family net_family_tcp_ipv6 = {TCP_INET6}; -const Family net_family_tox_tcp_ipv4 = {TOX_TCP_INET}; -const Family net_family_tox_tcp_ipv6 = {TOX_TCP_INET6}; +Family net_family_unspec() +{ + return family_unspec; +} + +Family net_family_ipv4() +{ + return family_ipv4; +} + +Family net_family_ipv6() +{ + return family_ipv6; +} + +Family net_family_tcp_server() +{ + return family_tcp_server; +} + +Family net_family_tcp_client() +{ + return family_tcp_client; +} + +Family net_family_tcp_ipv4() +{ + return family_tcp_ipv4; +} + +Family net_family_tcp_ipv6() +{ + return family_tcp_ipv6; +} + +Family net_family_tox_tcp_ipv4() +{ + return family_tox_tcp_ipv4; +} + +Family net_family_tox_tcp_ipv6() +{ + return family_tox_tcp_ipv6; +} bool net_family_is_unspec(Family family) { - return family.value == net_family_unspec.value; + return family.value == family_unspec.value; } bool net_family_is_ipv4(Family family) { - return family.value == net_family_ipv4.value; + return family.value == family_ipv4.value; } bool net_family_is_ipv6(Family family) { - return family.value == net_family_ipv6.value; + return family.value == family_ipv6.value; } -bool net_family_is_tcp_family(Family family) +bool net_family_is_tcp_server(Family family) { - return family.value == net_family_tcp_family.value; + return family.value == family_tcp_server.value; } -bool net_family_is_tcp_onion(Family family) +bool net_family_is_tcp_client(Family family) { - return family.value == net_family_tcp_onion.value; + return family.value == family_tcp_client.value; } bool net_family_is_tcp_ipv4(Family family) { - return family.value == net_family_tcp_ipv4.value; + return family.value == family_tcp_ipv4.value; } bool net_family_is_tcp_ipv6(Family family) { - return family.value == net_family_tcp_ipv6.value; + return family.value == family_tcp_ipv6.value; } bool net_family_is_tox_tcp_ipv4(Family family) { - return family.value == net_family_tox_tcp_ipv4.value; + return family.value == family_tox_tcp_ipv4.value; } bool net_family_is_tox_tcp_ipv6(Family family) { - return family.value == net_family_tox_tcp_ipv6.value; + return family.value == family_tox_tcp_ipv6.value; } bool sock_valid(Socket sock) { - return sock.socket != net_invalid_socket.socket; + return sock.sock != net_invalid_socket.sock; } -/** Close the socket. - */ -void kill_sock(Socket sock) +struct Network_Addr { + struct sockaddr_storage addr; + size_t size; +}; + +non_null() +static int sys_close(void *obj, int sock) +{ +#if defined(OS_WIN32) + return closesocket(sock); +#else // !OS_WIN32 + return close(sock); +#endif +} + +non_null() +static int sys_accept(void *obj, int sock) +{ + return accept(sock, nullptr, nullptr); +} + +non_null() +static int sys_bind(void *obj, int sock, const Network_Addr *addr) +{ + return bind(sock, (const struct sockaddr *)&addr->addr, addr->size); +} + +non_null() +static int sys_listen(void *obj, int sock, int backlog) +{ + return listen(sock, backlog); +} + +non_null() +static int sys_recvbuf(void *obj, int sock) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return; -#else #ifdef OS_WIN32 - closesocket(sock.socket); + u_long count = 0; + ioctlsocket(sock, FIONREAD, &count); #else - close(sock.socket); -#endif /* OS_WIN32 */ -#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ + int count = 0; + ioctl(sock, FIONREAD, &count); +#endif + + return count; } -bool set_socket_nonblock(Socket sock) +non_null() +static int sys_recv(void *obj, int sock, uint8_t *buf, size_t len) +{ + return recv(sock, (char *)buf, len, MSG_NOSIGNAL); +} + +non_null() +static int sys_send(void *obj, int sock, const uint8_t *buf, size_t len) +{ + return send(sock, (const char *)buf, len, MSG_NOSIGNAL); +} + +non_null() +static int sys_sendto(void *obj, int sock, const uint8_t *buf, size_t len, const Network_Addr *addr) { + return sendto(sock, (const char *)buf, len, 0, (const struct sockaddr *)&addr->addr, addr->size); +} + +non_null() +static int sys_recvfrom(void *obj, int sock, uint8_t *buf, size_t len, Network_Addr *addr) { + socklen_t size = addr->size; + const int ret = recvfrom(sock, (char *)buf, len, 0, (struct sockaddr *)&addr->addr, &size); + addr->size = size; + return ret; +} + +non_null() +static int sys_socket(void *obj, int domain, int type, int proto) +{ + return (int)socket(domain, type, proto); +} + +non_null() +static int sys_socket_nonblock(void *obj, int sock, bool nonblock) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return true; -#else #ifdef OS_WIN32 - u_long mode = 1; - return ioctlsocket(sock.socket, FIONBIO, &mode) == 0; + u_long mode = nonblock ? 1 : 0; + return ioctlsocket(sock, FIONBIO, &mode); #else - return fcntl(sock.socket, F_SETFL, O_NONBLOCK, 1) == 0; + return fcntl(sock, F_SETFL, O_NONBLOCK, nonblock ? 1 : 0); #endif /* OS_WIN32 */ -#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ } -bool set_socket_nosigpipe(Socket sock) +non_null() +static int sys_getsockopt(void *obj, int sock, int level, int optname, void *optval, size_t *optlen) { -#if defined(__APPLE__) - int set = 1; - return setsockopt(sock.socket, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set, sizeof(int)) == 0; -#else - return true; -#endif + socklen_t len = *optlen; + const int ret = getsockopt(sock, level, optname, optval, &len); + *optlen = len; + return ret; } -bool set_socket_reuseaddr(Socket sock) +non_null() +static int sys_setsockopt(void *obj, int sock, int level, int optname, const void *optval, size_t optlen) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return false; -#else - int set = 1; - return setsockopt(sock.socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&set, sizeof(set)) == 0; -#endif + return setsockopt(sock, level, optname, optval, optlen); } -bool set_socket_dualstack(Socket sock) +static const Network_Funcs system_network_funcs = { + sys_close, + sys_accept, + sys_bind, + sys_listen, + sys_recvbuf, + sys_recv, + sys_recvfrom, + sys_send, + sys_sendto, + sys_socket, + sys_socket_nonblock, + sys_getsockopt, + sys_setsockopt, +}; +static const Network system_network_obj = {&system_network_funcs}; + +const Network *system_network(void) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return false; -#else - int ipv6only = 0; - socklen_t optsize = sizeof(ipv6only); - int res = getsockopt(sock.socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, &optsize); + if ((true)) { + return nullptr; + } +#endif +#ifdef OS_WIN32 + WSADATA wsaData; - if ((res == 0) && (ipv6only == 0)) { - return true; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { + return nullptr; } +#endif + return &system_network_obj; +} - ipv6only = 0; - return setsockopt(sock.socket, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&ipv6only, sizeof(ipv6only)) == 0; +#if 0 +/* TODO(iphydf): Call this from functions that use `system_network()`. */ +void system_network_deinit(const Network *ns) +{ +#ifdef OS_WIN32 + WSACleanup(); +#endif +} #endif + +non_null() +static int net_setsockopt(const Network *ns, Socket sock, int level, int optname, const void *optval, size_t optlen) +{ + return ns->funcs->setsockopt(ns->obj, sock.sock, level, optname, optval, optlen); } +non_null() +static int net_getsockopt(const Network *ns, Socket sock, int level, int optname, void *optval, size_t *optlen) +{ + return ns->funcs->getsockopt(ns->obj, sock.sock, level, optname, optval, optlen); +} +non_null() static uint32_t data_0(uint16_t buflen, const uint8_t *buffer) { uint32_t data = 0; @@ -474,43 +643,136 @@ static uint32_t data_0(uint16_t buflen, const uint8_t *buffer) return data; } +non_null() static uint32_t data_1(uint16_t buflen, const uint8_t *buffer) { uint32_t data = 0; - if (buflen > 7) { + if (buflen > 8) { net_unpack_u32(buffer + 5, &data); } return data; } +non_null() static void loglogdata(const Logger *log, const char *message, const uint8_t *buffer, uint16_t buflen, const IP_Port *ip_port, long res) { - char ip_str[IP_NTOA_LEN]; - if (res < 0) { /* Windows doesn't necessarily know `%zu` */ - int error = net_error(); + Ip_Ntoa ip_str; + const int error = net_error(); char *strerror = net_new_strerror(error); LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x", buffer[0], message, min_u16(buflen, 999), 'E', - ip_ntoa(&ip_port->ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port->port), error, + net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), error, strerror, data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]); net_kill_strerror(strerror); } else if ((res > 0) && ((size_t)res <= buflen)) { + Ip_Ntoa ip_str; LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %08x%08x...%02x", buffer[0], message, min_u16(res, 999), (size_t)res < buflen ? '<' : '=', - ip_ntoa(&ip_port->ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port->port), 0, "OK", + net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), 0, "OK", data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]); } else { /* empty or overwrite */ + Ip_Ntoa ip_str; LOGGER_TRACE(log, "[%2u] %s %lu%c%u %s:%u (%u: %s) | %08x%08x...%02x", - buffer[0], message, res, !res ? '!' : '>', buflen, - ip_ntoa(&ip_port->ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port->port), 0, "OK", + buffer[0], message, res, res == 0 ? '!' : '>', buflen, + net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port), 0, "OK", data_0(buflen, buffer), data_1(buflen, buffer), buffer[buflen - 1]); } } +int net_send(const Network *ns, const Logger *log, + Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port) +{ + const int res = ns->funcs->send(ns->obj, sock.sock, buf, len); + loglogdata(log, "T=>", buf, len, ip_port, res); + return res; +} + +non_null() +static int net_sendto( + const Network *ns, + Socket sock, const uint8_t *buf, size_t len, const Network_Addr *addr, const IP_Port *ip_port) +{ + return ns->funcs->sendto(ns->obj, sock.sock, buf, len, addr); +} + +int net_recv(const Network *ns, const Logger *log, + Socket sock, uint8_t *buf, size_t len, const IP_Port *ip_port) +{ + const int res = ns->funcs->recv(ns->obj, sock.sock, buf, len); + loglogdata(log, "=>T", buf, len, ip_port, res); + return res; +} + +non_null() +static int net_recvfrom(const Network *ns, + Socket sock, uint8_t *buf, size_t len, Network_Addr *addr) +{ + return ns->funcs->recvfrom(ns->obj, sock.sock, buf, len, addr); +} + +int net_listen(const Network *ns, Socket sock, int backlog) +{ + return ns->funcs->listen(ns->obj, sock.sock, backlog); +} + +non_null() +static int net_bind(const Network *ns, Socket sock, const Network_Addr *addr) +{ + return ns->funcs->bind(ns->obj, sock.sock, addr); +} + +Socket net_accept(const Network *ns, Socket sock) +{ + const Socket newsock = {ns->funcs->accept(ns->obj, sock.sock)}; + return newsock; +} + +/** Close the socket. */ +void kill_sock(const Network *ns, Socket sock) +{ + ns->funcs->close(ns->obj, sock.sock); +} + +bool set_socket_nonblock(const Network *ns, Socket sock) +{ + return ns->funcs->socket_nonblock(ns->obj, sock.sock, true) == 0; +} + +bool set_socket_nosigpipe(const Network *ns, Socket sock) +{ +#if defined(__APPLE__) + int set = 1; + return net_setsockopt(ns, sock, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)) == 0; +#else + return true; +#endif +} + +bool set_socket_reuseaddr(const Network *ns, Socket sock) +{ + int set = 1; + return net_setsockopt(ns, sock, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set)) == 0; +} + +bool set_socket_dualstack(const Network *ns, Socket sock) +{ + int ipv6only = 0; + size_t optsize = sizeof(ipv6only); + const int res = net_getsockopt(ns, sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, &optsize); + + if ((res == 0) && (ipv6only == 0)) { + return true; + } + + ipv6only = 0; + return net_setsockopt(ns, sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)) == 0; +} + + typedef struct Packet_Handler { packet_handler_cb *function; void *object; @@ -519,6 +781,7 @@ typedef struct Packet_Handler { struct Networking_Core { const Logger *log; Packet_Handler packethandlers[256]; + const Network *ns; Family family; uint16_t port; @@ -543,6 +806,12 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe { IP_Port ipp_copy = *ip_port; + if (net_family_is_unspec(ip_port->ip.family)) { + // TODO(iphydf): Make this an error. Currently this fails sometimes when + // called from DHT.c:do_ping_and_sendnode_requests. + return -1; + } + if (net_family_is_unspec(net->family)) { /* Socket not initialized */ // TODO(iphydf): Make this an error. Currently, the onion client calls // this via DHT getnodes. @@ -570,25 +839,23 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe ip6.uint32[2] = net_htonl(0xFFFF); ip6.uint32[3] = ipp_copy.ip.ip.v4.uint32; - ipp_copy.ip.family = net_family_ipv6; + ipp_copy.ip.family = net_family_ipv6(); ipp_copy.ip.ip.v6 = ip6; } - struct sockaddr_storage addr; - - size_t addrsize; + Network_Addr addr; if (net_family_is_ipv4(ipp_copy.ip.family)) { - struct sockaddr_in *const addr4 = (struct sockaddr_in *)&addr; + struct sockaddr_in *const addr4 = (struct sockaddr_in *)&addr.addr; - addrsize = sizeof(struct sockaddr_in); + addr.size = sizeof(struct sockaddr_in); addr4->sin_family = AF_INET; addr4->sin_port = ipp_copy.port; fill_addr4(&ipp_copy.ip.ip.v4, &addr4->sin_addr); } else if (net_family_is_ipv6(ipp_copy.ip.family)) { - struct sockaddr_in6 *const addr6 = (struct sockaddr_in6 *)&addr; + struct sockaddr_in6 *const addr6 = (struct sockaddr_in6 *)&addr.addr; - addrsize = sizeof(struct sockaddr_in6); + addr.size = sizeof(struct sockaddr_in6); addr6->sin6_family = AF_INET6; addr6->sin6_port = ipp_copy.port; fill_addr6(&ipp_copy.ip.ip.v6, &addr6->sin6_addr); @@ -596,21 +863,12 @@ int send_packet(const Networking_Core *net, const IP_Port *ip_port, Packet packe addr6->sin6_flowinfo = 0; addr6->sin6_scope_id = 0; } else { - // TODO(iphydf): Make this an error. Currently this fails sometimes when - // called from DHT.c:do_ping_and_sendnode_requests. - LOGGER_WARNING(net->log, "unknown address type: %d", ipp_copy.ip.family.value); + LOGGER_ERROR(net->log, "unknown address type: %d", ipp_copy.ip.family.value); return -1; } -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - const long res = fuzz_sendto(net->sock.socket, (const char *)packet.data, packet.length, 0, - (struct sockaddr *)&addr, addrsize); -#else - const long res = sendto(net->sock.socket, (const char *)packet.data, packet.length, 0, - (struct sockaddr *)&addr, addrsize); -#endif - - loglogdata(net->log, "O=>", packet.data, packet.length, &ipp_copy, res); + const long res = net_sendto(net->ns, net->sock, packet.data, packet.length, &addr, &ipp_copy); + loglogdata(net->log, "O=>", packet.data, packet.length, ip_port, res); assert(res <= INT_MAX); return (int)res; @@ -627,34 +885,27 @@ int sendpacket(const Networking_Core *net, const IP_Port *ip_port, const uint8_t return send_packet(net, ip_port, packet); } -/** Function to receive data - * ip and port of sender is put into ip_port. - * Packet data is put into data. - * Packet length is put into length. +/** @brief Function to receive data + * ip and port of sender is put into ip_port. + * Packet data is put into data. + * Packet length is put into length. */ -static int receivepacket(const Logger *log, Socket sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) +non_null() +static int receivepacket(const Network *ns, const Logger *log, Socket sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) { memset(ip_port, 0, sizeof(IP_Port)); - struct sockaddr_storage addr; -#ifdef OS_WIN32 - int addrlen = sizeof(addr); -#else - socklen_t addrlen = sizeof(addr); -#endif + Network_Addr addr = {{0}}; + addr.size = sizeof(addr.addr); *length = 0; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - int fail_or_len = fuzz_recvfrom(sock.socket, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); -#else - int fail_or_len = recvfrom(sock.socket, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); -#endif + const int fail_or_len = net_recvfrom(ns, sock, data, MAX_UDP_PACKET_SIZE, &addr); if (fail_or_len < 0) { - int error = net_error(); + const int error = net_error(); if (!should_ignore_recv_error(error)) { char *strerror = net_new_strerror(error); - LOGGER_ERROR(log, "Unexpected error reading from socket: %u, %s", error, strerror); + LOGGER_ERROR(log, "unexpected error reading from socket: %u, %s", error, strerror); net_kill_strerror(strerror); } @@ -663,8 +914,8 @@ static int receivepacket(const Logger *log, Socket sock, IP_Port *ip_port, uint8 *length = (uint32_t)fail_or_len; - if (addr.ss_family == AF_INET) { - const struct sockaddr_in *addr_in = (const struct sockaddr_in *)&addr; + if (addr.addr.ss_family == AF_INET) { + const struct sockaddr_in *addr_in = (const struct sockaddr_in *)&addr.addr; const Family *const family = make_tox_family(addr_in->sin_family); assert(family != nullptr); @@ -676,8 +927,8 @@ static int receivepacket(const Logger *log, Socket sock, IP_Port *ip_port, uint8 ip_port->ip.family = *family; get_ip4(&ip_port->ip.ip.v4, &addr_in->sin_addr); ip_port->port = addr_in->sin_port; - } else if (addr.ss_family == AF_INET6) { - const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)&addr; + } else if (addr.addr.ss_family == AF_INET6) { + const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)&addr.addr; const Family *const family = make_tox_family(addr_in6->sin6_family); assert(family != nullptr); @@ -690,7 +941,7 @@ static int receivepacket(const Logger *log, Socket sock, IP_Port *ip_port, uint8 ip_port->port = addr_in6->sin6_port; if (ipv6_ipv4_in_v6(&ip_port->ip.ip.v6)) { - ip_port->ip.family = net_family_ipv4; + ip_port->ip.family = net_family_ipv4(); ip_port->ip.ip.v4.uint32 = ip_port->ip.ip.v6.uint32[3]; } } else { @@ -719,89 +970,37 @@ void networking_poll(const Networking_Core *net, void *userdata) uint8_t data[MAX_UDP_PACKET_SIZE]; uint32_t length; - while (receivepacket(net->log, net->sock, &ip_port, data, &length) != -1) { + while (receivepacket(net->ns, net->log, net->sock, &ip_port, data, &length) != -1) { if (length < 1) { continue; } - packet_handler_cb *const cb = net->packethandlers[data[0]].function; - void *const object = net->packethandlers[data[0]].object; + const Packet_Handler *const handler = &net->packethandlers[data[0]]; - if (cb == nullptr) { - LOGGER_WARNING(net->log, "[%02u] -- Packet has no handler", data[0]); + if (handler->function == nullptr) { + // TODO(https://github.com/TokTok/c-toxcore/issues/1115): Make this + // a warning or error again. + LOGGER_DEBUG(net->log, "[%02u] -- Packet has no handler", data[0]); continue; } - cb(object, &ip_port, data, length, userdata); - } -} - -//!TOKSTYLE- -// Global mutable state is not allowed in Tokstyle. -static uint8_t at_startup_ran = 0; -//!TOKSTYLE+ -int networking_at_startup(void) -{ - if (at_startup_ran != 0) { - return 0; - } - -#ifndef VANILLA_NACL - -#ifdef USE_RANDOMBYTES_STIR - randombytes_stir(); -#else - - if (sodium_init() == -1) { - return -1; - } - -#endif /*USE_RANDOMBYTES_STIR*/ - -#endif/*VANILLA_NACL*/ - -#ifdef OS_WIN32 - WSADATA wsaData; - - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { - return -1; + handler->function(handler->object, &ip_port, data, length, userdata); } - -#endif - at_startup_ran = 1; - return 0; -} - -/* TODO(irungentoo): Put this somewhere */ -#if 0 -static void at_shutdown(void) -{ -#ifdef OS_WIN32 - WSACleanup(); -#endif -} -#endif - -/** Initialize networking. - * Added for reverse compatibility with old new_networking calls. - */ -Networking_Core *new_networking(const Logger *log, const IP *ip, uint16_t port) -{ - return new_networking_ex(log, ip, port, port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM), nullptr); } -/** Initialize networking. +/** @brief 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. + * @return Networking_Core object if no problems + * @retval NULL if there are problems. * * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other. */ -Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t port_from, uint16_t port_to, - unsigned int *error) +Networking_Core *new_networking_ex( + const Logger *log, const Network *ns, const IP *ip, + uint16_t port_from, uint16_t port_to, unsigned int *error) { /* If both from and to are 0, use default port range * If one is 0 and the other is non-0, use the non-0 value as only port @@ -815,12 +1014,12 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por } else if (port_from != 0 && port_to == 0) { port_to = port_from; } else if (port_from > port_to) { - uint16_t temp = port_from; + const uint16_t temp_port = port_from; port_from = port_to; - port_to = temp; + port_to = temp_port; } - if (error) { + if (error != nullptr) { *error = 2; } @@ -830,69 +1029,60 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por return nullptr; } - if (networking_at_startup() != 0) { - return nullptr; - } - Networking_Core *temp = (Networking_Core *)calloc(1, sizeof(Networking_Core)); if (temp == nullptr) { return nullptr; } + temp->ns = ns; temp->log = log; temp->family = ip->family; temp->port = 0; /* Initialize our socket. */ /* add log message what we're creating */ - temp->sock = net_socket(temp->family, TOX_SOCK_DGRAM, TOX_PROTO_UDP); + temp->sock = net_socket(ns, temp->family, TOX_SOCK_DGRAM, TOX_PROTO_UDP); /* Check for socket error. */ if (!sock_valid(temp->sock)) { - int neterror = net_error(); + const int neterror = net_error(); char *strerror = net_new_strerror(neterror); - LOGGER_ERROR(log, "Failed to get a socket?! %d, %s", neterror, strerror); + LOGGER_ERROR(log, "failed to get a socket?! %d, %s", neterror, strerror); net_kill_strerror(strerror); free(temp); - if (error) { + if (error != nullptr) { *error = 1; } return nullptr; } -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Functions to increase the size of the send and receive UDP buffers. */ int n = 1024 * 1024 * 2; - if (setsockopt(temp->sock.socket, SOL_SOCKET, SO_RCVBUF, (const char *)&n, sizeof(n)) != 0) { - LOGGER_WARNING(log, "Failed to set socket option %d", SO_RCVBUF); + if (net_setsockopt(ns, temp->sock, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) != 0) { + LOGGER_ERROR(log, "failed to set socket option %d", SO_RCVBUF); } - if (setsockopt(temp->sock.socket, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof(n)) != 0) { - LOGGER_WARNING(log, "Failed to set socket option %d", SO_SNDBUF); + if (net_setsockopt(ns, temp->sock, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) != 0) { + LOGGER_ERROR(log, "failed to set socket option %d", SO_SNDBUF); } -#endif - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Enable broadcast on socket */ int broadcast = 1; - if (setsockopt(temp->sock.socket, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast)) != 0) { - LOGGER_WARNING(log, "Failed to set socket option %d", SO_BROADCAST); + if (net_setsockopt(ns, temp->sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) != 0) { + LOGGER_ERROR(log, "failed to set socket option %d", SO_BROADCAST); } -#endif - /* iOS UDP sockets are weird and apparently can SIGPIPE */ - if (!set_socket_nosigpipe(temp->sock)) { + if (!set_socket_nosigpipe(ns, temp->sock)) { kill_networking(temp); - if (error) { + if (error != nullptr) { *error = 1; } @@ -900,10 +1090,10 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por } /* Set socket nonblocking. */ - if (!set_socket_nonblock(temp->sock)) { + if (!set_socket_nonblock(ns, temp->sock)) { kill_networking(temp); - if (error) { + if (error != nullptr) { *error = 1; } @@ -912,24 +1102,23 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */ uint16_t *portptr = nullptr; - struct sockaddr_storage addr; - size_t addrsize; + Network_Addr addr; - memset(&addr, 0, sizeof(struct sockaddr_storage)); + memset(&addr.addr, 0, sizeof(struct sockaddr_storage)); if (net_family_is_ipv4(temp->family)) { - struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr; - addrsize = sizeof(struct sockaddr_in); + addr.size = sizeof(struct sockaddr_in); addr4->sin_family = AF_INET; addr4->sin_port = 0; fill_addr4(&ip->ip.v4, &addr4->sin_addr); portptr = &addr4->sin_port; } else if (net_family_is_ipv6(temp->family)) { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr; - addrsize = sizeof(struct sockaddr_in6); + addr.size = sizeof(struct sockaddr_in6); addr6->sin6_family = AF_INET6; addr6->sin6_port = 0; fill_addr6(&ip->ip.v6, &addr6->sin6_addr); @@ -943,12 +1132,16 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por return nullptr; } -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (net_family_is_ipv6(ip->family)) { - const int is_dualstack = set_socket_dualstack(temp->sock); - LOGGER_DEBUG(log, "Dual-stack socket: %s", - is_dualstack ? "enabled" : "Failed to enable, won't be able to receive from/send to IPv4 addresses"); + const bool is_dualstack = set_socket_dualstack(ns, temp->sock); + + if (is_dualstack) { + LOGGER_TRACE(log, "Dual-stack socket: enabled"); + } else { + LOGGER_ERROR(log, "Dual-stack socket failed to enable, won't be able to receive from/send to IPv4 addresses"); + } + +#ifndef ESP_PLATFORM /* multicast local nodes */ struct ipv6_mreq mreq; memset(&mreq, 0, sizeof(mreq)); @@ -957,21 +1150,20 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; mreq.ipv6mr_interface = 0; - const int res = setsockopt(temp->sock.socket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq)); + const int res = net_setsockopt(ns, temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); int neterror = net_error(); char *strerror = net_new_strerror(neterror); if (res < 0) { - LOGGER_DEBUG(log, "Failed to activate local multicast membership. (%d, %s)", neterror, strerror); + LOGGER_INFO(log, "Failed to activate local multicast membership in FF02::1. (%d, %s)", neterror, strerror); } else { - LOGGER_DEBUG(log, "Local multicast group FF02::1 joined successfully. (%d, %s)", neterror, strerror); + LOGGER_TRACE(log, "Local multicast group joined successfully. (%d, %s)", neterror, strerror); } net_kill_strerror(strerror); - } - #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, @@ -993,17 +1185,13 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por *portptr = net_htons(port_to_try); for (uint16_t tries = port_from; tries <= port_to; ++tries) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - int res = 0; -#else - int res = bind(temp->sock.socket, (struct sockaddr *)&addr, addrsize); -#endif + const int res = net_bind(ns, temp->sock, &addr); - if (!res) { + if (res == 0) { temp->port = *portptr; - char ip_str[IP_NTOA_LEN]; - LOGGER_DEBUG(log, "Bound successfully to %s:%u", ip_ntoa(ip, ip_str, sizeof(ip_str)), + Ip_Ntoa ip_str; + LOGGER_DEBUG(log, "Bound successfully to %s:%u", net_ip_ntoa(ip, &ip_str), net_ntohs(temp->port)); /* errno isn't reset on success, only set on failure, the failed @@ -1013,7 +1201,7 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por errno = 0; } - if (error) { + if (error != nullptr) { *error = 0; } @@ -1029,27 +1217,23 @@ Networking_Core *new_networking_ex(const Logger *log, const IP *ip, uint16_t por *portptr = net_htons(port_to_try); } - char ip_str[IP_NTOA_LEN]; + Ip_Ntoa ip_str; int neterror = net_error(); char *strerror = net_new_strerror(neterror); - LOGGER_ERROR(log, "Failed to bind socket: %d, %s IP: %s port_from: %u port_to: %u", neterror, strerror, - ip_ntoa(ip, ip_str, sizeof(ip_str)), port_from, port_to); + LOGGER_ERROR(log, "failed to bind socket: %d, %s IP: %s port_from: %u port_to: %u", neterror, strerror, + net_ip_ntoa(ip, &ip_str), port_from, port_to); net_kill_strerror(strerror); kill_networking(temp); - if (error) { + if (error != nullptr) { *error = 1; } return nullptr; } -Networking_Core *new_networking_no_udp(const Logger *log) +Networking_Core *new_networking_no_udp(const Logger *log, const Network *ns) { - if (networking_at_startup() != 0) { - return nullptr; - } - /* this is the easiest way to completely disable UDP without changing too much code. */ Networking_Core *net = (Networking_Core *)calloc(1, sizeof(Networking_Core)); @@ -1057,6 +1241,7 @@ Networking_Core *new_networking_no_udp(const Logger *log) return nullptr; } + net->ns = ns; net->log = log; return net; @@ -1065,13 +1250,13 @@ Networking_Core *new_networking_no_udp(const Logger *log) /** Function to cleanup networking stuff (doesn't do much right now). */ void kill_networking(Networking_Core *net) { - if (!net) { + if (net == nullptr) { return; } if (!net_family_is_unspec(net->family)) { /* Socket is initialized, so we close it. */ - kill_sock(net->sock); + kill_sock(net->ns, net->sock); } free(net); @@ -1080,7 +1265,7 @@ void kill_networking(Networking_Core *net) bool ip_equal(const IP *a, const IP *b) { - if (!a || !b) { + if (a == nullptr || b == nullptr) { return false; } @@ -1122,11 +1307,11 @@ bool ip_equal(const IP *a, const IP *b) bool ipport_equal(const IP_Port *a, const IP_Port *b) { - if (!a || !b) { + if (a == nullptr || b == nullptr) { return false; } - if (!a->port || (a->port != b->port)) { + if (a->port == 0 || (a->port != b->port)) { return false; } @@ -1136,38 +1321,38 @@ bool ipport_equal(const IP_Port *a, const IP_Port *b) /** nulls out ip */ void ip_reset(IP *ip) { - if (!ip) { + if (ip == nullptr) { return; } - memset(ip, 0, sizeof(IP)); + *ip = empty_ip; } /** nulls out ip_port */ void ipport_reset(IP_Port *ipport) { - if (!ipport) { + if (ipport == nullptr) { return; } - memset(ipport, 0, sizeof(IP_Port)); + *ipport = empty_ip_port; } /** nulls out ip, sets family according to flag */ void ip_init(IP *ip, bool ipv6enabled) { - if (!ip) { + if (ip == nullptr) { return; } - memset(ip, 0, sizeof(IP)); - ip->family = ipv6enabled ? net_family_ipv6 : net_family_ipv4; + *ip = empty_ip; + ip->family = ipv6enabled ? net_family_ipv6() : net_family_ipv4(); } /** checks if ip is valid */ bool ip_isset(const IP *ip) { - if (!ip) { + if (ip == nullptr) { return false; } @@ -1177,96 +1362,82 @@ bool ip_isset(const IP *ip) /** checks if ip is valid */ bool ipport_isset(const IP_Port *ipport) { - if (!ipport) { + if (ipport == nullptr) { return false; } - if (!ipport->port) { + if (ipport->port == 0) { return false; } return ip_isset(&ipport->ip); } -/** copies an ip structure (careful about direction!) */ +/** copies an ip structure (careful about direction) */ void ip_copy(IP *target, const IP *source) { - if (!source || !target) { + if (source == nullptr || target == nullptr) { return; } *target = *source; } -/** copies an ip_port structure (careful about direction!) */ +/** copies an ip_port structure (careful about direction) */ void ipport_copy(IP_Port *target, const IP_Port *source) { - if (!source || !target) { + if (source == nullptr || target == nullptr) { return; } *target = *source; } -/** ip_ntoa - * converts ip into a string - * ip_str must be of length at least IP_NTOA_LEN +/** @brief Converts IP into a string. + * + * Writes error message into the buffer on error. * - * writes error message into the buffer on error + * @param ip_str contains a buffer of the required size. * - * returns ip_str + * @return Pointer to the buffer inside `ip_str` containing the IP string. */ -const char *ip_ntoa(const IP *ip, char *ip_str, size_t length) +const char *net_ip_ntoa(const IP *ip, Ip_Ntoa *ip_str) { - if (length < IP_NTOA_LEN) { - snprintf(ip_str, length, "Bad buf length"); - return ip_str; - } - - if (ip) { - if (net_family_is_ipv4(ip->family)) { - /* returns standard quad-dotted notation */ - struct in_addr addr; - fill_addr4(&ip->ip.v4, &addr); + assert(ip_str != nullptr); - ip_str[0] = '\0'; - assert(make_family(ip->family) == AF_INET); - inet_ntop4(&addr, ip_str, length); - } else if (net_family_is_ipv6(ip->family)) { - /* returns hex-groups enclosed into square brackets */ - struct in6_addr addr; - fill_addr6(&ip->ip.v6, &addr); + if (ip == nullptr) { + snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid: NULL)"); + return ip_str->buf; + } - assert(make_family(ip->family) == AF_INET6); - inet_ntop6(&addr, ip_str, length); - } else { - snprintf(ip_str, length, "(IP invalid, family %u)", ip->family.value); - } - } else { - snprintf(ip_str, length, "(IP invalid: NULL)"); + if (!ip_parse_addr(ip, ip_str->buf, sizeof(ip_str->buf))) { + snprintf(ip_str->buf, sizeof(ip_str->buf), "(IP invalid, family %u)", ip->family.value); + return ip_str->buf; } /* brute force protection against lacking termination */ - ip_str[length - 1] = '\0'; - return ip_str; + ip_str->buf[sizeof(ip_str->buf) - 1] = '\0'; + return ip_str->buf; } bool ip_parse_addr(const IP *ip, char *address, size_t length) { - if (!address || !ip) { + if (address == nullptr || ip == nullptr) { return false; } if (net_family_is_ipv4(ip->family)) { - const struct in_addr *addr = (const struct in_addr *)&ip->ip.v4; + struct in_addr addr; assert(make_family(ip->family) == AF_INET); - return inet_ntop4(addr, address, length) != nullptr; + fill_addr4(&ip->ip.v4, &addr); + return inet_ntop4(&addr, address, length) != nullptr; } if (net_family_is_ipv6(ip->family)) { - const struct in6_addr *addr = (const struct in6_addr *)&ip->ip.v6; + struct in6_addr addr; assert(make_family(ip->family) == AF_INET6); - return inet_ntop6(addr, address, length) != nullptr; + fill_addr6(&ip->ip.v6, &addr); + return inet_ntop6(&addr, address, length) != nullptr; } return false; @@ -1274,14 +1445,14 @@ bool ip_parse_addr(const IP *ip, char *address, size_t length) bool addr_parse_ip(const char *address, IP *to) { - if (!address || !to) { + if (address == nullptr || to == nullptr) { return false; } struct in_addr addr4; if (inet_pton4(address, &addr4) == 1) { - to->family = net_family_ipv4; + to->family = net_family_ipv4(); get_ip4(&to->ip.v4, &addr4); return true; } @@ -1289,7 +1460,7 @@ bool addr_parse_ip(const char *address, IP *to) struct in6_addr addr6; if (inet_pton6(address, &addr6) == 1) { - to->family = net_family_ipv6; + to->family = net_family_ipv6(); get_ip6(&to->ip.v6, &addr6); return true; } @@ -1297,28 +1468,48 @@ bool addr_parse_ip(const char *address, IP *to) return false; } -int addr_resolve(const char *address, IP *to, IP *extra) +/** addr_resolve return values */ +#define TOX_ADDR_RESOLVE_INET 1 +#define TOX_ADDR_RESOLVE_INET6 2 + +/** + * Uses getaddrinfo to resolve an address into an IP address. + * + * Uses the first IPv4/IPv6 addresses returned by getaddrinfo. + * + * @param address a hostname (or something parseable to an IP address) + * @param to to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (0), if both + * IP versions are acceptable + * @param extra can be NULL and is only set in special circumstances, see returns + * + * Returns in `*to` a valid IPAny (v4/v6), + * prefers v6 if `ip.family` was TOX_AF_UNSPEC and both available + * Returns in `*extra` an IPv4 address, if family was TOX_AF_UNSPEC and `*to` is TOX_AF_INET6 + * + * @return 0 on failure, `TOX_ADDR_RESOLVE_*` on success. + */ +non_null(1, 2, 3) nullable(4) +static int addr_resolve(const Network *ns, const char *address, IP *to, IP *extra) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return false; -#else + if ((true)) { + return 0; + } +#endif - if (!address || !to) { + if (address == nullptr || to == nullptr) { return 0; } - Family tox_family = to->family; - int family = make_family(tox_family); + const Family tox_family = to->family; + const int family = make_family(tox_family); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. - if (networking_at_startup() != 0) { - return 0; - } - struct addrinfo *server = nullptr; const int rc = getaddrinfo(address, nullptr, &hints, &server); @@ -1329,9 +1520,9 @@ int addr_resolve(const char *address, IP *to, IP *extra) } IP ip4; - ip_init(&ip4, 0); // ipv6enabled = 0 + ip_init(&ip4, false); // ipv6enabled = false IP ip6; - ip_init(&ip6, 1); // ipv6enabled = 1 + ip_init(&ip6, true); // ipv6enabled = true int result = 0; bool done = false; @@ -1340,12 +1531,12 @@ int addr_resolve(const char *address, IP *to, IP *extra) switch (walker->ai_family) { case AF_INET: { if (walker->ai_family == family) { /* AF_INET requested, done */ - const struct sockaddr_in *addr = (const struct sockaddr_in *)(void *)walker->ai_addr; + const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)walker->ai_addr; get_ip4(&to->ip.v4, &addr->sin_addr); result = TOX_ADDR_RESOLVE_INET; done = true; - } else if (!(result & TOX_ADDR_RESOLVE_INET)) { /* AF_UNSPEC requested, store away */ - const struct sockaddr_in *addr = (const struct sockaddr_in *)(void *)walker->ai_addr; + } else if ((result & TOX_ADDR_RESOLVE_INET) == 0) { /* AF_UNSPEC requested, store away */ + const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)walker->ai_addr; get_ip4(&ip4.ip.v4, &addr->sin_addr); result |= TOX_ADDR_RESOLVE_INET; } @@ -1361,7 +1552,7 @@ int addr_resolve(const char *address, IP *to, IP *extra) result = TOX_ADDR_RESOLVE_INET6; done = true; } - } else if (!(result & TOX_ADDR_RESOLVE_INET6)) { /* AF_UNSPEC requested, store away */ + } else if ((result & TOX_ADDR_RESOLVE_INET6) == 0) { /* AF_UNSPEC requested, store away */ if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(void *)walker->ai_addr; get_ip6(&ip6.ip.v6, &addr->sin6_addr); @@ -1375,13 +1566,13 @@ int addr_resolve(const char *address, IP *to, IP *extra) } if (family == AF_UNSPEC) { - if (result & TOX_ADDR_RESOLVE_INET6) { + if ((result & TOX_ADDR_RESOLVE_INET6) != 0) { ip_copy(to, &ip6); - if ((result & TOX_ADDR_RESOLVE_INET) && (extra != nullptr)) { + if ((result & TOX_ADDR_RESOLVE_INET) != 0 && (extra != nullptr)) { ip_copy(extra, &ip4); } - } else if (result & TOX_ADDR_RESOLVE_INET) { + } else if ((result & TOX_ADDR_RESOLVE_INET) != 0) { ip_copy(to, &ip4); } else { result = 0; @@ -1390,12 +1581,11 @@ int addr_resolve(const char *address, IP *to, IP *extra) freeaddrinfo(server); return result; -#endif } -bool addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra) +bool addr_resolve_or_parse_ip(const Network *ns, const char *address, IP *to, IP *extra) { - if (!addr_resolve(address, to, extra)) { + if (addr_resolve(ns, address, to, extra) == 0) { if (!addr_parse_ip(address, to)) { return false; } @@ -1404,7 +1594,7 @@ bool addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra) return true; } -int net_connect(const Logger *log, Socket sock, const IP_Port *ip_port) +bool net_connect(const Logger *log, Socket sock, const IP_Port *ip_port) { struct sockaddr_storage addr = {0}; size_t addrsize; @@ -1424,30 +1614,55 @@ int net_connect(const Logger *log, Socket sock, const IP_Port *ip_port) fill_addr6(&ip_port->ip.ip.v6, &addr6->sin6_addr); addr6->sin6_port = ip_port->port; } else { - return 0; + Ip_Ntoa ip_str; + LOGGER_ERROR(log, "cannot connect to %s:%d which is neither IPv4 nor IPv6", + net_ip_ntoa(&ip_port->ip, &ip_str), ip_port->port); + return false; } #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else - LOGGER_DEBUG(log, "connecting socket %d", (int)sock.socket); - return connect(sock.socket, (struct sockaddr *)&addr, addrsize); + if ((true)) { + return true; + } #endif + + Ip_Ntoa ip_str; + LOGGER_DEBUG(log, "connecting socket %d to %s:%d", + (int)sock.sock, net_ip_ntoa(&ip_port->ip, &ip_str), net_ntohs(ip_port->port)); + errno = 0; + + if (connect(sock.sock, (struct sockaddr *)&addr, addrsize) == -1) { + const int error = net_error(); + + // Non-blocking socket: "Operation in progress" means it's connecting. + if (!should_ignore_connect_error(error)) { + char *net_strerror = net_new_strerror(error); + LOGGER_ERROR(log, "failed to connect to %s:%d: %d (%s)", + net_ip_ntoa(&ip_port->ip, &ip_str), ip_port->port, error, net_strerror); + net_kill_strerror(net_strerror); + return false; + } + } + + return true; } int32_t net_getipport(const char *node, IP_Port **res, int tox_type) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - *res = (IP_Port *)calloc(1, sizeof(IP_Port)); - assert(*res != nullptr); - IP_Port *ip_port = *res; - ip_port->ip.ip.v4.uint32 = 0x7F000003; // 127.0.0.3 - ip_port->ip.family = *make_tox_family(AF_INET); + if ((true)) { + *res = (IP_Port *)calloc(1, sizeof(IP_Port)); + assert(*res != nullptr); + IP_Port *ip_port = *res; + ip_port->ip.ip.v4.uint32 = 0x7F000003; // 127.0.0.3 + ip_port->ip.family = *make_tox_family(AF_INET); + + return 1; + } +#endif - return 1; -#else // Try parsing as IP address first. - IP_Port parsed = {0}; + IP_Port parsed = {{{0}}}; if (addr_parse_ip(node, &parsed.ip)) { IP_Port *tmp = (IP_Port *)calloc(1, sizeof(IP_Port)); @@ -1534,7 +1749,6 @@ int32_t net_getipport(const char *node, IP_Port **res, int tox_type) freeaddrinfo(infos); return count; -#endif } void net_freeipport(IP_Port *ip_ports) @@ -1542,106 +1756,42 @@ void net_freeipport(IP_Port *ip_ports) free(ip_ports); } -bool bind_to_port(Socket sock, Family family, uint16_t port) +bool bind_to_port(const Network *ns, Socket sock, Family family, uint16_t port) { - struct sockaddr_storage addr = {0}; - size_t addrsize; + Network_Addr addr = {{0}}; if (net_family_is_ipv4(family)) { - struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr; - addrsize = sizeof(struct sockaddr_in); + addr.size = sizeof(struct sockaddr_in); addr4->sin_family = AF_INET; addr4->sin_port = net_htons(port); } else if (net_family_is_ipv6(family)) { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr; - addrsize = sizeof(struct sockaddr_in6); + addr.size = sizeof(struct sockaddr_in6); addr6->sin6_family = AF_INET6; addr6->sin6_port = net_htons(port); } else { return false; } -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return true; -#else - return bind(sock.socket, (struct sockaddr *)&addr, addrsize) == 0; -#endif + return net_bind(ns, sock, &addr) == 0; } -Socket net_socket(Family domain, int type, int protocol) +Socket net_socket(const Network *ns, Family domain, int type, int protocol) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - const Socket sock = {1}; - return sock; -#else const int platform_domain = make_family(domain); const int platform_type = make_socktype(type); const int platform_prot = make_proto(protocol); - const Socket sock = {(int)socket(platform_domain, platform_type, platform_prot)}; + const Socket sock = {ns->funcs->socket(ns->obj, platform_domain, platform_type, platform_prot)}; return sock; -#endif -} - -int net_send(const Logger *log, Socket sock, const uint8_t *buf, size_t len, const IP_Port *ip_port) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - int res = fuzz_send(sock.socket, (const char *)buf, len, MSG_NOSIGNAL); -#else - int res = send(sock.socket, (const char *)buf, len, MSG_NOSIGNAL); -#endif - loglogdata(log, "T=>", buf, len, ip_port, res); - return res; -} - -int net_recv(const Logger *log, Socket sock, uint8_t *buf, size_t len, const IP_Port *ip_port) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - int res = fuzz_recv(sock.socket, (char *)buf, len, MSG_NOSIGNAL); -#else - int res = recv(sock.socket, (char *)buf, len, MSG_NOSIGNAL); -#endif - loglogdata(log, "=>T", buf, len, ip_port, res); - return res; -} - -int net_listen(Socket sock, int backlog) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else - return listen(sock.socket, backlog); -#endif -} - -Socket net_accept(Socket sock) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - const Socket newsock = {2}; - return newsock; -#else - const Socket newsock = {accept(sock.socket, nullptr, nullptr)}; - return newsock; -#endif } -uint16_t net_socket_data_recv_buffer(Socket sock) +uint16_t net_socket_data_recv_buffer(const Network *ns, Socket sock) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - return 0; -#else - -#ifdef OS_WIN32 - u_long count = 0; - ioctlsocket(sock.socket, FIONREAD, &count); -#else - int count = 0; - ioctl(sock.socket, FIONREAD, &count); -#endif - - return (uint16_t)count; -#endif + const int count = ns->funcs->recvbuf(ns->obj, sock.sock); + return (uint16_t)max_s32(0, min_s32(count, UINT16_MAX)); } uint32_t net_htonl(uint32_t hostlong) @@ -1689,8 +1839,8 @@ size_t net_pack_u64(uint8_t *bytes, uint64_t v) size_t net_unpack_u16(const uint8_t *bytes, uint16_t *v) { - uint8_t hi = bytes[0]; - uint8_t lo = bytes[1]; + const uint8_t hi = bytes[0]; + const uint8_t lo = bytes[1]; *v = ((uint16_t)hi << 8) | lo; return sizeof(*v); } @@ -1731,9 +1881,9 @@ int net_error(void) #endif } +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) char *net_new_strerror(int error) { -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) char *str = nullptr; // Windows API is weird. The 5th function arg is of char* type, but we // have to pass char** so that it could assign new memory block to our @@ -1745,29 +1895,42 @@ char *net_new_strerror(int error) FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error, 0, (char *)&str, 0, nullptr); return str; +} #else - char tmp[256]; - - errno = 0; - #ifdef _GNU_SOURCE - const char *retstr = strerror_r(error, tmp, sizeof(tmp)); +non_null() +static const char *net_strerror_r(int error, char *tmp, size_t tmp_size) +{ + const char *retstr = strerror_r(error, tmp, tmp_size); if (errno != 0) { - snprintf(tmp, sizeof(tmp), "error %d (strerror_r failed with errno %d)", error, errno); + snprintf(tmp, tmp_size, "error %d (strerror_r failed with errno %d)", error, errno); } + return retstr; +} #else - const int fmt_error = strerror_r(error, tmp, sizeof(tmp)); +non_null() +static const char *net_strerror_r(int error, char *tmp, size_t tmp_size) +{ + const int fmt_error = strerror_r(error, tmp, tmp_size); if (fmt_error != 0) { - snprintf(tmp, sizeof(tmp), "error %d (strerror_r failed with error %d, errno %d)", error, fmt_error, errno); + snprintf(tmp, tmp_size, "error %d (strerror_r failed with error %d, errno %d)", error, fmt_error, errno); } - const char *retstr = tmp; + return tmp; +} #endif +char *net_new_strerror(int error) +{ + char tmp[256]; + + errno = 0; + const char *retstr = net_strerror_r(error, tmp, sizeof(tmp)); const size_t retstr_len = strlen(retstr); + char *str = (char *)malloc(retstr_len + 1); if (str == nullptr) { @@ -1777,8 +1940,8 @@ char *net_new_strerror(int error) memcpy(str, retstr, retstr_len + 1); return str; -#endif } +#endif void net_kill_strerror(char *strerror) { |