From: Stefan Metzmacher Date: Thu, 12 Jan 2023 10:14:06 +0000 (+0100) Subject: lib/util: add samba_socket_{poll,sock,poll_or_sock}_error() X-Git-Tag: talloc-2.4.2~1196 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f8213ec871016cfa380b85334192cc72589ddb7f;p=thirdparty%2Fsamba.git lib/util: add samba_socket_{poll,sock,poll_or_sock}_error() These are copies of the static functions in lib/tsocket/tsocket_bsd.c, which we will replace in the next commit. Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme Reviewed-by: Andrew Bartlett --- diff --git a/lib/util/util_net.c b/lib/util/util_net.c index 8a34855b8fa..acaa76ea74e 100644 --- a/lib/util/util_net.c +++ b/lib/util/util_net.c @@ -27,6 +27,8 @@ #include "system/network.h" #include "system/locale.h" #include "system/filesys.h" +#include "system/select.h" +#include "lib/util/select.h" #include "lib/util/util_net.h" #undef strcasecmp @@ -1136,3 +1138,100 @@ bool samba_sockaddr_get_port(const struct samba_sockaddr *sa, uint16_t *port) #endif return false; } + +int samba_socket_poll_error(int fd) +{ + struct pollfd pfd = { + .fd = fd, +#ifdef POLLRDHUP + .events = POLLRDHUP, /* POLLERR and POLLHUP are not needed */ +#endif + }; + int ret; + + errno = 0; + ret = sys_poll_intr(&pfd, 1, 0); + if (ret == 0) { + return 0; + } + if (ret != 1) { + return POLLNVAL; + } + + if (pfd.revents & POLLERR) { + return POLLERR; + } + if (pfd.revents & POLLHUP) { + return POLLHUP; + } +#ifdef POLLRDHUP + if (pfd.revents & POLLRDHUP) { + return POLLRDHUP; + } +#endif + + /* should never be reached! */ + return POLLNVAL; +} + +int samba_socket_sock_error(int fd) +{ + int ret, error = 0; + socklen_t len = sizeof(error); + + /* + * if no data is available check if the socket is in error state. For + * dgram sockets it's the way to return ICMP error messages of + * connected sockets to the caller. + */ + ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len); + if (ret == -1) { + return ret; + } + if (error != 0) { + errno = error; + return -1; + } + return 0; +} + +int samba_socket_poll_or_sock_error(int fd) +{ + int ret; + int poll_error = 0; + + poll_error = samba_socket_poll_error(fd); + if (poll_error == 0) { + return 0; + } + +#ifdef POLLRDHUP + if (poll_error == POLLRDHUP) { + errno = ECONNRESET; + return -1; + } +#endif + + if (poll_error == POLLHUP) { + errno = EPIPE; + return -1; + } + + /* + * POLLERR and POLLNVAL fallback to + * getsockopt(fd, SOL_SOCKET, SO_ERROR) + * and force EPIPE as fallback. + */ + + errno = 0; + ret = samba_socket_sock_error(fd); + if (ret == 0) { + errno = EPIPE; + } + + if (errno == 0) { + errno = EPIPE; + } + + return -1; +} diff --git a/lib/util/util_net.h b/lib/util/util_net.h index c95d90907fa..1aed45a432c 100644 --- a/lib/util/util_net.h +++ b/lib/util/util_net.h @@ -128,4 +128,18 @@ bool sockaddr_storage_to_samba_sockaddr( bool samba_sockaddr_set_port(struct samba_sockaddr *sa, uint16_t port); bool samba_sockaddr_get_port(const struct samba_sockaddr *sa, uint16_t *port); +/* + * check for POLLERR or POLL*HUP + */ +int samba_socket_poll_error(int fd); +/* + * getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) + */ +int samba_socket_sock_error(int fd); +/* + * check for POLL*HUP and fallback to + * getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) + */ +int samba_socket_poll_or_sock_error(int fd); + #endif /* _SAMBA_UTIL_NET_H_ */