Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/net/net_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ __net_socket struct net_context {
#endif
#if defined(CONFIG_NET_CONTEXT_RCVTIMEO)
k_timeout_t rcvtimeo;
#endif
#if defined(CONFIG_NET_CONTEXT_SNDTIMEO)
k_timeout_t sndtimeo;
#endif
} options;

Expand Down Expand Up @@ -1048,6 +1051,7 @@ enum net_context_option {
NET_OPT_TXTIME = 3,
NET_OPT_SOCKS5 = 4,
NET_OPT_RCVTIMEO = 5,
NET_OPT_SNDTIMEO = 6,
};

/**
Expand Down
2 changes: 2 additions & 0 deletions include/net/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,8 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst,
* Applies to receive functions like recv(), but not to connect()
*/
#define SO_RCVTIMEO 20
/** sockopt: Send timeout */
#define SO_SNDTIMEO 21

/** sockopt: Timestamp TX packets */
#define SO_TIMESTAMPING 37
Expand Down
8 changes: 8 additions & 0 deletions subsys/net/ip/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,14 @@ config NET_CONTEXT_RCVTIMEO
sockets timeout is configured per socket with
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, ...) function.

config NET_CONTEXT_SNDTIMEO
bool "Add SNDTIMEO support to net_context"
help
It is possible to time out sending a network packet. The timeout
time is configurable run-time in the application code. For network
sockets timeout is configured per socket with
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, ...) function.

