/** * Copyright (C) Mellanox Technologies Ltd. 2019. ALL RIGHTS RESERVED. * * See file LICENSE for terms. */ #include extern "C" { #include #include } #include static std::string socket_err_exp_str; class test_socket : public ucs::test { public: protected: static ucs_log_func_rc_t socket_error_handler(const char *file, unsigned line, const char *function, ucs_log_level_t level, const ucs_log_component_config_t *comp_conf, const char *message, va_list ap) { // Ignore errors that invalid input parameters as it is expected if (level == UCS_LOG_LEVEL_ERROR) { std::string err_str = format_message(message, ap); if (err_str.find(socket_err_exp_str) != std::string::npos) { UCS_TEST_MESSAGE << err_str; return UCS_LOG_FUNC_RC_STOP; } } return UCS_LOG_FUNC_RC_CONTINUE; } }; UCS_TEST_F(test_socket, sockaddr_sizeof) { struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; size_t size; /* Check with IPv4 */ { size = 0; saddr->sa_family = AF_INET; EXPECT_UCS_OK(ucs_sockaddr_sizeof(saddr, &size)); EXPECT_EQ(sizeof(struct sockaddr_in), size); } /* Check with IPv6 */ { size = 0; saddr->sa_family = AF_INET6; EXPECT_UCS_OK(ucs_sockaddr_sizeof(saddr, &size)); EXPECT_EQ(sizeof(struct sockaddr_in6), size); } /* Check with wrong address family */ { socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); size = 0; saddr->sa_family = AF_UNIX; EXPECT_EQ(UCS_ERR_INVALID_PARAM, ucs_sockaddr_sizeof(saddr, &size)); /* Check that doesn't touch provided memory in error case */ EXPECT_EQ(0ULL, size); } } UCS_TEST_F(test_socket, sockaddr_inet_addr_sizeof) { struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; size_t size; /* Check with IPv4 */ { size = 0; saddr->sa_family = AF_INET; EXPECT_UCS_OK(ucs_sockaddr_inet_addr_sizeof(saddr, &size)); EXPECT_EQ(UCS_IPV4_ADDR_LEN, size); } /* Check with IPv6 */ { size = 0; saddr->sa_family = AF_INET6; EXPECT_UCS_OK(ucs_sockaddr_inet_addr_sizeof(saddr, &size)); EXPECT_EQ(UCS_IPV6_ADDR_LEN, size); } /* Check with wrong address family */ { socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); size = 0; saddr->sa_family = AF_UNIX; EXPECT_EQ(UCS_ERR_INVALID_PARAM, ucs_sockaddr_inet_addr_sizeof(saddr, &size)); /* Check that doesn't touch provided memory in error case */ EXPECT_EQ(0ULL, size); } } UCS_TEST_F(test_socket, sockaddr_get_port) { const uint16_t sin_port = 5555; uint16_t port = 0; struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; /* Check with IPv4 */ { port = 0; saddr->sa_family = AF_INET; ((struct sockaddr_in*)saddr)->sin_port = htons(sin_port); EXPECT_UCS_OK(ucs_sockaddr_get_port(saddr, &port)); EXPECT_EQ(sin_port, port); } /* Check with IPv6 */ { port = 0; saddr->sa_family = AF_INET6; ((struct sockaddr_in6*)saddr)->sin6_port = htons(sin_port); EXPECT_UCS_OK(ucs_sockaddr_get_port(saddr, &port)); EXPECT_EQ(sin_port, port); } /* Check with wrong address family */ { socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); port = sin_port; saddr->sa_family = AF_UNIX; EXPECT_EQ(UCS_ERR_INVALID_PARAM, ucs_sockaddr_get_port(saddr, &port)); /* Check that doesn't touch provided memory in error case */ EXPECT_EQ(sin_port, port); } } UCS_TEST_F(test_socket, sockaddr_get_inet_addr) { struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; struct sockaddr_in *saddr_in; struct sockaddr_in6 *saddr_in6; struct in_addr sin_addr; struct in6_addr sin6_addr; /* Check with wrong IPv4 */ { saddr->sa_family = AF_INET; sin_addr.s_addr = htonl(INADDR_ANY); ((struct sockaddr_in*)saddr)->sin_addr.s_addr = htonl(INADDR_ANY); EXPECT_EQ(&((struct sockaddr_in*)saddr)->sin_addr, ucs_sockaddr_get_inet_addr(saddr)); saddr_in = (struct sockaddr_in*)saddr; EXPECT_EQ(0, memcmp(&saddr_in->sin_addr, &sin_addr, sizeof(sin_addr))); } /* Check with wrong IPv6 */ { saddr->sa_family = AF_INET6; sin6_addr = in6addr_any; ((struct sockaddr_in6*)saddr)->sin6_addr = in6addr_any; EXPECT_EQ(&((struct sockaddr_in6*)saddr)->sin6_addr, ucs_sockaddr_get_inet_addr(saddr)); saddr_in6 = (struct sockaddr_in6*)saddr; EXPECT_EQ(0, memcmp(&saddr_in6->sin6_addr, &sin6_addr, sizeof(sin6_addr))); } /* Check with wrong address family */ { saddr->sa_family = AF_UNIX; socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); EXPECT_EQ(NULL, ucs_sockaddr_get_inet_addr(saddr)); } } UCS_TEST_F(test_socket, sockaddr_set_port) { const uint16_t sin_port = 5555; const uint16_t sin_port_net = htons(sin_port); struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; /* Check with IPv4 */ { saddr->sa_family = AF_INET; EXPECT_UCS_OK(ucs_sockaddr_set_port(saddr, sin_port)); EXPECT_EQ(sin_port_net, ((struct sockaddr_in*)saddr)->sin_port); } /* Check with IPv6 */ { saddr->sa_family = AF_INET6; EXPECT_UCS_OK(ucs_sockaddr_set_port(saddr, sin_port)); EXPECT_EQ(sin_port_net, ((struct sockaddr_in6*)saddr)->sin6_port); } /* Check with wrong address family */ { saddr->sa_family = AF_UNIX; socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); EXPECT_EQ(UCS_ERR_INVALID_PARAM, ucs_sockaddr_set_port(saddr, sin_port)); } } UCS_TEST_F(test_socket, sockaddr_set_inet_addr) { struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; struct in_addr sin_addr; struct in6_addr sin6_addr; sin_addr.s_addr = htonl(INADDR_ANY); sin6_addr = in6addr_any; /* Check with IPv4 */ { saddr->sa_family = AF_INET; EXPECT_UCS_OK(ucs_sockaddr_set_inet_addr(saddr, &sin_addr)); EXPECT_EQ(0, memcmp(&((struct sockaddr_in*)saddr)->sin_addr, &sin_addr, sizeof(sin_addr))); } /* Check with IPv6 */ { saddr->sa_family = AF_INET6; EXPECT_UCS_OK(ucs_sockaddr_set_inet_addr(saddr, &sin6_addr)); EXPECT_EQ(0, memcmp(&((struct sockaddr_in6*)saddr)->sin6_addr, &sin6_addr, sizeof(sin6_addr))); } /* Check with wrong address family */ { saddr->sa_family = AF_UNIX; socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); EXPECT_EQ(UCS_ERR_INVALID_PARAM, ucs_sockaddr_set_inet_addr(saddr, NULL)); } } UCS_TEST_F(test_socket, sockaddr_is_inaddr) { struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; struct in_addr sin_addr_loopback, sin_addr_any; struct in6_addr sin6_addr_loopback, sin6_addr_any; sin_addr_any.s_addr = htonl(INADDR_ANY); sin6_addr_any = in6addr_any; sin_addr_loopback.s_addr = htonl(INADDR_LOOPBACK); sin6_addr_loopback = in6addr_loopback; /* Check with IPv4 */ { saddr->sa_family = AF_INET; /* ANY is specified to address */ ASSERT_UCS_OK(ucs_sockaddr_set_inet_addr(saddr, &sin_addr_any)); EXPECT_TRUE(ucs_sockaddr_is_inaddr_any(saddr)); EXPECT_FALSE(ucs_sockaddr_is_inaddr_loopback(saddr)); /* LOOPBACK is specified to address */ ASSERT_UCS_OK(ucs_sockaddr_set_inet_addr(saddr, &sin_addr_loopback)); EXPECT_FALSE(ucs_sockaddr_is_inaddr_any(saddr)); EXPECT_TRUE(ucs_sockaddr_is_inaddr_loopback(saddr)); } /* Check with IPv6 */ { saddr->sa_family = AF_INET6; /* ANY is specified to address */ ASSERT_UCS_OK(ucs_sockaddr_set_inet_addr(saddr, &sin6_addr_any)); EXPECT_TRUE(ucs_sockaddr_is_inaddr_any(saddr)); EXPECT_FALSE(ucs_sockaddr_is_inaddr_loopback(saddr)); /* LOOPBACK is specified to address */ ASSERT_UCS_OK(ucs_sockaddr_set_inet_addr(saddr, &sin6_addr_loopback)); EXPECT_FALSE(ucs_sockaddr_is_inaddr_any(saddr)); EXPECT_TRUE(ucs_sockaddr_is_inaddr_loopback(saddr)); } /* Check with wrong address family */ { saddr->sa_family = AF_UNIX; socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); EXPECT_FALSE(ucs_sockaddr_is_inaddr_any(saddr)); } } UCS_TEST_F(test_socket, str_sockaddr_str) { const uint16_t port = 65534; const char *ipv4_addr = "192.168.122.157"; const char *ipv6_addr = "fe80::218:e7ff:fe16:fb97"; struct sockaddr_storage ss = {0}; struct sockaddr *saddr = (struct sockaddr*)&ss; char ipv4_addr_out[128], ipv6_addr_out[128], *str, test_str[1024]; ucs_status_t status; sprintf(ipv4_addr_out, "%s:%d", ipv4_addr, port); sprintf(ipv6_addr_out, "%s:%d", ipv6_addr, port); /* Check `str_len` with IPv4 address */ { saddr->sa_family = AF_INET; ((struct sockaddr_in*)saddr)->sin_port = htons(port); status = ucs_sock_ipstr_to_sockaddr(ipv4_addr, &ss); ASSERT_EQ(UCS_OK, status); /* Check with short `str_len` to fit IP address only */ str = (char*)ucs_sockaddr_str(saddr, test_str, INET_ADDRSTRLEN); EXPECT_EQ(str, test_str); EXPECT_EQ(0, strncmp(test_str, ipv4_addr_out, INET_ADDRSTRLEN - 1)); /* Check with big enough `str_len` */ str = (char*)ucs_sockaddr_str(saddr, test_str, 1024); EXPECT_EQ(str, test_str); EXPECT_EQ(0, strcmp(test_str, ipv4_addr_out)); } /* Check `str_len` with IPv6 address */ { saddr->sa_family = AF_INET6; ((struct sockaddr_in6*)saddr)->sin6_port = htons(port); status = ucs_sock_ipstr_to_sockaddr(ipv6_addr, &ss); ASSERT_EQ(UCS_OK, status); /* Check with short `str_len` to fit IP address only */ str = (char*)ucs_sockaddr_str(saddr, test_str, INET6_ADDRSTRLEN); EXPECT_EQ(str, test_str); EXPECT_EQ(0, strncmp(test_str, ipv6_addr_out, INET6_ADDRSTRLEN - 1)); /* Check with big enough `str_len` */ str = (char*)ucs_sockaddr_str(saddr, test_str, 1024); EXPECT_TRUE(str == test_str); EXPECT_EQ(0, strcmp(test_str, ipv6_addr_out)); } /* Check with wrong sa_family */ { saddr->sa_family = AF_UNIX; /* with big enough string */ { str = (char*)ucs_sockaddr_str(saddr, test_str, 1024); EXPECT_EQ(test_str, str); EXPECT_EQ(0, strcmp(str, "")); } /* without string */ { str = (char*)ucs_sockaddr_str(saddr, NULL, 0); EXPECT_EQ(NULL, str); } } /* Check NULL sockaddr */ { /* with big enough string */ { str = (char*)ucs_sockaddr_str(NULL, test_str, 1024); EXPECT_EQ(test_str, str); EXPECT_EQ(0, strcmp(str, "")); } /* without string */ { str = (char*)ucs_sockaddr_str(NULL, NULL, 0); EXPECT_EQ(NULL, str); } } } UCS_TEST_F(test_socket, socket_setopt) { socklen_t optlen; int optname; int optval; int level; ucs_status_t status; int fd; optlen = sizeof(optval); status = ucs_socket_create(AF_INET, SOCK_STREAM, &fd); EXPECT_UCS_OK(status); EXPECT_GE(fd, 0); /* with acceptable parameters */ { level = SOL_SOCKET; optname = SO_REUSEADDR; optval = 1; status = ucs_socket_setopt(fd, level, optname, &optval, optlen); EXPECT_UCS_OK(status); } /* with bad parameters */ { level = IPPROTO_TCP; optname = SO_REUSEADDR; optval = 1; socket_err_exp_str = "failed to set " + ucs::to_string(optname) + " option for " + ucs::to_string(level) + " level on fd " + ucs::to_string(fd) + + ": " + strerror(EINVAL); scoped_log_handler log_handler(socket_error_handler); status = ucs_socket_setopt(fd, level, optname, &optval, optlen); EXPECT_EQ(status, UCS_ERR_IO_ERROR); } close(fd); } static void sockaddr_cmp_test(int sa_family, const char *ip_addr1, const char *ip_addr2, unsigned port1, unsigned port2, struct sockaddr *sa1, struct sockaddr *sa2) { int cmp_res1, cmp_res2; ucs_status_t status; sa1->sa_family = sa_family; sa2->sa_family = sa_family; inet_pton(sa_family, ip_addr1, const_cast(ucs_sockaddr_get_inet_addr(sa1))); inet_pton(sa_family, ip_addr2, const_cast(ucs_sockaddr_get_inet_addr(sa2))); status = ucs_sockaddr_set_port(sa1, port1); ASSERT_UCS_OK(status); status = ucs_sockaddr_set_port(sa2, port2); ASSERT_UCS_OK(status); const void *addr1 = ucs_sockaddr_get_inet_addr(sa1); const void *addr2 = ucs_sockaddr_get_inet_addr(sa2); ASSERT_TRUE(addr1 != NULL); ASSERT_TRUE(addr2 != NULL); size_t addr_size = ((sa_family == AF_INET) ? sizeof(UCS_SOCKET_INET_ADDR(sa1)) : sizeof(UCS_SOCKET_INET6_ADDR(sa1))); // `sa1` vs `sa2` { int addr_cmp_res = memcmp(addr1, addr2, addr_size); int port_cmp_res = (port1 == port2) ? 0 : ((port1 < port2) ? -1 : 1); int expected_cmp_res = addr_cmp_res ? addr_cmp_res : port_cmp_res; cmp_res1 = ucs_sockaddr_cmp(sa1, sa2, &status); EXPECT_UCS_OK(status); EXPECT_EQ(expected_cmp_res, cmp_res1); // Call w/o `status` provided cmp_res2 = ucs_sockaddr_cmp(sa1, sa2, &status); EXPECT_EQ(cmp_res1, cmp_res2); } // `sa2` vs `sa1` { int addr_cmp_res = memcmp(addr2, addr1, addr_size); int port_cmp_res = (port2 == port1) ? 0 : ((port2 < port1) ? -1 : 1); int expected_cmp_res = addr_cmp_res ? addr_cmp_res : port_cmp_res; cmp_res1 = ucs_sockaddr_cmp(sa2, sa1, &status); EXPECT_UCS_OK(status); EXPECT_EQ(expected_cmp_res, cmp_res1); // Call w/o `status` provided cmp_res2 = ucs_sockaddr_cmp(sa2, sa1, &status); EXPECT_EQ(cmp_res1, cmp_res2); } } UCS_TEST_F(test_socket, sockaddr_cmp) { const unsigned port1 = 65534; const unsigned port2 = 65533; const char *ipv4_addr1 = "192.168.122.157"; const char *ipv4_addr2 = "192.168.123.157"; const char *ipv6_addr1 = "fe80::218:e7ff:fe16:fb97"; const char *ipv6_addr2 = "fe80::219:e7ff:fe16:fb97"; struct sockaddr_storage ss1 = {0}; struct sockaddr_storage ss2 = {0}; struct sockaddr *saddr1 = (struct sockaddr*)&ss1; struct sockaddr *saddr2 = (struct sockaddr*)&ss2; // Same addresses; same ports sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr1, port1, port1, saddr1, saddr2); sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr1, port1, port1, saddr1, saddr2); // Same addresses; different ports sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr1, port1, port2, saddr1, saddr2); sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr1, port1, port2, saddr1, saddr2); // Different addresses; same ports sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr2, port1, port1, saddr1, saddr2); sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr2, port1, port1, saddr1, saddr2); // Different addresses; different ports sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr2, port1, port2, saddr1, saddr2); sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr2, port1, port2, saddr1, saddr2); } static void sockaddr_cmp_err_test(const struct sockaddr *sa1, const struct sockaddr *sa2) { ucs_status_t status; int result; result = ucs_sockaddr_cmp((const struct sockaddr*)sa1, (const struct sockaddr*)sa2, &status); EXPECT_EQ(UCS_ERR_INVALID_PARAM, status); EXPECT_TRUE(result > 0); // Call w/o `status` provided result = ucs_sockaddr_cmp((const struct sockaddr*)sa1, (const struct sockaddr*)sa2, NULL); EXPECT_TRUE(result > 0); } UCS_TEST_F(test_socket, sockaddr_cmp_err) { // Check with wrong sa_family struct sockaddr_un sa_un = {}; struct sockaddr_in sa_in = {}; sa_un.sun_family = AF_UNIX; sa_in.sin_family = AF_INET; socket_err_exp_str = "unknown address family: "; scoped_log_handler log_handler(socket_error_handler); sockaddr_cmp_err_test((const struct sockaddr*)&sa_un, (const struct sockaddr*)&sa_un); sockaddr_cmp_err_test((const struct sockaddr*)&sa_in, (const struct sockaddr*)&sa_un); sockaddr_cmp_err_test((const struct sockaddr*)&sa_un, (const struct sockaddr*)&sa_in); } static void sockaddr_get_ipstr_check(const struct sockaddr *sockaddr, ucs_status_t expected_ret, const char *expected_str = NULL) { const size_t max_size = 1024; char str[max_size]; EXPECT_EQ(expected_ret, ucs_sockaddr_get_ipstr(sockaddr, str, max_size)); if (expected_str != NULL) { EXPECT_STREQ(expected_str, str); } } static void sockaddr_get_ipstr_check_ip(void *sockaddr, const char *ip_str) { EXPECT_UCS_OK( ucs_sock_ipstr_to_sockaddr(ip_str, (struct sockaddr_storage*)sockaddr)); sockaddr_get_ipstr_check((const struct sockaddr*)sockaddr, UCS_OK, ip_str); } UCS_TEST_F(test_socket, sockaddr_get_ipstr) { struct sockaddr_storage ss; struct sockaddr *saddr = (struct sockaddr*)&ss; /* Check ipv4 */ saddr->sa_family = AF_INET; sockaddr_get_ipstr_check_ip(saddr, "192.168.122.157"); /* Check ipv6 */ saddr->sa_family = AF_INET6; sockaddr_get_ipstr_check_ip(saddr, "fe80::218:e7ff:fe16:fb97"); /* Check invalid sa_family */ socket_err_exp_str = "unknown address family:"; scoped_log_handler log_handler(socket_error_handler); saddr->sa_family = AF_UNIX; sockaddr_get_ipstr_check(saddr, UCS_ERR_INVALID_PARAM); }