diff --git a/pkg/emb6/contrib/sock/udp/emb6_sock_udp.c b/pkg/emb6/contrib/sock/udp/emb6_sock_udp.c index 20664c80b01793d38e434f250ec97e31edd0ca15..4693a4636a919968d7e67f67dfa89b4c889bfcf9 100644 --- a/pkg/emb6/contrib/sock/udp/emb6_sock_udp.c +++ b/pkg/emb6/contrib/sock/udp/emb6_sock_udp.c @@ -84,7 +84,6 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, (void)flags; assert((sock != NULL)); - assert((local == NULL) || (local->port != 0)); assert((remote == NULL) || (remote->port != 0)); if (sock->sock.input_callback != NULL) { sock_udp_close(sock); diff --git a/pkg/lwip/contrib/sock/udp/lwip_sock_udp.c b/pkg/lwip/contrib/sock/udp/lwip_sock_udp.c index 96a49536ef52c1c1b6a26037da8afeabdb0caf65..e947849857596e1e21a58395e7a5b0eaf873069b 100644 --- a/pkg/lwip/contrib/sock/udp/lwip_sock_udp.c +++ b/pkg/lwip/contrib/sock/udp/lwip_sock_udp.c @@ -29,7 +29,6 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, const sock_udp_ep_t *remote, uint16_t flags) { assert(sock != NULL); - assert(local == NULL || local->port != 0); assert(remote == NULL || remote->port != 0); int res; diff --git a/sys/include/net/sock/udp.h b/sys/include/net/sock/udp.h index 0b9e30e81028e958b334d422a74882e6d2f31b16..f8b978e62974a0b4f56bae7ee1f3ac814576f54b 100644 --- a/sys/include/net/sock/udp.h +++ b/sys/include/net/sock/udp.h @@ -293,17 +293,17 @@ typedef struct sock_udp sock_udp_t; * @brief Creates a new UDP sock object * * @pre `(sock != NULL)` - * @pre `(local == NULL) || (local->port != 0)` * @pre `(remote == NULL) || (remote->port != 0)` * * @param[out] sock The resulting sock object. * @param[in] local Local end point for the sock object. * May be NULL. - * sock_udp_ep_t::port must not be 0 if `local != NULL`. * sock_udp_ep_t::netif must either be * @ref SOCK_ADDR_ANY_NETIF or equal to * sock_udp_ep_t::netif of @p remote if `remote != NULL`. * If NULL @ref sock_udp_send() may bind implicitly. + * sock_udp_ep_t::port may also be 0 to bind the `sock` to + * an ephemeral port. * @param[in] remote Remote end point for the sock object. * May be `NULL` but then the `remote` parameter of * @ref sock_udp_send() may not be `NULL` or it will @@ -318,7 +318,8 @@ typedef struct sock_udp sock_udp_t; * * @return 0 on success. * @return -EADDRINUSE, if `local != NULL` and @p local is already used - * elsewhere + * elsewhere or if `local->port == 0` but the pool of ephemeral ports + * is depleted * @return -EAFNOSUPPORT, if `local != NULL` or `remote != NULL` and * sock_udp_ep_t::family of @p local or @p remote is not supported. * @return -EINVAL, if sock_udp_ep_t::addr of @p remote is an invalid address. @@ -419,6 +420,8 @@ ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len, * sock_udp_ep_t::port may not be 0. * * @return The number of bytes sent on success. + * @return -EADDRINUSE, if `sock` has no local end-point or was `NULL` and the + * pool of available ephemeral ports is depleted. * @return -EAFNOSUPPORT, if `remote != NULL` and sock_udp_ep_t::family of * @p remote is != AF_UNSPEC and not supported. * @return -EHOSTUNREACH, if @p remote or remote end point of @p sock is not diff --git a/sys/net/gnrc/sock/udp/gnrc_sock_udp.c b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c index 27168242173190cbd2f26f6b6d1d561598cd8841..c2367e242d664d8af9509238b1311993d953df84 100644 --- a/sys/net/gnrc/sock/udp/gnrc_sock_udp.c +++ b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c @@ -87,7 +87,6 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, const sock_udp_ep_t *remote, uint16_t flags) { assert(sock); - assert(local == NULL || local->port != 0); assert(remote == NULL || remote->port != 0); if ((local != NULL) && (remote != NULL) && (local->netif != SOCK_ADDR_ANY_NETIF) && @@ -97,8 +96,19 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, } memset(&sock->local, 0, sizeof(sock_udp_ep_t)); if (local != NULL) { + uint16_t port = local->port; + + if (gnrc_af_not_supported(local->family)) { + return -EAFNOSUPPORT; + } + if (port == 0U) { + port = _get_dyn_port(sock); + if (port == GNRC_SOCK_DYN_PORTRANGE_ERR) { + return -EADDRINUSE; + } + } #ifdef MODULE_GNRC_SOCK_CHECK_REUSE - if (!(flags & SOCK_FLAGS_REUSE_EP)) { + else if (!(flags & SOCK_FLAGS_REUSE_EP)) { for (sock_udp_t *ptr = _udp_socks; ptr != NULL; ptr = (sock_udp_t *)ptr->reg.next) { if (memcmp(&ptr->local, local, sizeof(sock_udp_ep_t)) == 0) { @@ -110,10 +120,8 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, sock->reg.next = (gnrc_sock_reg_t *)_udp_socks; _udp_socks = sock; #endif - if (gnrc_af_not_supported(local->family)) { - return -EAFNOSUPPORT; - } memcpy(&sock->local, local, sizeof(sock_udp_ep_t)); + sock->local.port = port; } memset(&sock->remote, 0, sizeof(sock_udp_ep_t)); if (remote != NULL) { @@ -250,7 +258,7 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len, /* no sock or sock currently unbound */ memset(&local, 0, sizeof(local)); if ((src_port = _get_dyn_port(sock)) == GNRC_SOCK_DYN_PORTRANGE_ERR) { - return -EINVAL; + return -EADDRINUSE; } /* cppcheck-suppress nullPointer * (reason: sock *can* be NULL at this place, cppcheck is weird here as diff --git a/tests/gnrc_sock_udp/main.c b/tests/gnrc_sock_udp/main.c index d91205171b9dca3636160f8a7f730588afccd6c7..df4961b2789e698d0d137510ff4322f6dfd77f6c 100644 --- a/tests/gnrc_sock_udp/main.c +++ b/tests/gnrc_sock_udp/main.c @@ -117,6 +117,22 @@ static void test_sock_udp_create__only_local(void) assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); } +static void test_sock_udp_create__only_local_port0(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = 0U }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(AF_INET6 == ep.family); + assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6, + sizeof(ipv6_addr_t)) == 0); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(0U != ep.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); +} + static void test_sock_udp_create__only_local_reuse_ep(void) { static const sock_udp_ep_t local = { .family = AF_INET6, @@ -663,6 +679,7 @@ int main(void) CALL(test_sock_udp_create__EINVAL_netif()); CALL(test_sock_udp_create__no_endpoints()); CALL(test_sock_udp_create__only_local()); + CALL(test_sock_udp_create__only_local_port0()); CALL(test_sock_udp_create__only_local_reuse_ep()); CALL(test_sock_udp_create__only_remote()); CALL(test_sock_udp_create__full()); diff --git a/tests/lwip_sock_udp/main.c b/tests/lwip_sock_udp/main.c index 77416057ba97fddb95c2d3c5836b033e01d6853f..202b23627bb789e09e0d1be9364a6638c79d06bb 100644 --- a/tests/lwip_sock_udp/main.c +++ b/tests/lwip_sock_udp/main.c @@ -117,6 +117,21 @@ static void test_sock_udp_create4__only_local(void) assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); } +static void test_sock_udp_create4__only_local_port0(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET, + .port = 0U }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(AF_INET == ep.family); + assert(0 == ep.addr.ipv4_u32); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(0U != ep.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); +} + static void test_sock_udp_create4__only_local_reuse_ep(void) { static const sock_udp_ep_t local = { .family = AF_INET, @@ -694,6 +709,22 @@ static void test_sock_udp_create6__only_local(void) assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); } +static void test_sock_udp_create6__only_local_port0(void) +{ + static const sock_udp_ep_t local = { .family = AF_INET6, + .port = 0U }; + sock_udp_ep_t ep; + + assert(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP)); + assert(0 == sock_udp_get_local(&_sock, &ep)); + assert(AF_INET6 == ep.family); + assert(memcmp(&ipv6_addr_unspecified, &ep.addr.ipv6, + sizeof(ipv6_addr_t)) == 0); + assert(SOCK_ADDR_ANY_NETIF == ep.netif); + assert(0U != ep.port); + assert(-ENOTCONN == sock_udp_get_remote(&_sock, &ep)); +} + static void test_sock_udp_create6__only_local_reuse_ep(void) { static const sock_udp_ep_t local = { .family = AF_INET6, @@ -1256,6 +1287,7 @@ int main(void) CALL(test_sock_udp_create4__EINVAL_netif()); CALL(test_sock_udp_create4__no_endpoints()); CALL(test_sock_udp_create4__only_local()); + CALL(test_sock_udp_create4__only_local_port0()); CALL(test_sock_udp_create4__only_local_reuse_ep()); CALL(test_sock_udp_create4__only_remote()); CALL(test_sock_udp_create4__full()); @@ -1301,6 +1333,7 @@ int main(void) CALL(test_sock_udp_create6__EINVAL_netif()); CALL(test_sock_udp_create6__no_endpoints()); CALL(test_sock_udp_create6__only_local()); + CALL(test_sock_udp_create6__only_local_port0()); CALL(test_sock_udp_create6__only_local_reuse_ep()); CALL(test_sock_udp_create6__only_remote()); CALL(test_sock_udp_create6__full());