1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-14 01:57:53 +03:00

lib/tsocket: check for errors indicated by poll() before getsockopt(fd, SOL_SOCKET, SO_ERROR)

This also returns an error if we got TCP_FIN from the peer,
which is only reported by an explicit POLLRDHUP check.

Also on FreeBSD getsockopt(fd, SOL_SOCKET, SO_ERROR) fetches
and resets the error, so a 2nd call no longer returns an error.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15202

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit 29a65da63d730ecead1e7d4a81a76dd1c8c179ea)
This commit is contained in:
Stefan Metzmacher 2022-10-13 14:46:14 +02:00 committed by Jule Anger
parent 8a4ef3d92e
commit 5c051d3806

View File

@ -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;