⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				}				if (signal_pending(current)) {					err = -ERESTARTSYS;					goto do_interrupted;				}				tcp_push_pending_frames(sk, tp);				wait_for_tcp_memory(sk);				/* If SACK's were formed or PMTU events happened,				 * we must find out about it.				 */				mss_now = tcp_current_mss(sk);				continue;			}			seglen -= copy;			/* Prepare control bits for TCP header creation engine. */			TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK |						  ((PSH_NEEDED || psh) ?						   TCPCB_FLAG_PSH : 0));			TCP_SKB_CB(skb)->sacked = 0;			if (flags & MSG_OOB) {				TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_URG;				TCP_SKB_CB(skb)->urg_ptr = copy;			} else				TCP_SKB_CB(skb)->urg_ptr = 0;			/* TCP data bytes are SKB_PUT() on top, later			 * TCP+IP+DEV headers are SKB_PUSH()'d beneath.			 * Reserve header space and checksum the data.			 */			skb_reserve(skb, MAX_HEADER + sk->prot->max_header);			skb->csum = csum_and_copy_from_user(from,					skb_put(skb, copy), copy, 0, &err);			if (err)				goto do_fault;			from += copy;			copied += copy;			TCP_SKB_CB(skb)->seq = tp->write_seq;			TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + copy;			/* This advances tp->write_seq for us. */			tcp_send_skb(sk, skb, queue_it);		}	}	sk->err = 0;	err = copied;	goto out;do_sock_err:	if(copied)		err = copied;	else		err = sock_error(sk);	goto out;do_shutdown:	if(copied)		err = copied;	else {		if (!(flags&MSG_NOSIGNAL))			send_sig(SIGPIPE, current, 0);		err = -EPIPE;	}	goto out;do_interrupted:	if(copied)		err = copied;	goto out;do_fault:	kfree_skb(skb);do_fault2:	err = -EFAULT;out:	tcp_push_pending_frames(sk, tp);	release_sock(sk);	return err;}#undef PSH_NEEDED/* *	Send an ack if one is backlogged at this point. Ought to merge *	this with tcp_send_ack(). *      This is called for delayed acks also. */void tcp_read_wakeup(struct sock *sk){	/* If we're closed, don't send an ack, or we'll get a RST	 * from the closed destination.	 */	if (sk->state != TCP_CLOSE)		tcp_send_ack(sk);}/* *	Handle reading urgent data. BSD has very simple semantics for *	this, no blocking and very strange errors 8) */static int tcp_recv_urg(struct sock * sk, int nonblock,			struct msghdr *msg, int len, int flags,			int *addr_len){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	/* No URG data to read. */	if (sk->urginline || !tp->urg_data || tp->urg_data == URG_READ)		return -EINVAL;	/* Yes this is right ! */	if (sk->err)		return sock_error(sk);	if (sk->done)		return -ENOTCONN;	if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) {		sk->done = 1;		return 0;	}	lock_sock(sk);	if (tp->urg_data & URG_VALID) {		int err = 0;		char c = tp->urg_data;		if (!(flags & MSG_PEEK))			tp->urg_data = URG_READ;		if(msg->msg_name)			tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)						       msg->msg_name);		if(addr_len)			*addr_len = tp->af_specific->sockaddr_len;		/* Read urgent data. */		msg->msg_flags|=MSG_OOB;		release_sock(sk);		if(len>0)		{			err = memcpy_toiovec(msg->msg_iov, &c, 1);			/* N.B. already set above ... */			msg->msg_flags|=MSG_OOB;		}		else			msg->msg_flags|=MSG_TRUNC;		/* N.B. Is this right?? If len == 0 we didn't read any data */		return err ? -EFAULT : 1;	}	release_sock(sk);	/* Fixed the recv(..., MSG_OOB) behaviour.  BSD docs and	 * the available implementations agree in this case:	 * this call should never block, independent of the	 * blocking state of the socket.	 * Mike <pall@rz.uni-karlsruhe.de>	 */	return -EAGAIN;}/* *	Release a skb if it is no longer needed. This routine *	must be called with interrupts disabled or with the *	socket locked so that the sk_buff queue operation is ok. */static inline void tcp_eat_skb(struct sock *sk, struct sk_buff * skb){	__skb_unlink(skb, &sk->receive_queue);	kfree_skb(skb);}/* Clean up the receive buffer for full frames taken by the user, * then send an ACK if necessary.  COPIED is the number of bytes * tcp_recvmsg has given to the user so far, it speeds up the * calculation of whether or not we must ACK for the sake of * a window update. */static void cleanup_rbuf(struct sock *sk, int copied){	struct sk_buff *skb;	/* NOTE! The socket must be locked, so that we don't get	 * a messed-up receive queue.	 */	while ((skb=skb_peek(&sk->receive_queue)) != NULL) {		if (!skb->used || atomic_read(&skb->users) > 1)			break;		tcp_eat_skb(sk, skb);	}  	/* We send an ACK if we can now advertise a non-zero window	 * which has been raised "significantly".  	 */	if(copied > 0) {		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);		__u32 rcv_window_now = tcp_receive_window(tp);		__u32 new_window = __tcp_select_window(sk);		/* We won't be raising the window any further than		 * the window-clamp allows.  Our window selection		 * also keeps things a nice multiple of MSS.  These		 * checks are necessary to prevent spurious ACKs		 * which don't advertize a larger window.		 */		if((new_window && (new_window >= rcv_window_now * 2)) &&		   ((rcv_window_now + tp->mss_cache) <= tp->window_clamp))			tcp_read_wakeup(sk);	}}/* *	This routine copies from a sock struct into the user buffer. */int tcp_recvmsg(struct sock *sk, struct msghdr *msg,		int len, int nonblock, int flags, int *addr_len){	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	struct wait_queue wait = { current, NULL };	int copied = 0;	u32 peek_seq;	volatile u32 *seq;	/* So gcc doesn't overoptimise */	unsigned long used;	int err = 0;	int target = 1;		/* Read at least this many bytes */	if (sk->err)		return sock_error(sk);	if (sk->state == TCP_LISTEN)		return -ENOTCONN;	/* Urgent data needs to be handled specially. */	if (flags & MSG_OOB)		return tcp_recv_urg(sk, nonblock, msg, len, flags, addr_len);	/*	Copying sequence to update. This is volatile to handle	 *	the multi-reader case neatly (memcpy_to/fromfs might be	 *	inline and thus not flush cached variables otherwise).	 */	peek_seq = tp->copied_seq;	seq = &tp->copied_seq;	if (flags & MSG_PEEK)		seq = &peek_seq;	/* Handle the POSIX bogosity MSG_WAITALL. */	if (flags & MSG_WAITALL)		target=len;	add_wait_queue(sk->sleep, &wait);	lock_sock(sk);	/*	 *	BUG BUG BUG	 *	This violates 1003.1g compliance. We must wait for	 *	data to exist even if we read none!	 */	while (len > 0) {		struct sk_buff * skb;		u32 offset;		/* Are we at urgent data? Stop if we have read anything. */		if (copied && tp->urg_data && tp->urg_seq == *seq)			break;		/* We need to check signals first, to get correct SIGURG		 * handling. FIXME: Need to check this doesnt impact 1003.1g		 * and move it down to the bottom of the loop		 */		if (signal_pending(current)) {			if (copied)				break;			copied = -ERESTARTSYS;			if (nonblock)				copied = -EAGAIN;			break;		}		/* Next get a buffer. */		current->state = TASK_INTERRUPTIBLE;		skb = skb_peek(&sk->receive_queue);		do {			if (!skb)				break;			/* Now that we have two receive queues this			 * shouldn't happen.			 */			if (before(*seq, TCP_SKB_CB(skb)->seq)) {				printk(KERN_INFO "recvmsg bug: copied %X seq %X\n",				       *seq, TCP_SKB_CB(skb)->seq);				break;			}			offset = *seq - TCP_SKB_CB(skb)->seq;			if (skb->h.th->syn)				offset--;			if (offset < skb->len)				goto found_ok_skb;			if (skb->h.th->fin)				goto found_fin_ok;			if (!(flags & MSG_PEEK))				skb->used = 1;			skb = skb->next;		} while (skb != (struct sk_buff *)&sk->receive_queue);		if (copied >= target)			break;		/*		   These three lines and clause if (sk->state == TCP_CLOSE)		   are unlikely to be correct, if target > 1.		   I DO NOT FIX IT, because I have no idea, what		   POSIX prescribes to make here. Probably, it really		   wants to lose data 8), if not all target is received.		                                                 --ANK		 */		if (sk->err && !(flags&MSG_PEEK)) {			copied = sock_error(sk);			break;		}		if (sk->shutdown & RCV_SHUTDOWN) {			sk->done = 1;			break;		}		if (sk->state == TCP_CLOSE) {			if (!sk->done) {				sk->done = 1;				break;			}			copied = -ENOTCONN;			break;		}		if (nonblock) {			copied = -EAGAIN;			break;		}		cleanup_rbuf(sk, copied);		release_sock(sk);		sk->socket->flags |= SO_WAITDATA;		schedule();		sk->socket->flags &= ~SO_WAITDATA;		lock_sock(sk);		continue;	found_ok_skb:		/*	Lock the buffer. We can be fairly relaxed as		 *	an interrupt will never steal a buffer we are		 *	using unless I've missed something serious in		 *	tcp_data.		 */		atomic_inc(&skb->users);		/* Ok so how much can we use? */		used = skb->len - offset;		if (len < used)			used = len;		/* Do we have urgent data here? */		if (tp->urg_data) {			u32 urg_offset = tp->urg_seq - *seq;			if (urg_offset < used) {				if (!urg_offset) {					if (!sk->urginline) {						++*seq;						offset++;						used--;					}				} else					used = urg_offset;			}		}		/*	Copy it - We _MUST_ update *seq first so that we		 *	don't ever double read when we have dual readers		 */		*seq += used;		/*	This memcpy_toiovec can sleep. If it sleeps and we		 *	do a second read it relies on the skb->users to avoid		 *	a crash when cleanup_rbuf() gets called.		 */		err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);		if (err) {			/* Exception. Bailout! */			atomic_dec(&skb->users);			copied = -EFAULT;			break;		}		copied += used;		len -= used;		/*	We now will not sleep again until we are finished		 *	with skb. Sorry if you are doing the SMP port		 *	but you'll just have to fix it neatly ;)		 */		atomic_dec(&skb->users);		if (after(tp->copied_seq,tp->urg_seq))			tp->urg_data = 0;		if (used + offset < skb->len)			continue;		/*	Process the FIN. We may also need to handle PSH		 *	here and make it break out of MSG_WAITALL.		 */		if (skb->h.th->fin)			goto found_fin_ok;		if (flags & MSG_PEEK)			continue;		skb->used = 1;		if (atomic_read(&skb->users) == 1)			tcp_eat_skb(sk, skb);		continue;	found_fin_ok:		++*seq;		if (flags & MSG_PEEK)			break;		/* All is done. */		skb->used = 1;		sk->shutdown |= RCV_SHUTDOWN;		break;	}	if(copied >= 0 && msg->msg_name) {		tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)					       msg->msg_name);		if(addr_len)			*addr_len = tp->af_specific->sockaddr_len;	}	remove_wait_queue(sk->sleep, &wait);	current->state = TASK_RUNNING;	/* Clean up data we have read: This will do ACK frames. */	cleanup_rbuf(sk, copied);	release_sock(sk);	return copied;}/* * Check whether to renew the timer. */static inline void tcp_check_fin_timer(struct sock *sk){	if (sk->state == TCP_FIN_WAIT2 && !sk->timer.prev)		tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);}/* *	State processing on a close. This implements the state shift for *	sending our FIN frame. Note that we only send a FIN for some *	states. A shutdown() may have already sent the FIN, or we may be *	closed. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -