]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib/util: add samba_socket_{poll,sock,poll_or_sock}_error()
authorStefan Metzmacher <metze@samba.org>
Thu, 12 Jan 2023 10:14:06 +0000 (11:14 +0100)
committerRalph Boehme <slow@samba.org>
Tue, 24 Oct 2023 09:36:37 +0000 (09:36 +0000)
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 <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/util/util_net.c
lib/util/util_net.h

index 8a34855b8faff4a9e8df49d35c7fd2e6105f3b7b..acaa76ea74eef437f0a33802459987e09877e4a1 100644 (file)
@@ -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;
+}
index c95d90907fab3bb347b29cdf1467f191ad921e9f..1aed45a432c0abba88323d6130e3df92fa9aa985 100644 (file)
@@ -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_ */