--- linux.orig/net/unix/af_unix.c Mon Dec 13 08:28:11 1999 +++ linux/net/unix/af_unix.c Mon Dec 13 09:10:55 1999 @@ -43,10 +43,11 @@ * number of socks to 2*max_files and * the number of skb queueable in the * dgram receiver. * Artur Skawina : Hash function optimizations * Alexey Kuznetsov : Full scale SMP. Lot of bugs are introduced 8) + * Lars Heete : Fix for unix_accept bug. * * * Known differences from reference BSD that was tested: * * [TO FIX] @@ -942,10 +943,37 @@ sockb->state=SS_CONNECTED; } return 0; } +/* + * Wait for a packet.. + */ + +static int unix_wait_for_connect(struct sock * sk, int *err) +{ + int error = 0; + DECLARE_WAITQUEUE(wait, current); + + __set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(sk->sleep, &wait); + + if (skb_queue_empty(&sk->receive_queue)) { + /* handle signals */ + if (signal_pending(current)) { + error = *err = -ERESTARTSYS; + } + else { + schedule(); + } + } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sleep, &wait); + return error; +} + + static int unix_accept(struct socket *sock, struct socket *newsock, int flags) { unix_socket *sk = sock->sk; unix_socket *tsk; struct sk_buff *skb; @@ -959,20 +987,28 @@ if (sk->state!=TCP_LISTEN) goto out; /* If socket state is TCP_LISTEN it cannot change, so that no locks are necessary. + + It's not possible to use skb_recv_datagram here, + because this checks if the socket is connected. */ - - skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err); - if (!skb) - goto out; + + while ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { + if (flags&O_NONBLOCK) { + err = -EAGAIN; + goto out; + } + if (unix_wait_for_connect(sk, &err) != 0) + goto out; + } tsk = skb->sk; + kfree_skb(skb); if (skb_queue_len(&sk->receive_queue) <= sk->max_ack_backlog/2) wake_up_interruptible(&sk->protinfo.af_unix.peer_wait); - skb_free_datagram(sk, skb); /* attach accepted sock to socket */ unix_state_wlock(tsk); newsock->state = SS_CONNECTED; newsock->sk = tsk;