diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 62d207261e..e9799c2068 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -1145,6 +1145,8 @@ SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool); +SWITCH_DECLARE(switch_status_t) switch_sockaddr_new(switch_sockaddr_t ** sa, const char *ip, switch_port_t port, switch_memory_pool_t *pool); + /** * Send data over a network. * @param sock The socket to send the data over. diff --git a/src/switch_apr.c b/src/switch_apr.c index 25ff864129..c033d87bc4 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -814,7 +814,6 @@ SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, s new_sa = apr_pcalloc(pool, sizeof(apr_sockaddr_t)); switch_assert(new_sa); new_sa->pool = pool; - memset(new_sa, 0, sizeof(*new_sa)); new_sa->family = family; new_sa->sa.sin.sin_family = family; @@ -834,6 +833,65 @@ SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa return apr_sockaddr_info_get(sa, hostname, family, port, flags, pool); } +SWITCH_DECLARE(switch_status_t) switch_sockaddr_new(switch_sockaddr_t ** sa, const char *ip, switch_port_t port, switch_memory_pool_t *pool) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + apr_sockaddr_t *new_sa; + int family; + + if (!sa || !pool || !ip) { + switch_goto_status(SWITCH_STATUS_GENERR, end); + } + + new_sa = apr_pcalloc(pool, sizeof(apr_sockaddr_t)); + switch_assert(new_sa); + + new_sa->pool = pool; + + if (strchr(ip, ':')) { + struct sockaddr_in6 sa6 = { 0 }; + + family = APR_INET6; + inet_pton(family, ip, &(sa6.sin6_addr)); + memcpy(&new_sa->sa, &sa6, sizeof(struct sockaddr_in6)); + } else { + struct sockaddr_in sa4 = { 0 }; + + family = APR_INET; + inet_pton(family, ip, &(sa4.sin_addr)); + memcpy(&new_sa->sa, &sa4, sizeof(struct sockaddr_in)); + } + + new_sa->hostname = apr_pstrdup(pool, ip); + new_sa->family = family; + new_sa->sa.sin.sin_family = family; + if (port) { + /* XXX IPv6: assumes sin_port and sin6_port at same offset */ + new_sa->sa.sin.sin_port = htons(port); + new_sa->port = port; + } + + if (family == APR_INET) { + new_sa->salen = sizeof(struct sockaddr_in); + new_sa->addr_str_len = 16; + new_sa->ipaddr_ptr = &(new_sa->sa.sin.sin_addr); + new_sa->ipaddr_len = sizeof(struct in_addr); + } +#if APR_HAVE_IPV6 + else if (family == APR_INET6) { + new_sa->salen = sizeof(struct sockaddr_in6); + new_sa->addr_str_len = 46; + new_sa->ipaddr_ptr = &(new_sa->sa.sin6.sin6_addr); + new_sa->ipaddr_len = sizeof(struct in6_addr); + } +#endif + + *sa = new_sa; + +end: + return status; +} + SWITCH_DECLARE(switch_status_t) switch_socket_opt_set(switch_socket_t *sock, int32_t opt, int32_t on) { if (opt == SWITCH_SO_TCP_KEEPIDLE) { diff --git a/src/switch_core_port_allocator.c b/src/switch_core_port_allocator.c index 5c440537ee..3bbed2a351 100644 --- a/src/switch_core_port_allocator.c +++ b/src/switch_core_port_allocator.c @@ -115,7 +115,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(const char *ip, s return SWITCH_STATUS_SUCCESS; } -static switch_bool_t test_port(switch_core_port_allocator_t *alloc, int family, int type, switch_port_t port) +static switch_bool_t test_port(switch_core_port_allocator_t *alloc, int type, switch_port_t port) { switch_memory_pool_t *pool = NULL; switch_sockaddr_t *local_addr = NULL; @@ -126,8 +126,8 @@ static switch_bool_t test_port(switch_core_port_allocator_t *alloc, int family, return SWITCH_FALSE; } - if (switch_sockaddr_info_get(&local_addr, alloc->ip, SWITCH_UNSPEC, port, 0, pool) == SWITCH_STATUS_SUCCESS) { - if (switch_socket_create(&sock, family, type, 0, pool) == SWITCH_STATUS_SUCCESS) { + if (switch_sockaddr_new(&local_addr, alloc->ip, port, pool) == SWITCH_STATUS_SUCCESS) { + if (switch_socket_create(&sock, switch_sockaddr_get_family(local_addr), type, 0, pool) == SWITCH_STATUS_SUCCESS) { if (switch_socket_bind(sock, local_addr) == SWITCH_STATUS_SUCCESS) { r = SWITCH_TRUE; } @@ -179,12 +179,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_request_port(switch_c } if ((alloc->flags & SPF_ROBUST_UDP)) { - r = test_port(alloc, AF_INET, SOCK_DGRAM, port); + r = test_port(alloc, SOCK_DGRAM, port); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "UDP port robustness check for port %d %s\n", port, r ? "pass" : "fail"); } if ((alloc->flags & SPF_ROBUST_TCP)) { - r = test_port(alloc, AF_INET, SOCK_STREAM, port); + r = test_port(alloc, SOCK_STREAM, port); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TCP port robustness check for port %d %s\n", port, r ? "pass" : "fail"); } diff --git a/tests/unit/switch_core.c b/tests/unit/switch_core.c index 05b3b7f60d..9f58969a6f 100644 --- a/tests/unit/switch_core.c +++ b/tests/unit/switch_core.c @@ -82,6 +82,34 @@ FST_CORE_BEGIN("./conf") switch_safe_free(var_default_password); } FST_TEST_END() + + FST_TEST_BEGIN(test_switch_sockaddr_new) + { + int type = SOCK_DGRAM; + switch_port_t port = 12044; + const char *ip = "127.0.0.1"; + + switch_memory_pool_t *pool = NULL; + switch_sockaddr_t *local_addr = NULL; + switch_socket_t *sock = NULL; + switch_bool_t r = SWITCH_FALSE; + + if (switch_core_new_memory_pool(&pool) == SWITCH_STATUS_SUCCESS) { + if (switch_sockaddr_new(&local_addr, ip, port, pool) == SWITCH_STATUS_SUCCESS) { + if (switch_socket_create(&sock, switch_sockaddr_get_family(local_addr), type, 0, pool) == SWITCH_STATUS_SUCCESS) { + if (switch_socket_bind(sock, local_addr) == SWITCH_STATUS_SUCCESS) { + r = SWITCH_TRUE; + } + switch_socket_close(sock); + } + } + + switch_core_destroy_memory_pool(&pool); + } + + fst_check_int_equals(r, SWITCH_TRUE); + } + FST_TEST_END() } FST_SUITE_END() }