mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
UDP-RECVFROM with fork sometimes terminated - handle EINTR on recvmsg()
This commit is contained in:
parent
9502d092a2
commit
45d87df2fd
3 changed files with 40 additions and 25 deletions
5
CHANGES
5
CHANGES
|
@ -4,6 +4,11 @@ Corrections:
|
|||
terminating \0 Byte was written behind the last position.
|
||||
Thanks to Martin Liška for sending the address sanitizer report.
|
||||
|
||||
UDP-RECVFROM with fork sometimes terminated when multiple packets
|
||||
arrived. This issue was introduced with a bug fix in version 1.7.4.0.
|
||||
Reason was not handling EAGAIN on recvmsg().
|
||||
Thanks to Jamie McQuillan for reporting this issue.
|
||||
|
||||
Porting:
|
||||
OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain
|
||||
conditions: client connection to server with certificate with empty
|
||||
|
|
29
xio-socket.c
29
xio-socket.c
|
@ -693,6 +693,7 @@ int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
#endif /* WITH_GENERICSOCKET */
|
||||
|
||||
/* EINTR not handled specially */
|
||||
int xiogetpacketinfo(int fd)
|
||||
{
|
||||
#if defined(MSG_ERRQUEUE)
|
||||
|
@ -1245,6 +1246,7 @@ void xiosigaction_hasread(int signum
|
|||
return;
|
||||
}
|
||||
if (pid == xio_waitingfor) {
|
||||
xio_waitingfor = 0; /* so this child will not set hashappened again */
|
||||
xio_hashappened = true;
|
||||
xio_childstatus = WEXITSTATUS(status);
|
||||
Debug("xiosigaction_hasread() ->");
|
||||
|
@ -1284,6 +1286,7 @@ void xiosigaction_hasread(int signum
|
|||
PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD,
|
||||
PH_CONNECTED, PH_LATE, PH_LATE2
|
||||
OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap
|
||||
EINTR is not handled specially.
|
||||
*/
|
||||
int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
||||
struct sockaddr *us, socklen_t uslen,
|
||||
|
@ -1413,6 +1416,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
socklen_t palen = sizeof(_peername); /* peer address size */
|
||||
char ctrlbuff[1024]; /* ancillary messages */
|
||||
struct msghdr msgh = {0};
|
||||
int rc;
|
||||
|
||||
socket_init(pf, pa);
|
||||
|
||||
|
@ -1423,6 +1427,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
drop = true;
|
||||
}
|
||||
|
||||
Info("Recvfrom: Checking/waiting for next packet");
|
||||
/* loop until select()/poll() returns valid */
|
||||
do {
|
||||
struct pollfd readfd;
|
||||
|
@ -1455,15 +1460,15 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
|
||||
msgh.msg_controllen = sizeof(ctrlbuff);
|
||||
#endif
|
||||
if (xiogetpacketsrc(xfd->fd,
|
||||
while ((rc = xiogetpacketsrc(xfd->fd,
|
||||
&msgh,
|
||||
MSG_PEEK
|
||||
#ifdef MSG_TRUNC
|
||||
|MSG_TRUNC
|
||||
#endif
|
||||
) < 0) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
)) < 0 &&
|
||||
errno == EINTR) ;
|
||||
if (rc < 0) return STAT_RETRYLATER;
|
||||
palen = msgh.msg_namelen;
|
||||
|
||||
Notice1("receiving packet from %s"/*"src"*/,
|
||||
|
@ -1534,9 +1539,9 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
break;
|
||||
}
|
||||
|
||||
/* server: continue loop with listen */
|
||||
xio_waitingfor = pid;
|
||||
|
||||
do {
|
||||
#if HAVE_PSELECT
|
||||
{
|
||||
struct timespec timeout = { LONG_MAX, 0 };
|
||||
|
@ -1546,12 +1551,9 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
#else /* ! HAVE_PSELECT */
|
||||
/* now we are ready to handle signals */
|
||||
Sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||
|
||||
while (!xio_hashappened) {
|
||||
Sleep(1); /* any signal speeds up return */
|
||||
}
|
||||
#endif /* ! HAVE_PSELECT */
|
||||
xio_waitingfor = 0; /* so this child will not set hashappened again */
|
||||
} while (!xio_hashappened) ;
|
||||
xio_hashappened = false;
|
||||
|
||||
if (xio_childstatus != 0) {
|
||||
|
@ -1676,9 +1678,12 @@ int retropt_socket_pf(struct opt *opts, int *pf) {
|
|||
}
|
||||
|
||||
|
||||
/* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
|
||||
the arriving packet. in msgh the msg_name pointer must refer to an (empty)
|
||||
sockaddr storage. */
|
||||
/* This function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
|
||||
the arriving packet, thus it does not "consume" the packet.
|
||||
In msgh the msg_name pointer must refer to an (empty) sockaddr storage.
|
||||
Returns STAT_OK on success, or STAT_RETRYLATER when an error occurred,
|
||||
including EINTR.
|
||||
*/
|
||||
int xiogetpacketsrc(int fd, struct msghdr *msgh, int flags) {
|
||||
char peekbuff[1];
|
||||
#if HAVE_STRUCT_IOVEC
|
||||
|
|
21
xioread.c
21
xioread.c
|
@ -119,6 +119,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
socklen_t fromlen = sizeof(from);
|
||||
char infobuff[256];
|
||||
char ctrlbuff[1024]; /* ancillary messages */
|
||||
int rc;
|
||||
|
||||
msgh.msg_name = &from;
|
||||
msgh.msg_namelen = fromlen;
|
||||
|
@ -128,14 +129,16 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
|
||||
msgh.msg_controllen = sizeof(ctrlbuff);
|
||||
#endif
|
||||
if (xiogetpacketsrc(pipe->fd, &msgh,
|
||||
|
||||
while ((rc = xiogetpacketsrc(pipe->fd, &msgh,
|
||||
MSG_PEEK
|
||||
#ifdef MSG_TRUNC
|
||||
|MSG_TRUNC
|
||||
#endif
|
||||
) < 0) {
|
||||
return -1;
|
||||
}
|
||||
)) < 0 &&
|
||||
errno == EINTR) ;
|
||||
if (rc < 0) return -1;
|
||||
|
||||
do {
|
||||
bytes =
|
||||
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
|
||||
|
@ -319,6 +322,7 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
char infobuff[256];
|
||||
struct msghdr msgh = {0};
|
||||
char ctrlbuff[1024]; /* ancillary messages */
|
||||
int rc;
|
||||
|
||||
socket_init(pipe->para.socket.la.soa.sa_family, &from);
|
||||
/* get source address */
|
||||
|
@ -330,14 +334,15 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
|
|||
#if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
|
||||
msgh.msg_controllen = sizeof(ctrlbuff);
|
||||
#endif
|
||||
if (xiogetpacketsrc(pipe->fd, &msgh,
|
||||
while ((rc = xiogetpacketsrc(pipe->fd, &msgh,
|
||||
MSG_PEEK
|
||||
#ifdef MSG_TRUNC
|
||||
|MSG_TRUNC
|
||||
#endif
|
||||
) < 0) {
|
||||
return -1;
|
||||
}
|
||||
)) < 0 &&
|
||||
errno == EINTR) ;
|
||||
if (rc < 0) return -1;
|
||||
|
||||
xiodopacketinfo(&msgh, true, false);
|
||||
if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) {
|
||||
Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */
|
||||
|
|
Loading…
Reference in a new issue