lkml.org 
[lkml]   [1999]   [Oct]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
SubjectRe: [patch] fix for accept on unix-domain sockets
Date
On Thu, 28 Oct 1999, kuznet@ms2.inr.ac.ru wrote:
>> The reason is, that skb_recv_datagram is used get incoming connection requests, but this checks
>> if a SOCK_STREAM socket is in TCP_ESTABLISHED state before waiting.
>
>Opla! Thank you.
>
>The patch is incorrect (racy), but you can make correct one
>if copy part of skb_recv_datagram, omitting offending line
>and some useless checks (f.e. sk->shutdown, socket_error() etc)

Ok, here is my corrected version.
Is it possible to make a generic race-free skb_wait_datagram function, because some other
protocols might need this too for their accept call (ax25, x25, irda, rose, spx)

Lars--- linux.orig/net/unix/af_unix.c Thu Oct 28 18:25:11 1999
+++ linux/net/unix/af_unix.c Fri Oct 29 07:56:51 1999
@@ -942,10 +942,46 @@
sockb->state=SS_CONNECTED;
}
return 0;
}

+/*
+ * Wait for a packet..
+ */
+
+static int unix_wait_for_connect(struct sock * sk, int *err)
+{
+ int error;
+
+ DECLARE_WAITQUEUE(wait, current);
+
+ __set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(sk->sleep, &wait);
+
+ if (!skb_queue_empty(&sk->receive_queue))
+ goto ready;
+
+ /* handle signals */
+ error = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto out;
+
+ schedule();
+
+ready:
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+ return 0;
+
+out:
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
+ *err = error;
+ 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 +995,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;
\
 
 \ /
  Last update: 2005-03-22 13:54    [W:0.182 / U:0.212 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site