Note: this is the second version of this patch.
Apply by doing
cd /usr/src/sys
patch -p0 < accept.patch
And then rebuild your kernel.
Index: sys/socketvar.h
===================================================================
RCS file: /cvs/src/sys/sys/socketvar.h,v
retrieving revision 1.15
diff -u -r1.15 socketvar.h
--- socketvar.h 1999/02/18 22:56:57 1.15
+++ socketvar.h 1999/02/19 03:36:15
@@ -113,6 +113,7 @@
#define SS_CANTSENDMORE 0x010 /* can't send more data to peer */
#define SS_CANTRCVMORE 0x020 /* can't receive more data from peer */
#define SS_RCVATMARK 0x040 /* at mark on input */
+#define SS_ISDISCONNECTED 0x800 /* socket disconnected from peer */
#define SS_PRIV 0x080 /* privileged for broadcast, raw... */
#define SS_NBIO 0x100 /* non-blocking ops */
Index: kern/uipc_socket.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.25
diff -u -r1.25 uipc_socket.c
--- uipc_socket.c 1999/02/18 22:56:58 1.25
+++ uipc_socket.c 1999/02/19 03:36:23
@@ -156,9 +156,13 @@
if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
return;
if (so->so_head) {
- if (!soqremque(so, 0) && !soqremque(so, 1))
- panic("sofree dq");
- so->so_head = 0;
+ /*
+ * We must not decommission a socket that's on the accept(2)
+ * queue. If we do, then accept(2) may hang after select(2)
+ * indicated that the listening socket was ready.
+ */
+ if (!soqremque(so, 0))
+ return;
}
sbrelease(&so->so_snd);
sorflush(so);
@@ -174,14 +178,19 @@
soclose(so)
register struct socket *so;
{
+ struct socket *so2;
int s = splsoftnet(); /* conservative */
int error = 0;
if (so->so_options & SO_ACCEPTCONN) {
- while (so->so_q0)
- (void) soabort(so->so_q0);
- while (so->so_q)
- (void) soabort(so->so_q);
+ while ((so2 = so->so_q0) != NULL) {
+ (void) soqremque(so2, 0);
+ (void) soabort(so2);
+ }
+ while ((so2 = so->so_q) != NULL) {
+ (void) soqremque(so2, 1);
+ (void) soabort(so2);
+ }
}
if (so->so_pcb == 0)
goto discard;
@@ -237,12 +246,14 @@
struct mbuf *nam;
{
int s = splsoftnet();
- int error;
+ int error = 0;
if ((so->so_state & SS_NOFDREF) == 0)
panic("soaccept: !NOFDREF");
so->so_state &= ~SS_NOFDREF;
- error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, NULL, nam, NULL);
+ if ((so->so_state & SS_ISDISCONNECTED) == 0)
+ error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, NULL,
+ nam, NULL);
splx(s);
return (error);
}
Index: kern/uipc_socket2.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket2.c,v
retrieving revision 1.9
diff -u -r1.9 uipc_socket2.c
--- uipc_socket2.c 1999/02/18 22:56:58 1.9
+++ uipc_socket2.c 1999/02/19 03:36:28
@@ -135,7 +135,7 @@
{
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
- so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
+ so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
wakeup((caddr_t)&so->so_timeo);
sowwakeup(so);
sorwakeup(so);