patch-2.1.127 linux/net/ipv4/tcp.c

Next file: linux/net/ipv4/tcp_input.c
Previous file: linux/net/ipv4/sysctl_net_ipv4.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.127 1998/10/04 07:04:32 davem Exp $
+ * Version:	$Id: tcp.c,v 1.130 1998/11/07 14:36:10 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -860,8 +860,8 @@
 			if(copy > seglen)
 				copy = seglen;
 
+			/* Determine how large of a buffer to allocate.  */
 			tmp = MAX_HEADER + sk->prot->max_header;
-			queue_it = 0;
 			if (copy < min(mss_now, tp->max_window >> 1) &&
 			    !(flags & MSG_OOB)) {
 				tmp += min(mss_now, tp->max_window);
@@ -876,6 +876,7 @@
 				queue_it = 1;
 			} else {
 				tmp += copy;
+				queue_it = 0;
 			}
 			skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
 
@@ -1452,7 +1453,7 @@
 	tcp_synq_init(tp);
 }
 
-void tcp_close(struct sock *sk, unsigned long timeout)
+void tcp_close(struct sock *sk, long timeout)
 {
 	struct sk_buff *skb;
 	int data_was_unread = 0;
@@ -1522,7 +1523,6 @@
 		struct task_struct *tsk = current;
 		struct wait_queue wait = { tsk, NULL };
 
-		tsk->timeout = timeout;
 		add_wait_queue(sk->sleep, &wait);
 		release_sock(sk);
 
@@ -1530,12 +1530,11 @@
 			tsk->state = TASK_INTERRUPTIBLE;
 			if (!closing(sk))
 				break;
-			schedule();
-			if (signal_pending(tsk) || !tsk->timeout)
+			timeout = schedule_timeout(timeout);
+			if (signal_pending(tsk) || !timeout)
 				break;
 		}
 
-		tsk->timeout=0;
 		tsk->state = TASK_RUNNING;
 		remove_wait_queue(sk->sleep, &wait);
 		
@@ -1547,8 +1546,8 @@
          */
 	tcp_check_fin_timer(sk);
 
-	sk->dead = 1;
 	release_sock(sk);
+	sk->dead = 1;
 }
 
 /*
@@ -1619,6 +1618,8 @@
 	req->class->destructor(req);
 	tcp_openreq_free(req);
 	sk->ack_backlog--; 
+	if(sk->keepopen)
+		tcp_inc_slow_timer(TCP_SLT_KEEPALIVE);
 
 	/*
 	 * This does not pass any already set errors on the new socket
@@ -1657,48 +1658,86 @@
 		return -EFAULT;
 
 	switch(optname) {
-		case TCP_MAXSEG:
-/* values greater than interface MTU won't take effect.  however at
- * the point when this call is done we typically don't yet know
- * which interface is going to be used
- */
-	  		if(val<1||val>MAX_WINDOW)
-				return -EINVAL;
-			tp->user_mss=val;
-			return 0;
-		case TCP_NODELAY:
-			sk->nonagle=(val==0)?0:1;
-			return 0;
-		default:
-			return(-ENOPROTOOPT);
+	case TCP_MAXSEG:
+		/* values greater than interface MTU won't take effect.  however at
+		 * the point when this call is done we typically don't yet know
+		 * which interface is going to be used
+		 */
+		if(val < 1 || val > MAX_WINDOW)
+			return -EINVAL;
+		tp->user_mss = val;
+		return 0;
+
+	case TCP_NODELAY:
+		/* You cannot try to use this and TCP_CORK in
+		 * tandem, so let the user know.
+		 */
+		if (sk->nonagle == 2)
+			return -EINVAL;
+		sk->nonagle = (val == 0) ? 0 : 1;
+		return 0;
+
+	case TCP_CORK:
+		/* When set indicates to always queue non-full frames.
+		 * Later the user clears this option and we transmit
+		 * any pending partial frames in the queue.  This is
+		 * meant to be used alongside sendfile() to get properly
+		 * filled frames when the user (for example) must write
+		 * out headers with a write() call first and then use
+		 * sendfile to send out the data parts.
+		 *
+		 * You cannot try to use TCP_NODELAY and this mechanism
+		 * at the same time, so let the user know.
+		 */
+		if (sk->nonagle == 1)
+			return -EINVAL;
+		if (val != 0) {
+			sk->nonagle = 2;
+		} else {
+			sk->nonagle = 0;
+
+			if (tp->send_head) {
+				lock_sock(sk);
+				if (tp->send_head &&
+				    tcp_snd_test (sk, tp->send_head))
+					tcp_write_xmit(sk);
+				release_sock(sk);
+			}
+		}
+		return 0;
+
+	default:
+		return -ENOPROTOOPT;
 	};
 }
 
-int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, 
+int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval,
 		   int *optlen)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	int val;
-	int len;
+	int val, len;
 
 	if(level != SOL_TCP)
 		return tp->af_specific->getsockopt(sk, level, optname,
 						   optval, optlen);
-	
+
 	if(get_user(len,optlen))
 		return -EFAULT;
-		
-	len = min(len,sizeof(int));
+
+	len = min(len, sizeof(int));
 
 	switch(optname) {
-		case TCP_MAXSEG:
-			val=tp->user_mss;
-			break;
-		case TCP_NODELAY:
-			val=sk->nonagle;
-			break;
-		default:
-			return(-ENOPROTOOPT);
+	case TCP_MAXSEG:
+		val = tp->user_mss;
+		break;
+	case TCP_NODELAY:
+		val = (sk->nonagle == 1);
+		break;
+	case TCP_CORK:
+		val = (sk->nonagle == 2);
+		break;
+	default:
+		return -ENOPROTOOPT;
 	};
 
   	if(put_user(len, optlen))

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov