Subject: connect() problems.
To: None <tech-kern@netbsd.org>
From: None <ragge@ludd.luth.se>
List: tech-kern
Date: 05/15/2004 11:34:07
If the connect() system call is interrupted by a signal, the connect
attempt is terminated and a new connect() call needs to be done.

But, if there is for example a process that needs frequent timer 
interrupts, and the machine to connect to do not respond until
the next timer interrupt has been delivered the process can never
connect to it.

Posix specifies that if a connect() call is interrupted, the connection
attempt shall not be aborted but instead be established asynchronously.

The patch below is what solves the problem and also makes connect()
more posix conformant.  It is the same solution that solved the
problem in FreeBSD. Comments?

-- Ragge


Index: uipc_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.86
diff -c -r1.86 uipc_syscalls.c
*** uipc_syscalls.c	29 Nov 2003 10:02:42 -0000	1.86
--- uipc_syscalls.c	7 May 2004 13:51:14 -0000
***************
*** 272,284 ****
  	struct socket	*so;
  	struct mbuf	*nam;
  	int		error, s;
  
  	p = l->l_proc;
  	/* getsock() will use the descriptor for us */
  	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
  		return (error);
  	so = (struct socket *)fp->f_data;
! 	if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
  		error = EALREADY;
  		goto out;
  	}
--- 272,285 ----
  	struct socket	*so;
  	struct mbuf	*nam;
  	int		error, s;
+ 	int		interrupted = 0;
  
  	p = l->l_proc;
  	/* getsock() will use the descriptor for us */
  	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
  		return (error);
  	so = (struct socket *)fp->f_data;
! 	if (so->so_state & SS_ISCONNECTING) {
  		error = EALREADY;
  		goto out;
  	}
***************
*** 299,306 ****
  	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
  		error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
  			       netcon, 0);
! 		if (error)
  			break;
  	}
  	if (error == 0) {
  		error = so->so_error;
--- 300,310 ----
  	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
  		error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
  			       netcon, 0);
! 		if (error) {
! 			if (error == EINTR || error == ERESTART)
! 				interrupted = 1;
  			break;
+ 		}
  	}
  	if (error == 0) {
  		error = so->so_error;
***************
*** 308,314 ****
  	}
  	splx(s);
   bad:
! 	so->so_state &= ~SS_ISCONNECTING;
  	m_freem(nam);
  	if (error == ERESTART)
  		error = EINTR;
--- 312,319 ----
  	}
  	splx(s);
   bad:
! 	if (!interrupted)
! 		so->so_state &= ~SS_ISCONNECTING;
  	m_freem(nam);
  	if (error == ERESTART)
  		error = EINTR;