patch-1.3.96 linux/net/ipv4/tcp.c
Next file: linux/net/socket.c
Previous file: linux/net/ipv4/ip_sockglue.c
Back to the patch index
Back to the overall index
- Lines: 337
- Date:
Fri Apr 26 14:07:30 1996
- Orig file:
v1.3.95/linux/net/ipv4/tcp.c
- Orig date:
Sun Apr 21 12:39:03 1996
diff -u --recursive --new-file v1.3.95/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
@@ -437,12 +437,6 @@
static void tcp_close(struct sock *sk, unsigned long timeout);
/*
- * The less said about this the better, but it works and will do for 1.2 (and 1.4 ;))
- */
-
-struct wait_queue *master_select_wakeup;
-
-/*
* Find someone to 'accept'. Must be called with
* the socket locked or with interrupts disabled
*/
@@ -463,24 +457,6 @@
}
/*
- * Remove a completed connection and return it. This is used by
- * tcp_accept() to get connections from the queue.
- */
-
-static struct sk_buff *tcp_dequeue_established(struct sock *s)
-{
- struct sk_buff *skb;
- unsigned long flags;
- save_flags(flags);
- cli();
- skb=tcp_find_established(s);
- if(skb!=NULL)
- skb_unlink(skb); /* Take it off the queue */
- restore_flags(flags);
- return skb;
-}
-
-/*
* This routine closes sockets which have been at least partially
* opened, but not yet accepted. Currently it is only called by
* tcp_close, and timeout mirrors the value there.
@@ -685,14 +661,15 @@
static int tcp_listen_select(struct sock *sk, int sel_type, select_table *wait)
{
if (sel_type == SEL_IN) {
- int retval;
+ struct sk_buff * skb;
lock_sock(sk);
- retval = (tcp_find_established(sk) != NULL);
+ skb = tcp_find_established(sk);
release_sock(sk);
- if (!retval)
- select_wait(&master_select_wakeup,wait);
- return retval;
+ if (skb)
+ return 1;
+ select_wait(sk->sleep,wait);
+ return 0;
}
return 0;
}
@@ -895,31 +872,53 @@
* and starts the transmit system.
*/
-static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg,
- int len, int nonblock, int flags)
+static int do_tcp_sendmsg(struct sock *sk,
+ int iovlen, struct iovec *iov,
+ int len, int nonblock, int flags)
{
int copied = 0;
- int copy;
- int tmp;
- int seglen;
- int iovct=0;
- struct sk_buff *skb;
- struct sk_buff *send_tmp;
- struct proto *prot;
struct device *dev = NULL;
- unsigned char *from;
+
+ /*
+ * Wait for a connection to finish.
+ */
+ while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
+ {
+ if (sk->err)
+ return sock_error(sk);
+
+ if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
+ {
+ if (sk->keepopen)
+ send_sig(SIGPIPE, current, 0);
+ return -EPIPE;
+ }
+
+ if (nonblock)
+ return -EAGAIN;
+
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+
+ wait_for_tcp_connect(sk);
+ }
/*
* Ok commence sending
*/
- while(iovct<msg->msg_iovlen)
+ while (--iovlen >= 0)
{
- seglen=msg->msg_iov[iovct].iov_len;
- from=msg->msg_iov[iovct++].iov_base;
- prot = sk->prot;
+ int seglen=iov->iov_len;
+ unsigned char * from=iov->iov_base;
+ iov++;
+
while(seglen > 0)
{
+ int copy, delay;
+ int tmp;
+ struct sk_buff *skb;
+
/*
* Stop on errors
*/
@@ -940,33 +939,6 @@
return -EPIPE;
}
- /*
- * Wait for a connection to finish.
- */
- while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
- {
- if (copied)
- return copied;
-
- if (sk->err)
- return sock_error(sk);
-
- if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
- {
- if (sk->keepopen)
- send_sig(SIGPIPE, current, 0);
- return -EPIPE;
- }
-
- if (nonblock)
- return -EAGAIN;
-
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
-
- wait_for_tcp_connect(sk);
- }
-
/*
* The following code can result in copy <= if sk->mss is ever
* decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window).
@@ -1055,20 +1027,18 @@
return -EFAULT;
}
- /*
- * We should really check the window here also.
- */
+ /*
+ * We should really check the window here also.
+ */
- send_tmp = NULL;
+ delay = 0;
+ tmp = copy + sk->prot->max_header + 15;
if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out)
{
- skb = sock_wmalloc(sk, sk->mtu + 128 + prot->max_header + 15, 0, GFP_KERNEL);
- send_tmp = skb;
- }
- else
- {
- skb = sock_wmalloc(sk, copy + prot->max_header + 15 , 0, GFP_KERNEL);
+ tmp = tmp - copy + sk->mtu + 128;
+ delay = 1;
}
+ skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
/*
* If we didn't get any memory, we need to sleep.
@@ -1104,7 +1074,7 @@
* Perhaps some hints here would be good.
*/
- tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
+ tmp = sk->prot->build_header(skb, sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt, skb->truesize,sk->ip_tos,sk->ip_ttl,&sk->ip_route_cache);
if (tmp < 0 )
{
@@ -1143,9 +1113,9 @@
skb->free = 0;
sk->write_seq += copy;
- if (send_tmp != NULL)
+ if (delay)
{
- tcp_enqueue_partial(send_tmp, sk);
+ tcp_enqueue_partial(skb, sk);
continue;
}
tcp_send_skb(sk, skb);
@@ -1186,7 +1156,7 @@
}
lock_sock(sk);
- retval = do_tcp_sendmsg(sk, msg, len, nonblock, flags);
+ retval = do_tcp_sendmsg(sk, msg->msg_iovlen, msg->msg_iov, len, nonblock, flags);
/*
* Nagle's rule. Turn Nagle off with TCP_NODELAY for highly
@@ -1798,62 +1768,79 @@
/*
+ * Wait for a incoming connection, avoid race
+ * conditions. This must be called with the socket
+ * locked.
+ */
+static struct sk_buff * wait_for_connect(struct sock * sk)
+{
+ struct wait_queue wait = { current, NULL };
+ struct sk_buff * skb = NULL;
+
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ release_sock(sk);
+ schedule();
+ lock_sock(sk);
+ skb = tcp_find_established(sk);
+ if (skb)
+ break;
+ if (current->signal & ~current->blocked)
+ break;
+ }
+ remove_wait_queue(sk->sleep, &wait);
+ return skb;
+}
+
+/*
* This will accept the next outstanding connection.
+ *
+ * Be careful about race conditions here - this is subtle.
*/
static struct sock *tcp_accept(struct sock *sk, int flags)
{
- struct sock *newsk;
+ int error;
struct sk_buff *skb;
+ struct sock *newsk = NULL;
/*
* We need to make sure that this socket is listening,
* and that it has something pending.
*/
+ error = EINVAL;
if (sk->state != TCP_LISTEN)
- {
- sk->err = EINVAL;
- return(NULL);
- }
+ goto no_listen;
- /* Avoid the race. */
- cli();
lock_sock(sk);
- while((skb = tcp_dequeue_established(sk)) == NULL)
- {
- if (flags & O_NONBLOCK)
- {
- sti();
- release_sock(sk);
- sk->err = EAGAIN;
- return(NULL);
- }
-
+ skb = tcp_find_established(sk);
+ if (skb) {
+got_new_connect:
+ __skb_unlink(skb, &sk->receive_queue);
+ newsk = skb->sk;
+ kfree_skb(skb, FREE_READ);
+ sk->ack_backlog--;
+ error = 0;
+out:
release_sock(sk);
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- sk->err = ERESTARTSYS;
- return(NULL);
- }
- lock_sock(sk);
- }
- sti();
-
- /*
- * Now all we need to do is return skb->sk.
- */
-
- newsk = skb->sk;
+no_listen:
+ sk->err = error;
+ return newsk;
+ }
- kfree_skb(skb, FREE_READ);
- sk->ack_backlog--;
- release_sock(sk);
- return(newsk);
+ error = EAGAIN;
+ if (flags & O_NONBLOCK)
+ goto out;
+ skb = wait_for_connect(sk);
+ if (skb)
+ goto got_new_connect;
+ error = ERESTARTSYS;
+ goto out;
}
+
/*
* This will initiate an outgoing connection.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this