summaryrefslogtreecommitdiff
path: root/lib/tsocket/tsocket_bsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tsocket/tsocket_bsd.c')
-rw-r--r--lib/tsocket/tsocket_bsd.c80
1 files changed, 79 insertions, 1 deletions
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index a4c2d0cf336..8ab2ffb0b83 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -24,8 +24,10 @@
#include "replace.h"
#include "system/filesys.h"
#include "system/network.h"
+#include "system/select.h"
#include "tsocket.h"
#include "tsocket_internal.h"
+#include "lib/util/select.h"
#include "lib/util/iov_buf.h"
#include "lib/util/blocking.h"
#include "lib/util/util_net.h"
@@ -171,7 +173,42 @@ static ssize_t tsocket_bsd_netlink_pending(int fd)
}
#endif
-static ssize_t tsocket_bsd_error(int fd)
+static int tsocket_bsd_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;
+}
+
+static int tsocket_bsd_sock_error(int fd)
{
int ret, error = 0;
socklen_t len = sizeof(error);
@@ -192,6 +229,47 @@ static ssize_t tsocket_bsd_error(int fd)
return 0;
}
+static int tsocket_bsd_error(int fd)
+{
+ int ret;
+ int poll_error = 0;
+
+ poll_error = tsocket_bsd_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 = tsocket_bsd_sock_error(fd);
+ if (ret == 0) {
+ errno = EPIPE;
+ }
+
+ if (errno == 0) {
+ errno = EPIPE;
+ }
+
+ return -1;
+}
+
static ssize_t tsocket_bsd_pending(int fd)
{
int ret;