From 5e8284b2689a3a73fc7763a8fe4743d6d3544a7d Mon Sep 17 00:00:00 2001 From: guenther Date: Tue, 9 Aug 2016 02:25:35 +0000 Subject: [PATCH] When interrupted, connect() should leave the socket connecting in the background, similar to a non-blocking socket. Return EALREADY whenever already connecting, not just for non-blocking sockets. Fix from {Free,Net}BSD Prompted by a report from Michael Reed (m.reed (at) mykolab.com) ok millert@ --- regress/lib/libpthread/restart/connect/connect.c | 7 +++++-- sys/kern/uipc_syscalls.c | 14 +++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/regress/lib/libpthread/restart/connect/connect.c b/regress/lib/libpthread/restart/connect/connect.c index dfa62040a47..e1ef9ac2830 100644 --- a/regress/lib/libpthread/restart/connect/connect.c +++ b/regress/lib/libpthread/restart/connect/connect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: connect.c,v 1.1 2011/09/18 16:36:58 fgsch Exp $ */ +/* $OpenBSD: connect.c,v 1.2 2016/08/09 02:25:35 guenther Exp $ */ /* * Federico G. Schwindt , 2011. Public Domain. */ @@ -30,7 +30,10 @@ thr_connect(void *arg) sa.sin_port = htons(23); sa.sin_addr.s_addr = htonl(0xc7b98903); /* cvs.openbsd.org */ ASSERT(connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1); - return ((caddr_t)NULL + errno); + int err = errno; + ASSERT(connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1); + ASSERT(errno == EALREADY); + return ((caddr_t)NULL + err); } int diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index b00760dd939..a2505fe851b 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_syscalls.c,v 1.132 2016/05/18 01:13:13 millert Exp $ */ +/* $OpenBSD: uipc_syscalls.c,v 1.133 2016/08/09 02:25:35 guenther Exp $ */ /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ /* @@ -367,12 +367,12 @@ sys_connect(struct proc *p, void *v, register_t *retval) struct file *fp; struct socket *so; struct mbuf *nam = NULL; - int error, s; + int error, s, interrupted = 0; if ((error = getsock(p, SCARG(uap, s), &fp)) != 0) return (error); so = fp->f_data; - if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + if (so->so_state & SS_ISCONNECTING) { FRELE(fp, p); return (EALREADY); } @@ -409,8 +409,11 @@ sys_connect(struct proc *p, void *v, register_t *retval) s = splsoftnet(); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { error = tsleep(&so->so_timeo, PSOCK | PCATCH, "netcon2", 0); - if (error) + if (error) { + if (error == EINTR || error == ERESTART) + interrupted = 1; break; + } } if (error == 0) { error = so->so_error; @@ -418,7 +421,8 @@ sys_connect(struct proc *p, void *v, register_t *retval) } splx(s); bad: - so->so_state &= ~SS_ISCONNECTING; + if (!interrupted) + so->so_state &= ~SS_ISCONNECTING; FRELE(fp, p); if (nam) m_freem(nam); -- 2.20.1