posix: sockets: Implement SO_RCVTIMEO option in setsockopt
AwaLWM2M needs to be polled regularly to check for incoming data. Since RIOT only supports timeout at the GNRC sock layer while the network abstraction for RIOT in AwaLWM2M uses the posix layer, this causes RIOT to be blocked waiting for data that never arrive. This commit implements only the SO_RCVTIMEO option in setsockopt to allow users to set a receive timeout for a socket at the posix layer. Signed-off-by: Francois Berder <francois.berder@imgtec.com>
This commit is contained in:
parent
f20f94477b
commit
c787638696
@ -491,16 +491,8 @@ static inline int getsockopt(int socket, int level, int option_name, void *optio
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int setsockopt(int socket, int level, int option_name, const void *option_value,
|
||||
socklen_t option_len)
|
||||
{
|
||||
(void)socket;
|
||||
(void)level;
|
||||
(void)option_name;
|
||||
(void)option_value;
|
||||
(void)option_len;
|
||||
return -1;
|
||||
}
|
||||
int setsockopt(int socket, int level, int option_name, const void *option_value,
|
||||
socklen_t option_len);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@ -68,6 +68,9 @@ typedef struct {
|
||||
int type;
|
||||
int protocol;
|
||||
bool bound;
|
||||
#ifdef POSIX_SETSOCKOPT
|
||||
uint32_t recv_timeout;
|
||||
#endif
|
||||
socket_sock_t *sock;
|
||||
#ifdef MODULE_SOCK_TCP
|
||||
sock_tcp_t *queue_array;
|
||||
@ -323,6 +326,9 @@ int socket(int domain, int type, int protocol)
|
||||
}
|
||||
s->bound = false;
|
||||
s->sock = NULL;
|
||||
#ifdef POSIX_SETSOCKOPT
|
||||
s->recv_timeout = SOCK_NO_TIMEOUT;
|
||||
#endif
|
||||
#ifdef MODULE_SOCK_TCP
|
||||
if (type == SOCK_STREAM) {
|
||||
s->queue_array = NULL;
|
||||
@ -363,6 +369,13 @@ int accept(int socket, struct sockaddr *restrict address,
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef POSIX_SETSOCKOPT
|
||||
const uint32_t recv_timeout = s->recv_timeout;
|
||||
#else
|
||||
const uint32_t recv_timeout = SOCK_NO_TIMEOUT;
|
||||
#endif
|
||||
|
||||
switch (s->type) {
|
||||
case SOCK_STREAM:
|
||||
new_s = _get_free_socket();
|
||||
@ -372,9 +385,8 @@ int accept(int socket, struct sockaddr *restrict address,
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
/* TODO: apply configured timeout */
|
||||
if ((res = sock_tcp_accept(&s->sock->tcp.queue, &sock,
|
||||
SOCK_NO_TIMEOUT)) < 0) {
|
||||
recv_timeout)) < 0) {
|
||||
errno = -res;
|
||||
res = -1;
|
||||
break;
|
||||
@ -789,11 +801,17 @@ ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags,
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef POSIX_SETSOCKOPT
|
||||
const uint32_t recv_timeout = s->recv_timeout;
|
||||
#else
|
||||
const uint32_t recv_timeout = SOCK_NO_TIMEOUT;
|
||||
#endif
|
||||
|
||||
switch (s->type) {
|
||||
#ifdef MODULE_SOCK_IP
|
||||
case SOCK_RAW:
|
||||
/* TODO: apply configured timeout */
|
||||
if ((res = sock_ip_recv(&s->sock->raw, buffer, length, SOCK_NO_TIMEOUT,
|
||||
if ((res = sock_ip_recv(&s->sock->raw, buffer, length, recv_timeout
|
||||
(sock_ip_ep_t *)&ep)) < 0) {
|
||||
errno = -res;
|
||||
res = -1;
|
||||
@ -802,9 +820,8 @@ ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags,
|
||||
#endif
|
||||
#ifdef MODULE_SOCK_TCP
|
||||
case SOCK_STREAM:
|
||||
/* TODO: apply configured timeout */
|
||||
if ((res = sock_tcp_read(&s->sock->tcp.sock, buffer, length,
|
||||
SOCK_NO_TIMEOUT)) < 0) {
|
||||
recv_timeout)) < 0) {
|
||||
errno = -res;
|
||||
res = -1;
|
||||
}
|
||||
@ -812,8 +829,7 @@ ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags,
|
||||
#endif
|
||||
#ifdef MODULE_SOCK_UDP
|
||||
case SOCK_DGRAM:
|
||||
/* TODO: apply configured timeout */
|
||||
if ((res = sock_udp_recv(&s->sock->udp, buffer, length, SOCK_NO_TIMEOUT,
|
||||
if ((res = sock_udp_recv(&s->sock->udp, buffer, length, recv_timeout,
|
||||
&ep)) < 0) {
|
||||
errno = -res;
|
||||
res = -1;
|
||||
@ -920,6 +936,62 @@ ssize_t sendto(int socket, const void *buffer, size_t length, int flags,
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a partial implementation of setsockopt for changing the receive
|
||||
* timeout value of a socket.
|
||||
*/
|
||||
int setsockopt(int socket, int level, int option_name, const void *option_value,
|
||||
socklen_t option_len)
|
||||
{
|
||||
#ifdef POSIX_SETSOCKOPT
|
||||
socket_t *s;
|
||||
struct timeval *tv;
|
||||
const uint32_t max_timeout_secs = UINT32_MAX / (1000 * 1000);
|
||||
|
||||
if (level != SOL_SOCKET
|
||||
|| option_name != SO_RCVTIMEO) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
if (option_value == NULL
|
||||
|| option_len != sizeof(struct timeval)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mutex_lock(&_socket_pool_mutex);
|
||||
s = _get_socket(socket);
|
||||
mutex_unlock(&_socket_pool_mutex);
|
||||
if (s == NULL) {
|
||||
errno = ENOTSOCK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tv = (struct timeval *) option_value;
|
||||
|
||||
if (tv->tv_sec < 0 || tv->tv_usec < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((uint32_t)tv->tv_sec > max_timeout_secs
|
||||
|| ((uint32_t)tv->tv_sec == max_timeout_secs && (uint32_t)tv->tv_usec > UINT32_MAX - max_timeout_secs * 1000 * 1000)) {
|
||||
errno = EDOM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->recv_timeout = tv->tv_sec * 1000 * 1000 + tv->tv_usec;
|
||||
return 0;
|
||||
#else
|
||||
(void)socket;
|
||||
(void)level;
|
||||
(void)option_name;
|
||||
(void)option_value;
|
||||
(void)option_len;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user