patch-2.3.41 linux/net/core/sock.c

Next file: linux/net/ethernet/eth.c
Previous file: linux/net/core/skbuff.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.40/linux/net/core/sock.c linux/net/core/sock.c
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.87 1999/11/23 08:56:59 davem Exp $
+ * Version:	$Id: sock.c,v 1.89 2000/01/18 08:24:13 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -140,6 +140,23 @@
 /* Maximal space eaten by iovec or ancilliary data plus some space */
 int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512);
 
+static int sock_set_timeout(long *timeo_p, char *optval, int optlen)
+{
+	struct timeval tv;
+
+	if (optlen < sizeof(tv))
+		return -EINVAL;
+	if (copy_from_user(&tv, optval, sizeof(tv)))
+		return -EFAULT;
+
+	*timeo_p = MAX_SCHEDULE_TIMEOUT;
+	if (tv.tv_sec == 0 && tv.tv_usec == 0)
+		return 0;
+	if (tv.tv_sec < (MAX_SCHEDULE_TIMEOUT/HZ - 1))
+		*timeo_p = tv.tv_sec*HZ + (tv.tv_usec+(1000000/HZ-1))/(1000000/HZ);
+	return 0;
+}
+
 /*
  *	This is meant for all protocols to use and covers goings on
  *	at the socket level. Everything here is generic.
@@ -214,7 +231,7 @@
 			if (val > sysctl_wmem_max)
 				val = sysctl_wmem_max;
 
-			sk->sndbuf = max(val*2,2048);
+			sk->sndbuf = max(val*2,SOCK_MIN_SNDBUF);
 
 			/*
 			 *	Wake up sending tasks if we
@@ -233,7 +250,7 @@
 				val = sysctl_rmem_max;
 
 			/* FIXME: is this lower bound the right one? */
-			sk->rcvbuf = max(val*2,256);
+			sk->rcvbuf = max(val*2,SOCK_MIN_RCVBUF);
 			break;
 
 		case SO_KEEPALIVE:
@@ -266,16 +283,19 @@
 				ret = -EINVAL;	/* 1003.1g */
 				break;
 			}
-			if (copy_from_user(&ling,optval,sizeof(ling)))
-			{
+			if (copy_from_user(&ling,optval,sizeof(ling))) {
 				ret = -EFAULT;
 				break;
 			}
-			if(ling.l_onoff==0)
+			if(ling.l_onoff==0) {
 				sk->linger=0;
-			else
-			{
-				sk->lingertime=ling.l_linger;
+			} else {
+#if (BITS_PER_LONG == 32)
+				if (ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
+					sk->lingertime=MAX_SCHEDULE_TIMEOUT;
+				else
+#endif
+					sk->lingertime=ling.l_linger*HZ;
 				sk->linger=1;
 			}
 			break;
@@ -287,8 +307,21 @@
 		case SO_PASSCRED:
 			sock->passcred = valbool;
 			break;
-			
-			
+
+		case SO_RCVLOWAT:
+			if (val < 0)
+				val = INT_MAX;
+			sk->rcvlowat = val ? : 1;
+			break;
+
+		case SO_RCVTIMEO:
+			ret = sock_set_timeout(&sk->rcvtimeo, optval, optlen);
+			break;
+
+		case SO_SNDTIMEO:
+			ret = sock_set_timeout(&sk->sndtimeo, optval, optlen);
+			break;
+
 #ifdef CONFIG_NETDEVICES
 		case SO_BINDTODEVICE:
 		{
@@ -446,7 +479,7 @@
 		case SO_LINGER:	
 			lv=sizeof(v.ling);
 			v.ling.l_onoff=sk->linger;
- 			v.ling.l_linger=sk->lingertime;
+ 			v.ling.l_linger=sk->lingertime/HZ;
 			break;
 					
 		case SO_BSDCOMPAT:
@@ -454,13 +487,31 @@
 			break;
 			
 		case SO_RCVTIMEO:
+			lv=sizeof(struct timeval);
+			if (sk->rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
+				v.tm.tv_sec = 0;
+				v.tm.tv_usec = 0;
+			} else {
+				v.tm.tv_sec = sk->rcvtimeo/HZ;
+				v.tm.tv_usec = ((sk->rcvtimeo%HZ)*1000)/HZ;
+			}
+			break;
+
 		case SO_SNDTIMEO:
 			lv=sizeof(struct timeval);
-			v.tm.tv_sec=0;
-			v.tm.tv_usec=0;
+			if (sk->sndtimeo == MAX_SCHEDULE_TIMEOUT) {
+				v.tm.tv_sec = 0;
+				v.tm.tv_usec = 0;
+			} else {
+				v.tm.tv_sec = sk->sndtimeo/HZ;
+				v.tm.tv_usec = ((sk->sndtimeo%HZ)*1000)/HZ;
+			}
 			break;
 
 		case SO_RCVLOWAT:
+			v.val = sk->rcvlowat;
+			break;
+
 		case SO_SNDLOWAT:
 			v.val=1;
 			break; 
@@ -663,7 +714,7 @@
 /* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
    I think, these locks should be removed for datagram sockets.
  */
-static void sock_wait_for_wmem(struct sock * sk)
+static long sock_wait_for_wmem(struct sock * sk, long timeo)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -679,10 +730,11 @@
 			break;
 		if (sk->err)
 			break;
-		schedule();
+		timeo = schedule_timeout(timeo);
 	}
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(sk->sleep, &wait);
+	return timeo;
 }
 
 
@@ -695,6 +747,9 @@
 {
 	int err;
 	struct sk_buff *skb;
+	long timeo;
+
+	timeo = sock_sndtimeo(sk, noblock);
 
 	while (1) {
 		unsigned long try_size = size;
@@ -736,12 +791,12 @@
 
 		sk->socket->flags |= SO_NOSPACE;
 		err = -EAGAIN;
-		if (noblock)
+		if (!timeo)
 			goto failure;
 		err = -ERESTARTSYS;
 		if (signal_pending(current))
 			goto failure;
-		sock_wait_for_wmem(sk);
+		timeo = sock_wait_for_wmem(sk, timeo);
 	}
 
 	return skb;
@@ -771,13 +826,21 @@
 void __release_sock(struct sock *sk)
 {
 	struct sk_buff *skb = sk->backlog.head;
+
 	do {
-		struct sk_buff *next = skb->next;
-		skb->next = NULL;
-		sk->backlog_rcv(sk, skb);
-		skb = next;
-	} while(skb != NULL);
-	sk->backlog.head = sk->backlog.tail = NULL;
+		sk->backlog.head = sk->backlog.tail = NULL;
+		bh_unlock_sock(sk);
+
+		do {
+			struct sk_buff *next = skb->next;
+
+			skb->next = NULL;
+			sk->backlog_rcv(sk, skb);
+			skb = next;
+		} while (skb != NULL);
+
+		bh_lock_sock(sk);
+	} while((skb = sk->backlog.head) != NULL);
 }
 
 /*
@@ -1004,7 +1067,7 @@
 {
 	read_lock(&sk->callback_lock);
 	if(!sk->dead)
-		wake_up_interruptible(sk->sleep);
+		wake_up_interruptible_all(sk->sleep);
 	read_unlock(&sk->callback_lock);
 }
 
@@ -1087,6 +1150,9 @@
 	sk->peercred.pid 	=	0;
 	sk->peercred.uid	=	-1;
 	sk->peercred.gid	=	-1;
+	sk->rcvlowat		=	1;
+	sk->rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
+	sk->sndtimeo		=	MAX_SCHEDULE_TIMEOUT;
 
 	atomic_set(&sk->refcnt, 1);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)