/** * Selftest. To be run for every commit. */ #include #include #include #include #include #include #include #include #include #include #define LIBZT_DEBUG 1 #include "../src/Debug.hpp" #pragma GCC diagnostic ignored "-Wunused-value" int random32() { const int BITS_PER_RAND = (int)(log2(RAND_MAX / 2 + 1) + 1.0); int ret = 0; for (int i = 0; i < sizeof(int) * CHAR_BIT; i += BITS_PER_RAND) { ret <<= BITS_PER_RAND; ret |= rand(); } return ret; } uint64_t random64() { return ((uint64_t)random32() << 32) | random32(); } //----------------------------------------------------------------------------// // Test parameters and variables // //----------------------------------------------------------------------------// int verbosity = 2; int callback_was_called_flag = 0; // Used throughout the selftest char keypair_i[ZTS_ID_STR_BUF_LEN]; //----------------------------------------------------------------------------// // Event handler // //----------------------------------------------------------------------------// void print_node_details(const char* msg, zts_node_info_t* d) { DEBUG_INFO(" %s", msg); if (verbosity < 2) { return; } DEBUG_INFO(" msg->node->node_id : %10llx", d->node_id); DEBUG_INFO(" msg->node->port_primary : %10d", d->port_primary); DEBUG_INFO(" msg->node->port_secondary : %10d", d->port_secondary); DEBUG_INFO(" msg->node->port_tertiary : %10d", d->port_tertiary); DEBUG_INFO(" msg->node->ver_major : %10d", d->ver_major); DEBUG_INFO(" msg->node->ver_minor : %10d", d->ver_minor); DEBUG_INFO(" msg->node->ver_rev : %10d", d->ver_rev); } void print_net_details(const char* msg, zts_net_info_t* d) { DEBUG_INFO(" %s", msg); if (verbosity < 2) { return; } DEBUG_INFO(" net_id : %16llx", d->net_id); DEBUG_INFO(" mac : %llx", d->mac); DEBUG_INFO(" name : %s", d->name); DEBUG_INFO(" type : %d", d->type); DEBUG_INFO(" mtu : %d", d->mtu); DEBUG_INFO(" dhcp : %d", d->dhcp); DEBUG_INFO(" bridge : %d", d->bridge); DEBUG_INFO(" broadcast_enabled : %d", d->broadcast_enabled); DEBUG_INFO(" port_error : %d", d->port_error); DEBUG_INFO(" netconf_rev : %lu", d->netconf_rev); DEBUG_INFO(" route_count : %d", d->route_count); DEBUG_INFO(" multicast_sub_count : %d", d->multicast_sub_count); for (int i = 0; i < d->multicast_sub_count; i++) { DEBUG_INFO("\t - mac=%llx, adi=%x", d->multicast_subs[i].mac, d->multicast_subs[i].adi); } DEBUG_INFO("\t- addresses:"); for (int i = 0; i < d->assigned_addr_count; i++) { if (d->assigned_addrs[i].ss_family == ZTS_AF_INET) { char ipstr[ZTS_INET_ADDRSTRLEN] = { 0 }; struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)&(d->assigned_addrs[i]); zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN); DEBUG_INFO("\t - %s", ipstr); } if (d->assigned_addrs[i].ss_family == ZTS_AF_INET6) { char ipstr[ZTS_INET6_ADDRSTRLEN] = { 0 }; struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&(d->assigned_addrs[i]); zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN); DEBUG_INFO("\t - %s", ipstr); } } char target[ZTS_INET6_ADDRSTRLEN] = { 0 }; char via[ZTS_INET6_ADDRSTRLEN] = { 0 }; DEBUG_INFO("\t- routes:"); for (int i = 0; i < d->route_count; i++) { if (d->routes[i].target.ss_family == ZTS_AF_INET) { struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)&(d->routes[i].target); zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), target, ZTS_INET6_ADDRSTRLEN); in4 = (struct zts_sockaddr_in*)&(d->routes[i].via); zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), via, ZTS_INET6_ADDRSTRLEN); } if (d->routes[i].target.ss_family == ZTS_AF_INET6) { struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&(d->routes[i].target); zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), target, ZTS_INET6_ADDRSTRLEN); in6 = (struct zts_sockaddr_in6*)&(d->routes[i].via); zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), via, ZTS_INET6_ADDRSTRLEN); } DEBUG_INFO("\t - target : %s", target); DEBUG_INFO("\t - via : %s", via); DEBUG_INFO("\t - flags : %d", d->routes[i].flags); DEBUG_INFO("\t - metric : %d", d->routes[i].metric); } } void print_peer_details(const char* msg, zts_peer_info_t* d) { DEBUG_INFO(" %s", msg); if (verbosity < 2) { return; } DEBUG_INFO("\t- peer : %llx", d->peer_id); DEBUG_INFO("\t- role : %d", d->role); DEBUG_INFO("\t- latency : %d", d->latency); DEBUG_INFO("\t- version : %d.%d.%d", d->ver_major, d->ver_minor, d->ver_rev); DEBUG_INFO("\t- path_count : %d", d->path_count); DEBUG_INFO("\t- paths:"); // Print all known paths for each peer for (unsigned int j = 0; j < d->path_count; j++) { char ipstr[ZTS_INET6_ADDRSTRLEN] = { 0 }; int port = 0; struct zts_sockaddr* sa = (struct zts_sockaddr*)&(d->paths[j].address); if (sa->sa_family == ZTS_AF_INET) { struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)sa; zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN); port = ntohs(in4->sin_port); } if (sa->sa_family == ZTS_AF_INET6) { struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)sa; zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN); } DEBUG_INFO("\t - %15s : %6d", ipstr, port); } DEBUG_INFO(""); } void print_netif_details(const char* msg, zts_netif_info_t* d) { DEBUG_INFO(" %s", msg); if (verbosity < 2) { return; } DEBUG_INFO("\t- net_id : %llx", d->net_id); DEBUG_INFO("\t- mac : %llx", d->mac); DEBUG_INFO("\t- mtu : %d", d->mtu); } void print_route_details(const char* msg, zts_route_info_t* d) { DEBUG_INFO("%s", msg); if (verbosity < 2) { return; } } void print_address_details(const char* msg, zts_addr_info_t* d) { DEBUG_INFO(" %s", msg); if (verbosity < 2) { return; } char ipstr[ZTS_INET6_ADDRSTRLEN] = { 0 }; struct zts_sockaddr* sa = (struct zts_sockaddr*)&(d->addr); if (sa->sa_family == ZTS_AF_INET) { struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)&(d->addr); zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN); } if (sa->sa_family == ZTS_AF_INET6) { struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&(d->addr); zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN); } DEBUG_INFO(" network : %llx", d->net_id); DEBUG_INFO(" addr : %s", ipstr); } //----------------------------------------------------------------------------// // Event Handler // //----------------------------------------------------------------------------// #define ZTS_NODE_EVENT(code) code >= ZTS_EVENT_NODE_UP&& code <= ZTS_EVENT_NODE_FATAL_ERROR #define ZTS_NETWORK_EVENT(code) code >= ZTS_EVENT_NETWORK_NOT_FOUND&& code <= ZTS_EVENT_NETWORK_UPDATE #define ZTS_STACK_EVENT(code) code >= ZTS_EVENT_STACK_UP&& code <= ZTS_EVENT_STACK_DOWN #define ZTS_NETIF_EVENT(code) code >= ZTS_EVENT_NETIF_UP&& code <= ZTS_EVENT_NETIF_LINK_DOWN #define ZTS_PEER_EVENT(code) code >= ZTS_EVENT_PEER_DIRECT&& code <= ZTS_EVENT_PEER_PATH_DEAD #define ZTS_ROUTE_EVENT(code) code >= ZTS_EVENT_ROUTE_ADDED&& code <= ZTS_EVENT_ROUTE_REMOVED #define ZTS_ADDR_EVENT(code) code >= ZTS_EVENT_ADDR_ADDED_IP4&& code <= ZTS_EVENT_ADDR_REMOVED_IP6 #define ZTS_STORE_EVENT(code) code >= ZTS_EVENT_STORE_IDENTITY_SECRET&& code <= ZTS_EVENT_STORE_NETWORK void on_zts_event(void* msgPtr) { /* Used to signal that a callback was sent to the user, we test for this value later */ callback_was_called_flag = 1; assert(("msgPtr is null", msgPtr != NULL)); zts_event_msg_t* msg = (zts_event_msg_t*)msgPtr; assert(("Invalid callback event code", msg->event_code > 0)); DEBUG_INFO(" msg->event_code = %d", msg->event_code); if (msg->node) { DEBUG_INFO(" msg->node = %p", (void*)(msg->node)); } if (msg->network) { DEBUG_INFO(" msg->network = %p", (void*)(msg->network)); } if (msg->netif) { DEBUG_INFO(" msg->netif = %p", (void*)(msg->netif)); } if (msg->route) { DEBUG_INFO(" msg->route = %p", (void*)(msg->route)); } if (msg->peer) { DEBUG_INFO(" msg->peer = %p", (void*)(msg->peer)); } if (msg->addr) { DEBUG_INFO(" msg->addr = %p", (void*)(msg->addr)); } // Ensure references to structures are valid when needed assert((msg->node == NULL) ^ (msg->node && ZTS_NODE_EVENT(msg->event_code))); assert((msg->network == NULL) ^ (msg->network && ZTS_NETWORK_EVENT(msg->event_code))); assert((msg->netif == NULL) ^ (msg->netif && ZTS_NETIF_EVENT(msg->event_code))); assert((msg->peer == NULL) ^ (msg->peer && ZTS_PEER_EVENT(msg->event_code))); assert((msg->route == NULL) ^ (msg->route && ZTS_ROUTE_EVENT(msg->event_code))); assert((msg->addr == NULL) ^ (msg->addr && ZTS_ADDR_EVENT(msg->event_code))); assert((msg->cache == NULL) ^ (msg->cache && ZTS_STORE_EVENT(msg->event_code))); // Node events if (msg->event_code == ZTS_EVENT_NODE_UP) { print_node_details("ZTS_EVENT_NODE_UP", msg->node); } if (msg->event_code == ZTS_EVENT_NODE_ONLINE) { print_node_details("ZTS_EVENT_NODE_ONLINE", msg->node); } if (msg->event_code == ZTS_EVENT_NODE_OFFLINE) { print_node_details("ZTS_EVENT_NODE_OFFLINE", msg->node); } if (msg->event_code == ZTS_EVENT_NODE_DOWN) { print_node_details("ZTS_EVENT_NODE_DOWN", msg->node); } if (msg->event_code == ZTS_EVENT_NODE_FATAL_ERROR) { print_node_details("ZTS_EVENT_NODE_FATAL_ERROR", msg->node); } // Network events if (msg->event_code == ZTS_EVENT_NETWORK_NOT_FOUND) { print_net_details("ZTS_EVENT_NETWORK_NOT_FOUND", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_CLIENT_TOO_OLD) { print_net_details("ZTS_EVENT_NETWORK_CLIENT_TOO_OLD", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_REQ_CONFIG) { print_net_details("ZTS_EVENT_NETWORK_REQ_CONFIG", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_OK) { print_net_details("ZTS_EVENT_NETWORK_OK", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_ACCESS_DENIED) { print_net_details("ZTS_EVENT_NETWORK_ACCESS_DENIED", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_READY_IP6) { print_net_details("ZTS_EVENT_NETWORK_READY_IP6", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_READY_IP4) { print_net_details("ZTS_EVENT_NETWORK_READY_IP4", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_READY_IP4_IP6) { print_net_details("ZTS_EVENT_NETWORK_READY_IP4_IP6", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_DOWN) { print_net_details("ZTS_EVENT_NETWORK_DOWN", msg->network); } if (msg->event_code == ZTS_EVENT_NETWORK_UPDATE) { print_net_details("ZTS_EVENT_NETWORK_UPDATE", msg->network); } // Stack events if (msg->event_code == ZTS_EVENT_STACK_UP) { // print_stack_details("ZTS_EVENT_STACK_UP", msg->stack); } if (msg->event_code == ZTS_EVENT_STACK_DOWN) { // print_stack_details("ZTS_EVENT_STACK_DOWN", msg->stack); } // Netif events if (msg->event_code == ZTS_EVENT_NETIF_UP) { print_netif_details("ZTS_EVENT_NETIF_UP", msg->netif); } if (msg->event_code == ZTS_EVENT_NETIF_DOWN) { print_netif_details("ZTS_EVENT_NETIF_DOWN", msg->netif); } if (msg->event_code == ZTS_EVENT_NETIF_REMOVED) { print_netif_details("ZTS_EVENT_NETIF_REMOVED", msg->netif); } if (msg->event_code == ZTS_EVENT_NETIF_LINK_UP) { print_netif_details("ZTS_EVENT_NETIF_LINK_UP", msg->netif); } if (msg->event_code == ZTS_EVENT_NETIF_LINK_DOWN) { print_netif_details("ZTS_EVENT_NETIF_LINK_DOWN", msg->netif); } // Peer events if (msg->peer) { if (msg->peer->role == ZTS_PEER_ROLE_PLANET) { /* Safe to ignore, these are our roots. They orchestrate the P2P connection. You might also see other unknown peers, these are our network controllers. */ return; } } if (msg->event_code == ZTS_EVENT_PEER_DIRECT) { print_peer_details("ZTS_EVENT_PEER_DIRECT", msg->peer); } if (msg->event_code == ZTS_EVENT_PEER_RELAY) { print_peer_details("ZTS_EVENT_PEER_RELAY", msg->peer); } if (msg->event_code == ZTS_EVENT_PEER_UNREACHABLE) { print_peer_details("ZTS_EVENT_PEER_UNREACHABLE", msg->peer); } if (msg->event_code == ZTS_EVENT_PEER_PATH_DISCOVERED) { print_peer_details("ZTS_EVENT_PEER_PATH_DISCOVERED", msg->peer); } if (msg->event_code == ZTS_EVENT_PEER_PATH_DEAD) { print_peer_details("ZTS_EVENT_PEER_PATH_DEAD", msg->peer); } // Route events if (msg->event_code == ZTS_EVENT_ROUTE_ADDED) { print_route_details("ZTS_EVENT_ROUTE_ADDED", msg->route); } if (msg->event_code == ZTS_EVENT_ROUTE_REMOVED) { print_route_details("ZTS_EVENT_ROUTE_REMOVED", msg->route); } // Address events if (msg->event_code == ZTS_EVENT_ADDR_ADDED_IP4) { print_address_details("ZTS_EVENT_ADDR_ADDED_IP4", msg->addr); } if (msg->event_code == ZTS_EVENT_ADDR_ADDED_IP6) { print_address_details("ZTS_EVENT_ADDR_ADDED_IP6", msg->addr); } if (msg->event_code == ZTS_EVENT_ADDR_REMOVED_IP4) { print_address_details("ZTS_EVENT_ADDR_REMOVED_IP4", msg->addr); } if (msg->event_code == ZTS_EVENT_ADDR_REMOVED_IP6) { print_address_details("ZTS_EVENT_ADDR_REMOVED_IP6", msg->addr); } // Cache events if (msg->event_code == ZTS_EVENT_STORE_IDENTITY_PUBLIC) { DEBUG_INFO("ZTS_EVENT_STORE_IDENTITY_PUBLIC (len=%d)", msg->len); } if (msg->event_code == ZTS_EVENT_STORE_IDENTITY_SECRET) { DEBUG_INFO("ZTS_EVENT_STORE_IDENTITY_SECRET (len=%d)", msg->len); } if (msg->event_code == ZTS_EVENT_STORE_PLANET) { DEBUG_INFO("ZTS_EVENT_STORE_PLANET (len=%d)", msg->len); } if (msg->event_code == ZTS_EVENT_STORE_PEER) { DEBUG_INFO("ZTS_EVENT_STORE_PEER (len=%d)", msg->len); } if (msg->event_code == ZTS_EVENT_STORE_NETWORK) { DEBUG_INFO("ZTS_EVENT_STORE_NETWORK (len=%d)", msg->len); } DEBUG_INFO(""); } void api_value_arg_test(int tid, uint8_t num, int8_t i8, int16_t i16, int32_t i32, int64_t i64, void* nullable) { DEBUG_INFO( "fuzzing values: thr = %10d, func [ %3d ] (%4d, %7d, %12d, %32lld, %p)", tid, num, i8, i16, i32, i64, nullable); int res = ZTS_ERR_OK; // Test uninitialized Network Stack API usage /* res = zts_get_all_stats((struct zts_stats *)nullable); assert(("pre-init call to zts_get_all_stats(): res != ZTS_ERR_SERVICE", res == ZTS_ERR_SERVICE)); res = zts_get_protocol_stats(i32, nullable); assert(("pre-init call to zts_get_protocol_stats(): res != ZTS_ERR_SERVICE", res == ZTS_ERR_SERVICE)); */ res = zts_dns_set_server(i8, (const zts_ip_addr*)nullable); assert(("pre-init call to zts_add_dns_nameserver(): res != ZTS_ERR_SERVICE", res == ZTS_ERR_SERVICE)); const zts_ip_addr* res_ptr = zts_dns_get_server(i8); assert(("pre-init call to zts_del_dns_nameserver(): res != ZTS_ERR_SERVICE", res == ZTS_ERR_SERVICE)); struct zts_sockaddr* null_addr = (struct zts_sockaddr*)nullable; struct zts_sockaddr_storage* null_addr_ss = (struct zts_sockaddr_storage*)nullable; zts_socklen_t* null_len = (zts_socklen_t*)nullable; zts_fd_set* null_fd_set = (zts_fd_set*)nullable; zts_timeval* null_timeval = (zts_timeval*)nullable; // Test uninitialized control API usage (Node) switch (num) { // // Central // /* case 1: assert(zts_central_set_access_mode(i8) == ZTS_ERR_SERVICE); break; case 2: assert(zts_central_set_verbose(i8) == ZTS_ERR_SERVICE); break; case 3: assert(zts_central_clear_resp_buf() == ZTS_ERR_SERVICE); break; case 4: assert(zts_central_init(const NULL, const NULL, NULL, i32) == ZTS_ERR_SERVICE); break; case 5: assert(zts_central_cleanup() == ZTS_ERR_SERVICE); break; case 6: assert(zts_central_get_last_resp_buf(NULL, i32) == ZTS_ERR_SERVICE); break; case 7: assert(zts_central_status_get(NULL) == ZTS_ERR_SERVICE); break; case 8: assert(zts_central_self_get(NULL) == ZTS_ERR_SERVICE); break; case 9: assert(zts_central_net_get(NULL, i64) == ZTS_ERR_SERVICE); break; case 10: assert(zts_central_net_update(NULL, i64) == ZTS_ERR_SERVICE); break; case 11: assert(zts_central_net_delete(NULL, i64) == ZTS_ERR_SERVICE); break; case 12: assert(zts_central_net_get_all(NULL) == ZTS_ERR_SERVICE); break; case 13: assert(zts_central_member_get(NULL, i64, i64) == ZTS_ERR_SERVICE); break; case 14: assert(zts_central_member_update(NULL, i64, i64, NULL) == ZTS_ERR_SERVICE); break; case 15: assert(zts_central_node_auth(NULL, i64, i64, i8) == ZTS_ERR_SERVICE); break; case 16: assert(zts_central_net_get_members(NULL, i64) == ZTS_ERR_SERVICE); break; */ // // Id (tested in separate section) // /* case 20: assert(zts_id_new(NULL, NULL) == ZTS_ERR_SERVICE); break; case 21: assert(zts_id_pair_is_valid(NULL, i32) == ZTS_ERR_SERVICE); break; */ // // Init // /* int res = 0; case 30: assert(zts_init_from_storage(NULL) == ZTS_ERR_OK); break; case 31: assert(zts_init_from_memory(NULL, i16) == ZTS_ERR_OK); break; case 32: assert(zts_init_set_event_handler(NULL) == ZTS_ERR_SERVICE); break; case 33: assert(zts_init_blacklist_if(NULL, i32) == ZTS_ERR_SERVICE); break; case 34: assert(zts_init_set_roots(NULL, i32) == ZTS_ERR_SERVICE); break; case 35: assert(zts_init_set_port(i16) == ZTS_ERR_SERVICE); break; case 36: assert(zts_init_allow_net_cache(i32) == ZTS_ERR_SERVICE); break; case 37: assert(zts_init_allow_peer_cache(i32) == ZTS_ERR_SERVICE); break; */ // // Address // case 40: assert(zts_addr_is_assigned(i64, i32) == 0); break; case 41: assert(zts_addr_get(i64, i32, null_addr_ss) == ZTS_ERR_SERVICE); break; /* case 42: assert(zts_addr_get_str(i64, i32, NULL, i32) == ZTS_ERR_SERVICE); break; */ case 43: assert(zts_addr_get_all(i64, null_addr_ss, NULL) == ZTS_ERR_SERVICE); break; /* case 44: assert(zts_addr_compute_6plane(i64, i64, null_addr) == ZTS_ERR_SERVICE); break; case 45: assert(zts_addr_compute_rfc4193(i64, i64, null_addr) == ZTS_ERR_SERVICE); break; case 46: assert(zts_addr_compute_rfc4193_str(i64, i64, NULL, i32) == ZTS_ERR_SERVICE); break; case 47: assert(zts_addr_compute_6plane_str(i64, i64, NULL, i32) == ZTS_ERR_SERVICE); break; // // Network // case 50: assert(zts_net_compute_adhoc_id(i16, i16) == ZTS_ERR_SERVICE); break; */ case 51: assert(zts_net_join(i64) == ZTS_ERR_SERVICE); break; case 52: assert(zts_net_leave(i64) == ZTS_ERR_SERVICE); break; // case 53: // assert(zts_net_count() == ZTS_ERR_SERVICE); // break; case 54: assert(zts_net_get_mac(i64) == ZTS_ERR_SERVICE); break; case 55: assert(zts_net_get_mac_str(i64, NULL, i32) == ZTS_ERR_SERVICE); break; case 56: assert(zts_net_get_broadcast(i64) == ZTS_ERR_SERVICE); break; case 57: assert(zts_net_get_mtu(i64) == ZTS_ERR_SERVICE); break; case 58: assert(zts_net_get_name(i64, NULL, i32) == ZTS_ERR_SERVICE); break; case 59: assert(zts_net_get_status(i64) == ZTS_ERR_SERVICE); break; case 60: assert(zts_net_get_type(i64) == ZTS_ERR_SERVICE); break; // Route case 80: assert(zts_route_is_assigned(i64, i32) == ZTS_ERR_SERVICE); break; // Node /* case 90: assert(zts_node_start() == ZTS_ERR_SERVICE); break; */ case 91: assert(zts_node_is_online() == 0); break; case 92: assert(zts_node_get_id() == ZTS_ERR_SERVICE); break; case 93: assert(zts_node_get_id_pair(NULL, NULL) == ZTS_ERR_SERVICE); break; case 94: assert(zts_node_get_port() == ZTS_ERR_SERVICE); break; case 95: assert(zts_node_stop() == ZTS_ERR_SERVICE); break; // case 96: // assert(zts_node_restart() == ZTS_ERR_SERVICE); break; case 97: assert(zts_node_free() == ZTS_ERR_SERVICE); break; // // Moon // /* case 100: assert(zts_moon_orbit(i64, i64) == ZTS_ERR_SERVICE); break; case 101: assert(zts_moon_deorbit(i64) == ZTS_ERR_SERVICE); break; */ // // Utility // // case 110: // assert(zts_util_delay(i64) == ZTS_ERR_SERVICE); // break; // Socket case 120: assert(zts_bsd_socket(i32, i32, i32) == ZTS_ERR_SERVICE); break; case 121: assert(zts_bsd_connect(i32, null_addr, i32) == ZTS_ERR_SERVICE); break; case 122: assert(zts_connect(i32, NULL, i32, i32) == ZTS_ERR_SERVICE); break; case 123: assert(zts_bsd_bind(i32, null_addr, i32) == ZTS_ERR_SERVICE); break; case 124: assert(zts_bind(i32, NULL, i32) == ZTS_ERR_SERVICE); break; case 125: assert(zts_bsd_listen(i32, i32) == ZTS_ERR_SERVICE); break; case 126: assert(zts_bsd_accept(i32, null_addr, NULL) == ZTS_ERR_SERVICE); break; case 127: assert(zts_accept(i32, NULL, i32, NULL) == ZTS_ERR_SERVICE); break; case 128: assert(zts_bsd_setsockopt(i32, i32, i32, NULL, i32) == ZTS_ERR_SERVICE); break; case 129: assert(zts_bsd_getsockopt(i32, i32, i32, NULL, NULL) == ZTS_ERR_SERVICE); break; case 130: assert(zts_bsd_getsockname(i32, null_addr, NULL) == ZTS_ERR_SERVICE); break; case 131: assert(zts_bsd_getpeername(i32, null_addr, NULL) == ZTS_ERR_SERVICE); break; case 132: assert(zts_bsd_close(i32) == ZTS_ERR_SERVICE); break; case 133: assert(zts_bsd_select(i32, NULL, NULL, NULL, NULL) == ZTS_ERR_SERVICE); break; case 134: assert(zts_bsd_fcntl(i32, i32, i32) == ZTS_ERR_SERVICE); break; case 135: assert(zts_bsd_poll(NULL, (zts_nfds_t)NULL, i32) == ZTS_ERR_SERVICE); break; case 136: assert(zts_bsd_ioctl(i32, i64, NULL) == ZTS_ERR_SERVICE); break; case 137: assert(zts_bsd_send(i32, NULL, i32, i32) == ZTS_ERR_SERVICE); break; case 138: assert(zts_bsd_sendto(i32, NULL, i32, i32, null_addr, i32) == ZTS_ERR_SERVICE); break; case 139: assert(zts_bsd_sendmsg(i32, NULL, i32) == ZTS_ERR_SERVICE); break; case 140: assert(zts_bsd_recv(i32, NULL, i32, i32) == ZTS_ERR_SERVICE); break; case 141: assert(zts_bsd_recvfrom(i32, NULL, i32, i32, null_addr, NULL) == ZTS_ERR_SERVICE); break; case 142: assert(zts_bsd_recvmsg(i32, NULL, i32) == ZTS_ERR_SERVICE); break; case 143: assert(zts_bsd_read(i32, NULL, i32) == ZTS_ERR_SERVICE); break; case 144: assert(zts_bsd_readv(i32, NULL, i32) == ZTS_ERR_SERVICE); break; case 145: assert(zts_bsd_write(i32, NULL, i32) == ZTS_ERR_SERVICE); break; case 146: assert(zts_bsd_writev(i32, nullable, i32) == ZTS_ERR_SERVICE); break; case 147: assert(zts_bsd_shutdown(i32, i32) == ZTS_ERR_SERVICE); break; case 148: assert(zts_set_no_delay(i32, i32) == ZTS_ERR_SERVICE); break; case 149: assert(zts_get_no_delay(i32) == ZTS_ERR_SERVICE); break; case 150: assert(zts_set_linger(i32, i32, i32) == ZTS_ERR_SERVICE); break; case 151: assert(zts_get_linger_value(i32) == ZTS_ERR_SERVICE); break; case 152: assert(zts_get_linger_value(i32) == ZTS_ERR_SERVICE); break; case 153: assert(zts_set_reuse_addr(i32, i32) == ZTS_ERR_SERVICE); break; case 154: assert(zts_get_reuse_addr(i32) == ZTS_ERR_SERVICE); break; case 155: assert(zts_set_recv_timeout(i32, i32, i32) == ZTS_ERR_SERVICE); break; case 156: assert(zts_get_recv_timeout(i32) == ZTS_ERR_SERVICE); break; case 157: assert(zts_set_send_timeout(i32, i32, i32) == ZTS_ERR_SERVICE); break; case 158: assert(zts_get_send_timeout(i32) == ZTS_ERR_SERVICE); break; case 159: assert(zts_set_send_buf_size(i32, i32) == ZTS_ERR_SERVICE); break; case 160: assert(zts_get_send_buf_size(i32) == ZTS_ERR_SERVICE); break; case 161: assert(zts_set_recv_buf_size(i32, i32) == ZTS_ERR_SERVICE); break; case 162: assert(zts_get_recv_buf_size(i32) == ZTS_ERR_SERVICE); break; case 163: assert(zts_set_ttl(i32, i32) == ZTS_ERR_SERVICE); break; case 164: assert(zts_get_ttl(i32) == ZTS_ERR_SERVICE); break; case 165: assert(zts_set_blocking(i32, i32) == ZTS_ERR_SERVICE); break; case 166: assert(zts_get_blocking(i32) == ZTS_ERR_SERVICE); break; case 167: assert(zts_set_keepalive(i32, i32) == ZTS_ERR_SERVICE); break; case 168: assert(zts_get_keepalive(i32) == ZTS_ERR_SERVICE); break; case 169: assert(zts_bsd_gethostbyname(NULL) == NULL); break; case 170: assert(zts_dns_set_server(i8, null_addr) == ZTS_ERR_SERVICE); break; case 171: assert(zts_dns_get_server(i8) == NULL); break; /* case 172: assert(zts_ipaddr_ntoa(null_addr) == NULL); break; case 173: assert(zts_ipaddr_aton(NULL, NULL) == ZTS_ERR_SERVICE); break; case 174: assert(zts_inet_ntop(i32, NULL, NULL, i32) == NULL); break; case 175: assert(zts_inet_pton(i32, NULL, NULL) == ZTS_ERR_SERVICE); break; case 176: assert(zts_util_ipstr_to_saddr(i32, NULL, i32, null_addr, NULL) == ZTS_ERR_SERVICE); break; */ default: break; } } #define FUZZ_NUM 128 void test_pre_service_fuzz() { DEBUG_INFO("\n\n***\ttest_pre_service_fuzz"); unsigned int tid = (unsigned int)pthread_self(); // Test service-related API functions before initializing service // Test null values in sequential order for (int i = 0; i < FUZZ_NUM; i++) { api_value_arg_test(tid, i, 0, 0, 0, 0, NULL); } // Test all null values in random order (delayed) for (int i = 0; i < FUZZ_NUM; i++) { uint8_t delay = (uint8_t)random64(); uint8_t num = (uint8_t)random64(); zts_util_delay(delay / 16); api_value_arg_test(tid, num, 0, 0, 0, 0, NULL); } // Test random values in random order (delayed) for (int i = 0; i < FUZZ_NUM; i++) { uint8_t delay = (uint8_t)random64(); uint8_t num = (uint8_t)random64(); int8_t i8 = (uint8_t)random64(); int16_t i16 = (uint16_t)random64(); int32_t i32 = (uint32_t)random64(); int64_t i64 = (uint64_t)random64(); int x; void* nullable = &x; zts_util_delay(delay / 16); api_value_arg_test(tid, num, i8, i16, i32, i64, nullable); } // Test all null values in random order (no delay) for (int i = 0; i < FUZZ_NUM; i++) { uint8_t num = (uint8_t)random64(); api_value_arg_test(tid, num, 0, 0, 0, 0, NULL); } // Test random values in random order (no delay) for (int i = 0; i < FUZZ_NUM; i++) { uint8_t num = (uint8_t)random64(); int8_t i8 = (uint8_t)random64(); int16_t i16 = (uint16_t)random64(); int32_t i32 = (uint32_t)random64(); int64_t i64 = (uint64_t)random64(); int x; void* nullable = &x; api_value_arg_test(tid, num, i8, i16, i32, i64, nullable); } // Test non-service helper functions // (B) Test zts_inet_ntop char ipstr[ZTS_INET6_ADDRSTRLEN] = { 0 }; int16_t port = 0; struct zts_sockaddr_in in4; in4.sin_port = htons(8080); #if defined(_WIN32) zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.S_addr)); #else zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.s_addr)); #endif in4.sin_family = ZTS_AF_INET; struct zts_sockaddr* sa = (struct zts_sockaddr*)&in4; if (sa->sa_family == ZTS_AF_INET) { struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)sa; zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN); port = ntohs(in4->sin_port); } if (sa->sa_family == ZTS_AF_INET6) { struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)sa; zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN); } assert(port == 8080); assert(! strcmp(ipstr, "192.168.22.1")); // (C) Test zts_inet_pton uint8_t buf[sizeof(struct zts_in6_addr)] = { 0 }; char str[ZTS_INET6_ADDRSTRLEN] = { 0 }; zts_inet_pton(ZTS_AF_INET, "192.168.22.2", buf); zts_inet_ntop(ZTS_AF_INET, buf, str, ZTS_INET6_ADDRSTRLEN); assert(! strcmp(str, "192.168.22.2")); } void test_sockets() { int res = ZTS_ERR_OK; // Test simplified API, proxy for setsockopt/getsockopt/ioctl etc. int s4 = zts_bsd_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0); assert(s4 >= 0); // TCP_NODELAY // Check value before doing anything assert(zts_get_no_delay(s4) == 0); // Turn on assert(zts_set_no_delay(s4, 1) == ZTS_ERR_OK); // Should return value instead of error code assert(zts_get_no_delay(s4) == 1); // Turn off assert(zts_set_no_delay(s4, 0) == ZTS_ERR_OK); assert(zts_get_no_delay(s4) == ZTS_ERR_OK); // SO_LINGER // Check value before doing anything assert(zts_get_linger_enabled(s4) == 0); assert(zts_get_linger_value(s4) == 0); // Turn on, set to 7 seconds assert(zts_set_linger(s4, 1, 7) == ZTS_ERR_OK); assert(zts_get_linger_enabled(s4) == 1); assert(zts_get_linger_value(s4) == 7); assert(zts_set_linger(s4, 0, 0) == ZTS_ERR_OK); // Turn off assert(zts_get_linger_enabled(s4) == 0); assert(zts_get_linger_value(s4) == 0); // SO_REUSEADDR // Check value before doing anything assert(zts_get_reuse_addr(s4) == 0); // Turn on assert(zts_set_reuse_addr(s4, 1) == ZTS_ERR_OK); // Should return value instead of error code assert(zts_get_reuse_addr(s4) == 1); // Turn off assert(zts_set_reuse_addr(s4, 0) == ZTS_ERR_OK); assert(zts_get_reuse_addr(s4) == ZTS_ERR_OK); // SO_RCVTIMEO // Check value before doing anything assert(zts_get_recv_timeout(s4) == 0); // Set to value assert(zts_set_recv_timeout(s4, 3, 0) == ZTS_ERR_OK); assert(zts_get_recv_timeout(s4) == 3); assert(zts_set_recv_timeout(s4, 0, 0) == ZTS_ERR_OK); // Set to zero assert(zts_get_recv_timeout(s4) == 0); // SO_SNDTIMEO // Check value before doing anything assert(zts_get_send_timeout(s4) == 0); // Set to value assert(zts_set_send_timeout(s4, 4, 0) == ZTS_ERR_OK); assert(zts_get_send_timeout(s4) == 4); assert(zts_set_send_timeout(s4, 0, 0) == ZTS_ERR_OK); // Set to zero assert(zts_get_send_timeout(s4) == 0); // SO_SNDBUF // Check value before doing anything assert(zts_get_send_buf_size(s4) == -1); // Unimplemented // Set to 7 seconds assert(zts_set_send_buf_size(s4, 1024) == ZTS_ERR_OK); assert(zts_get_send_buf_size(s4) == -1); // Unimplemented assert(zts_set_send_buf_size(s4, 0) == ZTS_ERR_OK); // Set to zero assert(zts_get_send_buf_size(s4) == -1); // Unimplemented // SO_RCVBUF // Check value before doing anything assert(zts_get_recv_buf_size(s4) > 0); // Set to value assert(zts_set_recv_buf_size(s4, 1024) == ZTS_ERR_OK); assert(zts_get_recv_buf_size(s4) == 1024); assert(zts_set_recv_buf_size(s4, 0) == ZTS_ERR_OK); // Set to zero assert(zts_get_recv_buf_size(s4) == 0); // IP_TTL // Check value before doing anything assert(zts_get_ttl(s4) == 255); // Defaults to max // Set to value assert(zts_set_ttl(s4, 128) == ZTS_ERR_OK); assert(zts_get_ttl(s4) == 128); assert(zts_set_ttl(s4, 0) == ZTS_ERR_OK); // Set to zero assert(zts_get_ttl(s4) == 0); // O_NONBLOCK // Check value before doing anything assert(zts_get_blocking(s4) == 1); // Turn off (non-blocking) assert(zts_set_blocking(s4, 0) == ZTS_ERR_OK); // Should return value instead of error code assert(zts_get_blocking(s4) == 0); // Turn off assert(zts_set_blocking(s4, 1) == ZTS_ERR_OK); assert(zts_get_blocking(s4) == 1); // SO_KEEPALIVE // Check value before doing anything assert(zts_get_keepalive(s4) == 0); // Turn on assert(zts_set_keepalive(s4, 1) == ZTS_ERR_OK); // Should return value instead of error code assert(zts_get_keepalive(s4) == 1); // Turn off assert(zts_set_keepalive(s4, 0) == ZTS_ERR_OK); assert(zts_get_keepalive(s4) == ZTS_ERR_OK); // TODO // char peername[ZTS_INET6_ADDRSTRLEN] = { 0 }; // int port = 0; // int res = zts_getpeername(accfd, peername, ZTS_INET6_ADDRSTRLEN, &port); // printf("getpeername = %s : %d (%d)\n", peername, port, res); // res = zts_getsockname(accfd, peername, ZTS_INET6_ADDRSTRLEN, &port); // printf("getsockname = %s : %d (%d)\n", peername, port, res); // Test DNS client functionality /* // Set first nameserver char *ns1_addr_str = "FCC5:205E:4FF5:5311:DFF0::1"; zts_ip_addr ns1; zts_ipaddr_aton(ns1_addr_str, &ns1); zts_dns_set_server(0, &ns1); // Get first nameserver const zts_ip_addr *ns1_result; ns1_result = zts_dns_get_server(0); DEBUG_INFO("dns1 = %s", zts_ipaddr_ntoa(ns1_result)); // Set second nameserver char *ns2_addr_str = "192.168.22.1"; zts_ip_addr ns2; zts_ipaddr_aton(ns2_addr_str, &ns2); zts_dns_set_server(1, &ns2); // Get second nameserver const zts_ip_addr *ns2_result; ns2_result = zts_dns_get_server(1); DEBUG_INFO("dns1 = %s", zts_ipaddr_ntoa(ns2_result)); // Check that each nameserver address was properly set and get assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns1_addr_str, zts_ipaddr_ntoa(ns1_result)))); assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns2_addr_str, zts_ipaddr_ntoa(ns2_result)))); */ // Test shutting down the service zts_node_stop(); s4 = zts_bsd_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); assert(s4 == ZTS_ERR_SERVICE); } //----------------------------------------------------------------------------// // Server // //----------------------------------------------------------------------------// #define MAX_CONNECT_TIME 60 // outer re-attempt loop #define CONNECT_TIMEOUT 30 // zts_connect, ms #define BUFLEN 128 char* msg = "welcome to the machine"; void test_server_socket_usage(uint16_t port4, uint16_t port6) { int err = ZTS_ERR_OK; int bytes_read = 0; int bytes_sent = 0; int msglen = strlen(msg); char dstbuf[BUFLEN] = { 0 }; int buflen = BUFLEN; struct timespec start, now; int time_diff = 0; // IPv4 test DEBUG_INFO("server4: will listen on: 0.0.0.0:%d", port4); int s4 = zts_bsd_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); assert(s4 == 0 && zts_errno == 0); err = zts_bind(s4, "0.0.0.0", port4); assert(err == ZTS_ERR_OK && zts_errno == 0); err = zts_bsd_listen(s4, 1); assert(err == ZTS_ERR_OK && zts_errno == 0); struct zts_sockaddr_in in4; zts_socklen_t addrlen4 = sizeof(in4); int acc4 = -1; clock_gettime(CLOCK_MONOTONIC, &start); do { DEBUG_INFO("server4: accepting..."); acc4 = zts_bsd_accept(s4, &in4, &addrlen4); zts_util_delay(250); clock_gettime(CLOCK_MONOTONIC, &now); time_diff = (now.tv_sec - start.tv_sec); } while (err < 0 && time_diff < MAX_CONNECT_TIME); assert(acc4 == 1 && zts_errno == 0); // Read message memset(dstbuf, 0, buflen); // Test zts_get_data_available while (1) { int av = zts_get_data_available(acc4); zts_util_delay(50); if (av > 0) { break; } } bytes_read = zts_bsd_read(acc4, dstbuf, buflen); DEBUG_INFO("server4: read (%d) bytes", bytes_read); assert(bytes_read == msglen && zts_errno == 0); // Send message bytes_sent = zts_bsd_write(acc4, msg, msglen); DEBUG_INFO("server4: wrote (%d) bytes", bytes_sent); assert(bytes_sent == msglen && zts_errno == 0); zts_bsd_close(s4); assert(err == ZTS_ERR_OK && zts_errno == 0); zts_bsd_close(acc4); assert(err == ZTS_ERR_OK && zts_errno == 0); assert(bytes_sent == bytes_read); if (bytes_sent == bytes_read) { DEBUG_INFO("server4: Test OK"); } else { DEBUG_INFO("server4: Test FAIL"); } // IPv6 test DEBUG_INFO("server6: will listen on: [::]:%d", port6); int s6 = zts_bsd_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0); assert(s6 == 0 && zts_errno == 0); err = zts_bind(s6, "::", port6); assert(err == ZTS_ERR_OK && zts_errno == 0); err = zts_bsd_listen(s6, 1); assert(err == ZTS_ERR_OK && zts_errno == 0); struct zts_sockaddr_in6 in6; zts_socklen_t addrlen6 = sizeof(in6); int acc6 = -1; clock_gettime(CLOCK_MONOTONIC, &start); do { DEBUG_INFO("server6: accepting..."); acc6 = zts_bsd_accept(s6, &in6, &addrlen6); zts_util_delay(250); clock_gettime(CLOCK_MONOTONIC, &now); time_diff = (now.tv_sec - start.tv_sec); } while (err < 0 && time_diff < MAX_CONNECT_TIME); DEBUG_INFO("server6: accepted connection (fd=%d)", acc6); assert(acc6 == 1 && zts_errno == 0); // Read message memset(dstbuf, 0, buflen); bytes_read = zts_bsd_read(acc6, dstbuf, buflen); DEBUG_INFO("server6: read (%d) bytes", bytes_read); assert(bytes_read == msglen && zts_errno == 0); // Send message bytes_sent = zts_bsd_write(acc6, msg, msglen); DEBUG_INFO("server6: wrote (%d) bytes", bytes_sent); assert(bytes_sent == msglen && zts_errno == 0); zts_bsd_close(s6); assert(err == ZTS_ERR_OK && zts_errno == 0); zts_bsd_close(acc6); assert(err == ZTS_ERR_OK && zts_errno == 0); zts_node_stop(); assert(err == ZTS_ERR_OK && zts_errno == 0); int s = zts_bsd_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); assert(s == ZTS_ERR_SERVICE); assert(bytes_sent == bytes_read); if (bytes_sent == bytes_read) { DEBUG_INFO("server6: Test OK"); } else { DEBUG_INFO("server6: Test FAIL"); } } //----------------------------------------------------------------------------// // Client // //----------------------------------------------------------------------------// void test_client_socket_usage(char* ip4, uint16_t port4, char* ip6, uint16_t port6) { int err = ZTS_ERR_OK; int bytes_read = 0; int bytes_sent = 0; int msglen = strlen(msg); char dstbuf[BUFLEN] = { 0 }; int buflen = BUFLEN; struct timespec start, now; int time_diff = 0; // IPv4 test err = ZTS_ERR_OK; int s4 = zts_bsd_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); assert(err == ZTS_ERR_OK && zts_errno == 0); zts_set_blocking(s4, 1); assert(err == ZTS_ERR_OK && zts_errno == 0); clock_gettime(CLOCK_MONOTONIC, &start); do { DEBUG_INFO("client4: connecting to: %s:%d", ip4, port4); err = zts_connect(s4, ip4, port4, CONNECT_TIMEOUT); zts_util_delay(500); clock_gettime(CLOCK_MONOTONIC, &now); time_diff = (now.tv_sec - start.tv_sec); } while (err < 0 && time_diff < MAX_CONNECT_TIME); assert(err == ZTS_ERR_OK && zts_errno == 0); DEBUG_INFO("client4: connected"); // Send message bytes_sent = zts_bsd_write(s4, msg, msglen); DEBUG_INFO("client4: wrote (%d) bytes", bytes_sent); assert(bytes_sent == msglen && zts_errno == 0); // Read message memset(dstbuf, 0, buflen); bytes_read = zts_bsd_read(s4, dstbuf, buflen); assert(bytes_read == msglen && zts_errno == 0); DEBUG_INFO("client4: read (%d) bytes", bytes_read); assert(bytes_sent == bytes_read && zts_errno == 0); zts_bsd_close(s4); assert(err == ZTS_ERR_OK && zts_errno == 0); assert(bytes_sent == bytes_read); if (bytes_sent == bytes_read) { DEBUG_INFO("client4: Test OK"); } else { DEBUG_INFO("client4: Test FAIL"); } // IPv6 test err = ZTS_ERR_OK; int s6 = zts_bsd_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0); assert(err == ZTS_ERR_OK && zts_errno == 0); zts_set_blocking(s6, 1); assert(err == ZTS_ERR_OK && zts_errno == 0); clock_gettime(CLOCK_MONOTONIC, &start); do { DEBUG_INFO("client6: connecting to: %s:%d", ip6, port6); err = zts_connect(s6, ip6, port6, CONNECT_TIMEOUT); zts_util_delay(500); clock_gettime(CLOCK_MONOTONIC, &now); time_diff = (now.tv_sec - start.tv_sec); } while (err < 0 && time_diff < MAX_CONNECT_TIME); assert(err == ZTS_ERR_OK && zts_errno == 0); DEBUG_INFO("client6: connected"); // Send message bytes_sent = zts_bsd_write(s6, msg, msglen); DEBUG_INFO("client6: wrote (%d) bytes", bytes_sent); assert(bytes_sent == msglen && zts_errno == 0); // Read message memset(dstbuf, 0, buflen); bytes_read = zts_bsd_read(s6, dstbuf, buflen); assert(bytes_read == msglen && zts_errno == 0); DEBUG_INFO("client6: read (%d) bytes", bytes_read); assert(bytes_sent == bytes_read && zts_errno == 0); zts_bsd_close(s6); assert(err == ZTS_ERR_OK && zts_errno == 0); zts_node_stop(); assert(err == ZTS_ERR_OK && zts_errno == 0); int s = zts_bsd_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); assert(s == ZTS_ERR_SERVICE); assert(bytes_sent == bytes_read); if (bytes_sent == bytes_read) { DEBUG_INFO("client6: Test OK"); } else { DEBUG_INFO("client6: Test FAIL"); } } //----------------------------------------------------------------------------// // Start node // //----------------------------------------------------------------------------// int test_api_abuse() { /* TODO DEBUG_INFO("\n\n***\ttest_api_abuse"); if (join_network) { for (int i = 0; i < 1024 * 4; i++) { printf("join %d\n", i); zts_net_join(net_id); printf("leave %d\n", i); zts_net_leave(net_id); } zts_node_stop(); zts_util_delay(2000); exit(0); } */ return 0; } int test_start_node( char* path, uint64_t net_id, char* keypair, int use_storage, int use_callbacks, int use_identity, int join_network, int shutdown) { DEBUG_INFO("\n\n***\ttest_start_node"); struct timespec start, now; int time_diff = 0; zts_util_delay(5000); // Allow events to settle (if any) callback_was_called_flag = 0; // Reset DEBUG_INFO("starting node..."); clock_gettime(CLOCK_MONOTONIC, &start); int res = ZTS_ERR_OK; // Optional initialization if (use_storage) { assert(zts_init_from_storage(path) == ZTS_ERR_OK); } if (use_callbacks) { assert(zts_init_set_event_handler(&on_zts_event) == ZTS_ERR_OK); } if (use_identity) { // TODO: tomorrow assert(zts_init_from_memory(keypair, ZTS_ID_STR_BUF_LEN) == ZTS_ERR_OK); } // Start assert(zts_node_start() == ZTS_ERR_OK); do { zts_util_delay(25); clock_gettime(CLOCK_MONOTONIC, &now); time_diff = (now.tv_sec - start.tv_sec); } while (! zts_node_is_online() && (time_diff < MAX_CONNECT_TIME)); if (! zts_node_is_online()) { DEBUG_INFO("Node failed to come online"); exit(-1); } // Test identity handling char keypair_i[ZTS_ID_STR_BUF_LEN] = { 0 }; unsigned int keypair_len = ZTS_ID_STR_BUF_LEN; assert(zts_node_get_id_pair(keypair_i, &keypair_len) == ZTS_ERR_OK); DEBUG_INFO("Checking key length"); assert(keypair_len <= ZTS_ID_STR_BUF_LEN); DEBUG_INFO("GET [identity = %s]", keypair_i); DEBUG_INFO("Checking validity of identity"); assert(zts_id_pair_is_valid(keypair_i, ZTS_ID_STR_BUF_LEN) == 1); // Test various getters assert(zts_node_get_id() != 0); DEBUG_INFO("GET [id: %llx]", zts_node_get_id()); assert(zts_node_get_port() > 0); DEBUG_INFO("GET [port: %d]", zts_node_get_port()); if (join_network) { DEBUG_INFO("Joining: %llx", net_id); clock_gettime(CLOCK_MONOTONIC, &start); if (net_id) { zts_net_join(net_id); do { zts_util_delay(25); clock_gettime(CLOCK_MONOTONIC, &now); time_diff = (now.tv_sec - start.tv_sec); } while ((! zts_addr_is_assigned(net_id, ZTS_AF_INET) || ! zts_addr_is_assigned(net_id, ZTS_AF_INET6)) && (time_diff < MAX_CONNECT_TIME)); if (! zts_addr_is_assigned(net_id, ZTS_AF_INET) || ! zts_addr_is_assigned(net_id, ZTS_AF_INET6)) { DEBUG_INFO("Node failed to receive assigned addresses"); exit(-1); } } char ipstr[ZTS_INET6_ADDRSTRLEN] = { 0 }; // Get ipv4 struct zts_sockaddr_storage ss; assert(zts_addr_get(net_id, ZTS_AF_INET, &ss) == ZTS_ERR_OK); struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)&ss; zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET6_ADDRSTRLEN); DEBUG_INFO("ipv4: %s", ipstr); assert(! strcmp(ipstr, "172.22.22.2") || ! strcmp(ipstr, "172.22.22.1")); memset(ipstr, 0, sizeof(ipstr)); // Get ipv6 assert(zts_addr_get(net_id, ZTS_AF_INET6, &ss) == ZTS_ERR_OK); struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&ss; zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN); DEBUG_INFO("ipv6: %s", ipstr); assert(! strcmp(ipstr, "FCC5:205E:4F90:9691:8F72::1") || ! strcmp(ipstr, "FCC5:205E:4FF7:46D5:50DD::1")); memset(ipstr, 0, sizeof(ipstr)); // Get ipv4 (string format) assert(zts_addr_get_str(net_id, ZTS_AF_INET, ipstr, ZTS_INET6_ADDRSTRLEN) == ZTS_ERR_OK); DEBUG_INFO("ipv4_str: %s", ipstr); memset(ipstr, 0, sizeof(ipstr)); // Get ipv6 (string format) assert(zts_addr_get_str(net_id, ZTS_AF_INET6, ipstr, ZTS_INET6_ADDRSTRLEN) == ZTS_ERR_OK); DEBUG_INFO("ipv6_str: %s", ipstr); memset(ipstr, 0, sizeof(ipstr)); // Get (all) ipv4 addresses in an array of sockaddr_storage objects struct zts_sockaddr_storage ss_all[ZTS_MAX_ASSIGNED_ADDRESSES] = { 0 }; int count = ZTS_MAX_ASSIGNED_ADDRESSES; assert(zts_addr_get_all(net_id, ss_all, &count) == ZTS_ERR_OK); assert(count > 0 && count <= ZTS_MAX_ASSIGNED_ADDRESSES); DEBUG_INFO("assigned addr count: %d", count); for (int i = 0; i < count; i++) { struct zts_sockaddr* sa = (struct zts_sockaddr*)&ss_all[i]; if (sa->sa_family == ZTS_AF_INET) { struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)&ss_all[i]; zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET6_ADDRSTRLEN); DEBUG_INFO("ipv(all): %s", ipstr); } if (sa->sa_family == ZTS_AF_INET6) { struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&ss_all[i]; zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN); DEBUG_INFO("ipv(all): %s", ipstr); } } // (C) Test zts_inet_pton uint8_t buf[sizeof(struct zts_in6_addr)] = { 0 }; char str[ZTS_INET6_ADDRSTRLEN] = { 0 }; zts_inet_pton(ZTS_AF_INET, "192.168.22.2", buf); zts_inet_ntop(ZTS_AF_INET, buf, str, ZTS_INET6_ADDRSTRLEN); assert(! strcmp(str, "192.168.22.2")); // assert(zts_net_count() > 0); // DEBUG_INFO("Networks joined : %d", zts_net_count()); char name[ZTS_MAX_NETWORK_SHORT_NAME_LENGTH] = { 0 }; assert(zts_net_get_name(net_id, name, ZTS_MAX_NETWORK_SHORT_NAME_LENGTH) == ZTS_ERR_OK); DEBUG_INFO("Network name: %s", name); assert(! strcmp(name, "TESTNET-1")); // Test zts_core_ locking functions to query node zts_core_lock_obtain(); char addr_str[ZTS_INET6_ADDRSTRLEN] = { 0 }; char target_str[ZTS_INET6_ADDRSTRLEN] = { 0 }; char via_str[ZTS_INET6_ADDRSTRLEN] = { 0 }; uint16_t flags; uint16_t metric; int addr_count = zts_core_query_addr_count(net_id); DEBUG_INFO("addr_count = %d", addr_count); for (int i = 0; i < addr_count; i++) { zts_core_query_addr(net_id, i, addr_str, ZTS_INET6_ADDRSTRLEN); DEBUG_INFO("addr = %s", addr_str); } int route_count = zts_core_query_route_count(net_id); DEBUG_INFO("route_count = %d", route_count); for (int i = 0; i < route_count; i++) { zts_core_query_route(net_id, i, target_str, via_str, ZTS_INET6_ADDRSTRLEN, &flags, &metric); DEBUG_INFO("target = %s, via = %s, flags = %d, metric = %d", target_str, via_str, flags, metric); } int mc_sub_count = zts_core_query_mc_count(net_id); DEBUG_INFO("addr_count = %d", addr_count); for (int i = 0; i < mc_sub_count; i++) { zts_core_query_addr(net_id, i, addr_str, ZTS_INET6_ADDRSTRLEN); DEBUG_INFO("addr = %s", addr_str); } zts_core_lock_release(); } // join network if (! use_callbacks) { DEBUG_INFO("Asserting that no events were generated"); assert(callback_was_called_flag == 0); } // Ensure that no networks were joined (if not explicitly joined) // if (! join_network) { // assert(zts_net_count() == 0); //} // Shut down node if requested if (shutdown) { DEBUG_INFO("Shutting down node..."); assert(zts_node_stop() == ZTS_ERR_OK); DEBUG_INFO("Node has been shut down"); } return ZTS_ERR_OK; } void test_identity_key_handling() { DEBUG_INFO("\n\n***\ttest_identity_key_handling"); char keypair[ZTS_ID_STR_BUF_LEN] = { 0 }; unsigned int keypair_len = ZTS_ID_STR_BUF_LEN; // Test valid key DEBUG_INFO("Generating new identity..."); assert(zts_id_new(keypair, &keypair_len) == ZTS_ERR_OK); DEBUG_INFO("Checking key length"); assert(keypair_len <= ZTS_ID_STR_BUF_LEN); DEBUG_INFO("Checking validity of identity"); DEBUG_INFO("Identity = [%s]", keypair); assert(zts_id_pair_is_valid(keypair, ZTS_ID_STR_BUF_LEN) == 1); /* Test valid key with incorrect len provided by user. This test should return false even if a valid key was provided. This is because we want the user to be notified of a possible error the size of the buffer that they may use to contain the key for other operations. I think this is the responsible thing to do? */ DEBUG_INFO("Checking validity of identity with incorrect provided length"); assert(zts_id_pair_is_valid(keypair, -1024) == 0); assert(zts_id_pair_is_valid(keypair, -1) == 0); assert(zts_id_pair_is_valid(keypair, 0) == 0); assert(zts_id_pair_is_valid(keypair, 1) == 0); assert(zts_id_pair_is_valid(keypair, 1024) == 0); // Test key that is too short char keypair_short[ZTS_ID_STR_BUF_LEN] = { 0 }; strncpy(keypair_short, keypair, 64); DEBUG_INFO("Checking validity of key that is too short (should be false)"); DEBUG_INFO("Identity = [%s]", keypair_short); assert(zts_id_pair_is_valid(keypair_short, ZTS_ID_STR_BUF_LEN) == 0); // Test key that is too long char keypair_long[ZTS_ID_STR_BUF_LEN] = { 0 }; strncpy(keypair_long, keypair, ZTS_ID_STR_BUF_LEN); strncat(keypair_long, keypair, 16); DEBUG_INFO("len=%lu", strlen(keypair_long)); DEBUG_INFO("Checking validity of key that is too long (should be false)"); DEBUG_INFO("Identity = [%s]", keypair_long); assert(zts_id_pair_is_valid(keypair_long, ZTS_ID_STR_BUF_LEN) == 0); // Test empty key char keypair_null[ZTS_ID_STR_BUF_LEN] = { 0 }; DEBUG_INFO("Checking validity of key that is empty (should be false)"); DEBUG_INFO("Identity = [%s]", keypair_null); assert(zts_id_pair_is_valid(keypair_null, ZTS_ID_STR_BUF_LEN) == 0); // Test valid key with a corrupted element keypair[32]++; DEBUG_INFO("Checking validity of identity that is corrupted (should be false)"); DEBUG_INFO("Identity = [%s]", keypair); assert(zts_id_pair_is_valid(keypair, ZTS_ID_STR_BUF_LEN) == 0); } void test_addr_computation() { DEBUG_INFO("\n\n***\ttest_addr_computation"); // Test plausible values uint64_t nodeid = 0x75f3543094; uint16_t start_port = 2000; uint16_t end_port = 3000; uint64_t net_id = zts_net_compute_adhoc_id(start_port, end_port); assert(net_id == 0xff07d00bb8000000); char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 }; assert(zts_addr_compute_rfc4193_str(net_id, nodeid, ipstr, ZTS_IP_MAX_STR_LEN) == ZTS_ERR_OK); assert(! strcmp(ipstr, "FDFF:7D0:BB8:0:99:9375:F354:3094")); assert(zts_addr_compute_6plane_str(net_id, nodeid, ipstr, ZTS_IP_MAX_STR_LEN) == ZTS_ERR_OK); assert(! strcmp(ipstr, "FC47:7D0:B75:F354:3094::1")); } void test_roots_handling() { DEBUG_INFO("\n\n***\ttest_roots_handling"); char roots_data[ZTS_STORE_DATA_LEN] = { 0 }; int len = ZTS_STORE_DATA_LEN; assert(zts_init_set_roots(NULL, 1) != ZTS_ERR_OK); assert(zts_init_set_roots(roots_data, 0) != ZTS_ERR_OK); assert(zts_init_set_roots(roots_data, len) == ZTS_ERR_OK); // TODO: Test setting when node is already running } void test_start_sequences() { DEBUG_INFO("\n\n***\ttest_start_sequences"); int res; char* path = "."; uint64_t net_id; char keypair_f[ZTS_ID_STR_BUF_LEN] = { 0 }; unsigned int keypair_len = ZTS_ID_STR_BUF_LEN; int use_storage; int use_callbacks; int use_identity; int join_network; int shutdown; /* Start node with no given identity, no storage access allowed, callbacks disabled. Once it is confirmed to be online save the identity for future use. */ DEBUG_INFO("TEST: Node with no id, no storage, no callbacks"); use_storage = 0; use_callbacks = 0; use_identity = 0; join_network = 0; shutdown = 0; assert( test_start_node(".", 0x0, NULL, use_storage, use_callbacks, use_identity, join_network, shutdown) == ZTS_ERR_OK); assert(zts_node_get_id_pair(keypair_i, &keypair_len) == ZTS_ERR_OK); assert(zts_node_stop() == ZTS_ERR_OK); // Confirm that no callbacks were sent to the user /* Start a node under similar conditions as above, but this time provide it with the previously-generated identity and then try to read it back from the node to ensure it was set properly */ DEBUG_INFO("TEST: Node with given id, no storage, no callbacks"); use_storage = 0; use_callbacks = 0; use_identity = 1; join_network = 0; shutdown = 0; assert( test_start_node(".", 0x0, keypair_i, use_storage, use_callbacks, use_identity, join_network, shutdown) == ZTS_ERR_OK); keypair_len = ZTS_ID_STR_BUF_LEN; assert(zts_node_get_id_pair(keypair_f, &keypair_len) == ZTS_ERR_OK); // Compare keypairs DEBUG_INFO("Comparing keys"); assert(! strcmp(keypair_i, keypair_f)); assert(zts_node_stop() == ZTS_ERR_OK); /* start node with above identity and storage allowed. should not load from storage if an identity exists since one was already provided */ DEBUG_INFO("TEST: Node with given id, storage, no callbacks"); use_storage = 1; use_callbacks = 0; use_identity = 1; join_network = 0; shutdown = 0; assert( test_start_node(".", 0x0, keypair_i, use_storage, use_callbacks, use_identity, join_network, shutdown) == ZTS_ERR_OK); keypair_len = ZTS_ID_STR_BUF_LEN; assert(zts_node_get_id_pair(keypair_f, &keypair_len) == ZTS_ERR_OK); assert(zts_node_stop() == ZTS_ERR_OK); // Compare keypairs DEBUG_INFO("Comparing keys"); assert(! strcmp(keypair_i, keypair_f)); } #define NUM_THREADS 2 int test_thread_safety() { DEBUG_INFO("\n\n***\ttest_thread_safety"); pthread_t threads[NUM_THREADS]; for (int i = 0; i < NUM_THREADS; i++) { int res = pthread_create(&threads[i], NULL, test_pre_service_fuzz, (void*)NULL); } for (int i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } return 0; } int test_stats() { DEBUG_INFO("\n\n***\ttest_stats"); zts_stats_counter_t s = { 0 }; int err = ZTS_ERR_OK; if ((err = zts_stats_get_all(&s)) == ZTS_ERR_NO_RESULT) { printf("no results\n"); } printf( " link_tx=%9d, link_rx=%9d, link_drop=%9d, link_err=%9d\n", s.link_tx, s.link_rx, s.link_drop, s.link_err); printf( "etharp_tx=%9d, etharp_rx=%9d, etharp_drop=%9d, etharp_err=%9d\n", s.etharp_tx, s.etharp_rx, s.etharp_drop, s.etharp_err); printf( " ip4_tx=%9d, ip4_rx=%9d, ip4_drop=%9d, ip4_err=%9d\n", s.ip4_tx, s.ip4_rx, s.ip4_drop, s.ip4_err); printf( " ip6_tx=%9d, ip6_rx=%9d, ip6_drop=%9d, ip6_err=%9d\n", s.ip6_tx, s.ip6_rx, s.ip6_drop, s.ip6_err); printf( " icmp4_tx=%9d, icmp4_rx=%9d, icmp4_drop=%9d, icmp4_err=%9d\n", s.icmp4_tx, s.icmp4_rx, s.icmp4_drop, s.icmp4_err); printf( " icmp6_tx=%9d, icmp6_rx=%9d, icmp6_drop=%9d, icmp6_err=%9d\n", s.icmp6_tx, s.icmp6_rx, s.icmp6_drop, s.icmp6_err); printf( " udp_tx=%9d, udp_rx=%9d, udp_drop=%9d, udp_err=%9d\n", s.udp_tx, s.udp_rx, s.udp_drop, s.udp_err); printf( " tcp_tx=%9d, tcp_rx=%9d, tcp_drop=%9d, tcp_err=%9d\n", s.tcp_tx, s.tcp_rx, s.tcp_drop, s.tcp_err); printf( " nd6_tx=%9d, nd6_rx=%9d, nd6_drop=%9d, nd6_err=%9d\n", s.nd6_tx, s.nd6_rx, s.nd6_drop, s.nd6_err); return 0; } int test_utils() { DEBUG_INFO("\n\n***\ttest_utils"); // Test zts_util_get_ip_family // TODO: Consider ports erroneously embedded in string assert(zts_util_get_ip_family("0") == ZTS_AF_INET); assert(zts_util_get_ip_family("0.0") == ZTS_AF_INET); assert(zts_util_get_ip_family("0.0.0") == ZTS_AF_INET); assert(zts_util_get_ip_family("1") == ZTS_AF_INET); assert(zts_util_get_ip_family("255") == ZTS_AF_INET); // assert(zts_util_get_ip_family("256") != ZTS_AF_INET); assert(zts_util_get_ip_family("-1") != ZTS_AF_INET); assert(zts_util_get_ip_family("0.0.0.0") == ZTS_AF_INET); assert(zts_util_get_ip_family("0.0.0.1") == ZTS_AF_INET); assert(zts_util_get_ip_family("0.0.1.0") == ZTS_AF_INET); assert(zts_util_get_ip_family("0.1.0.0") == ZTS_AF_INET); assert(zts_util_get_ip_family("1.0.0.0") == ZTS_AF_INET); assert(zts_util_get_ip_family("1.2.3.4") == ZTS_AF_INET); assert(zts_util_get_ip_family("255.255.255.255") == ZTS_AF_INET); assert(zts_util_get_ip_family("a.b.c.d") != ZTS_AF_INET); assert(zts_util_get_ip_family("256.256.256.256") != ZTS_AF_INET); assert(zts_util_get_ip_family("0.-1.0.0") != ZTS_AF_INET); assert(zts_util_get_ip_family(".0.0.0.0") != ZTS_AF_INET); assert(zts_util_get_ip_family("0..0.0.0") != ZTS_AF_INET); assert(zts_util_get_ip_family("0.0.0.0..") != ZTS_AF_INET); assert(zts_util_get_ip_family(".") != ZTS_AF_INET); assert(zts_util_get_ip_family("..") != ZTS_AF_INET); assert(zts_util_get_ip_family("...") != ZTS_AF_INET); assert(zts_util_get_ip_family("....") != ZTS_AF_INET); assert(zts_util_get_ip_family(".....") != ZTS_AF_INET); assert(zts_util_get_ip_family("") != ZTS_AF_INET); assert(zts_util_get_ip_family("::") == ZTS_AF_INET6); return 0; } //----------------------------------------------------------------------------// // Main // //----------------------------------------------------------------------------// int main(int argc, char** argv) { if (argc != 1 && argc != 5 && argc != 7) { DEBUG_INFO("Invalid number of arguments."); exit(-1); } // Default selftest if (argc == 1) { srand(time(NULL)); DEBUG_INFO("Single node test"); test_utils(); test_pre_service_fuzz(); test_thread_safety(); test_identity_key_handling(); test_addr_computation(); test_roots_handling(); test_start_sequences(); test_api_abuse(); test_stats(); // test_sockets(); } // Server test if (argc == 5) { DEBUG_INFO("Server test"); uint64_t net_id = strtoull(argv[2], NULL, 16); int port4 = atoi(argv[3]); int port6 = atoi(argv[4]); test_start_node(argv[1], net_id, NULL, 1, 1, 0, 1, 0); test_server_socket_usage(port4, port6); } // Client test if (argc == 7) { DEBUG_INFO("Client test"); uint64_t net_id = strtoull(argv[2], NULL, 16); int port4 = atoi(argv[3]); int port6 = atoi(argv[5]); test_start_node(argv[1], net_id, NULL, 1, 1, 0, 1, 0); test_client_socket_usage(argv[4], port4, argv[6], port6); } DEBUG_INFO("SUCCESS"); return 0; }