diff --git a/sys/posix/include/sys/socket.h b/sys/posix/include/sys/socket.h index e9ba8cba96d7c2baad577023cb480cd094ff9052..1bd9ea8009b93c0a239b0b9432865525c4f72e67 100644 --- a/sys/posix/include/sys/socket.h +++ b/sys/posix/include/sys/socket.h @@ -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); /** @} */ diff --git a/sys/posix/sockets/posix_sockets.c b/sys/posix/sockets/posix_sockets.c index 094da7df2ef90e121cf803bcaca5d1af37a5db58..2295522ba9e37c364ed9abd0ed5bd9b443b2d829 100644 --- a/sys/posix/sockets/posix_sockets.c +++ b/sys/posix/sockets/posix_sockets.c @@ -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 +} + /** * @} */