config NET_TEST
bool "Network Testing"
help
Expand Down
41 changes: 41 additions & 0 deletions subsys/net/ip/net_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ int net_context_get(sa_family_t family,
#if defined(CONFIG_NET_CONTEXT_RCVTIMEO)
contexts[i].options.rcvtimeo = K_FOREVER;
#endif
#if defined(CONFIG_NET_CONTEXT_SNDTIMEO)
contexts[i].options.sndtimeo = K_FOREVER;
#endif

if (IS_ENABLED(CONFIG_NET_IPV6) ||
IS_ENABLED(CONFIG_NET_IPV4)) {
Expand Down Expand Up @@ -1235,6 +1238,22 @@ static int get_context_rcvtimeo(struct net_context *context,
#endif
}

static int get_context_sndtimeo(struct net_context *context,
void *value, size_t *len)
{
#if defined(CONFIG_NET_CONTEXT_SNDTIMEO)
*((k_timeout_t *)value) = context->options.sndtimeo;

if (len) {
*len = sizeof(k_timeout_t);
}

return 0;
#else
return -ENOTSUP;
#endif
}

/* If buf is not NULL, then use it. Otherwise read the data to be written
* to net_pkt from msghdr.
*/
Expand Down Expand Up @@ -2186,6 +2205,22 @@ static int set_context_rcvtimeo(struct net_context *context,
#endif
}

static int set_context_sndtimeo(struct net_context *context,
const void *value, size_t len)
{
#if defined(CONFIG_NET_CONTEXT_SNDTIMEO)
if (len != sizeof(k_timeout_t)) {
return -EINVAL;
}

context->options.sndtimeo = *((k_timeout_t *)value);

return 0;
#else
return -ENOTSUP;
#endif
}

int net_context_set_option(struct net_context *context,
enum net_context_option option,
const void *value, size_t len)
Expand Down Expand Up @@ -2216,6 +2251,9 @@ int net_context_set_option(struct net_context *context,
case NET_OPT_RCVTIMEO:
ret = set_context_rcvtimeo(context, value, len);
break;
case NET_OPT_SNDTIMEO:
ret = set_context_sndtimeo(context, value, len);
break;
}

k_mutex_unlock(&context->lock);
Expand Down Expand Up @@ -2253,6 +2291,9 @@ int net_context_get_option(struct net_context *context,
case NET_OPT_RCVTIMEO:
ret = get_context_rcvtimeo(context, value, len);
break;
case NET_OPT_SNDTIMEO:
ret = get_context_sndtimeo(context, value, len);
break;
}

k_mutex_unlock(&context->lock);
Expand Down
34 changes: 34 additions & 0 deletions subsys/net/lib/sockets/sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ ssize_t zsock_sendto_ctx(struct net_context *ctx, const void *buf, size_t len,
if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
} else {
net_context_get_option(ctx, NET_OPT_SNDTIMEO, &timeout, NULL);
buf_timeout = z_timeout_end_calc(MAX_WAIT_BUFS);
}

Expand Down Expand Up @@ -684,6 +685,8 @@ ssize_t zsock_sendmsg_ctx(struct net_context *ctx, const struct msghdr *msg,

if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
} else {
net_context_get_option(ctx, NET_OPT_SNDTIMEO, &timeout, NULL);
}

status = net_context_sendmsg(ctx, msg, flags, NULL, timeout, NULL);
Expand Down Expand Up @@ -1659,6 +1662,37 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname,

break;

case SO_SNDTIMEO:
if (IS_ENABLED(CONFIG_NET_CONTEXT_SNDTIMEO)) {
const struct zsock_timeval *tv = optval;
k_timeout_t timeout;

if (optlen != sizeof(struct zsock_timeval)) {
errno = EINVAL;
return -1;
}

if (tv->tv_sec == 0 && tv->tv_usec == 0) {
timeout = K_FOREVER;
} else {
timeout = K_USEC(tv->tv_sec * 1000000ULL
+ tv->tv_usec);
}

ret = net_context_set_option(ctx,
NET_OPT_SNDTIMEO,
&timeout,
sizeof(timeout));
if (ret < 0) {
errno = -ret;
return -1;
}

return 0;
}

break;

case SO_TXTIME:
if (IS_ENABLED(CONFIG_NET_CONTEXT_TXTIME)) {
ret = net_context_set_option(ctx,
Expand Down
2 changes: 2 additions & 0 deletions subsys/net/lib/sockets/sockets_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ ssize_t zcan_sendto_ctx(struct net_context *ctx, const void *buf, size_t len,

if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
} else {
net_context_get_option(ctx, NET_OPT_SNDTIMEO, &timeout, NULL);
}

if (addrlen == 0) {
Expand Down
4 changes: 4 additions & 0 deletions subsys/net/lib/sockets/sockets_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ ssize_t zpacket_sendto_ctx(struct net_context *ctx, const void *buf, size_t len,

if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
} else {
net_context_get_option(ctx, NET_OPT_SNDTIMEO, &timeout, NULL);
}

/* Register the callback before sending in order to receive the response
Expand Down Expand Up @@ -181,6 +183,8 @@ ssize_t zpacket_sendmsg_ctx(struct net_context *ctx, const struct msghdr *msg,

if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) {
timeout = K_NO_WAIT;
} else {
net_context_get_option(ctx, NET_OPT_SNDTIMEO, &timeout, NULL);
}

status = net_context_sendmsg(ctx, msg, flags, NULL, timeout, NULL);
Expand Down
1 change: 1 addition & 0 deletions tests/net/socket/udp/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ CONFIG_TEST_USERSPACE=y
CONFIG_NET_CONTEXT_PRIORITY=y
CONFIG_NET_CONTEXT_TXTIME=y
CONFIG_NET_CONTEXT_RCVTIMEO=y
CONFIG_NET_CONTEXT_SNDTIMEO=y
38 changes: 38 additions & 0 deletions tests/net/socket/udp/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,43 @@ void test_so_rcvtimeo(void)
zassert_equal(rv, 0, "close failed");
}

void test_so_sndtimeo(void)
{
struct sockaddr_in bind_addr4;
struct sockaddr_in6 bind_addr6;
int sock1, sock2, rv;

struct timeval optval = {
.tv_sec = 2,
.tv_usec = 500000,
};

prepare_sock_udp_v4(CONFIG_NET_CONFIG_MY_IPV4_ADDR, 55555,
&sock1, &bind_addr4);
prepare_sock_udp_v6(CONFIG_NET_CONFIG_MY_IPV6_ADDR, 55555,
&sock2, &bind_addr6);

rv = bind(sock1, (struct sockaddr *)&bind_addr4, sizeof(bind_addr4));
zassert_equal(rv, 0, "bind failed");

rv = bind(sock2, (struct sockaddr *)&bind_addr6, sizeof(bind_addr6));
zassert_equal(rv, 0, "bind failed");

rv = setsockopt(sock1, SOL_SOCKET, SO_SNDTIMEO, &optval,
sizeof(optval));
zassert_equal(rv, 0, "setsockopt failed (%d)", errno);

optval.tv_usec = 0;
rv = setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, &optval,
sizeof(optval));
zassert_equal(rv, 0, "setsockopt failed");

rv = close(sock1);
zassert_equal(rv, 0, "close failed");
rv = close(sock2);
zassert_equal(rv, 0, "close failed");
}

void test_so_protocol(void)
{
struct sockaddr_in bind_addr4;
Expand Down Expand Up @@ -1090,6 +1127,7 @@ void test_main(void)
ztest_unit_test(test_so_priority),
ztest_unit_test(test_so_txtime),
ztest_unit_test(test_so_rcvtimeo),
ztest_unit_test(test_so_sndtimeo),
ztest_unit_test(test_so_protocol),
ztest_unit_test(test_v4_sendmsg_recvfrom),
ztest_user_unit_test(test_v4_sendmsg_recvfrom),
Expand Down