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

📄 tcp.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
		while (seglen > 0) {			int copy, tmp, queue_it;			if (err)				goto do_fault2;			/* Stop on errors. */			if (sk->err)				goto do_sock_err;			/* Make sure that we are established. */			if (sk->shutdown & SEND_SHUTDOWN)				goto do_shutdown;				/* Now we need to check if we have a half			 * built packet we can tack some data onto.			 */			skb = sk->write_queue.prev;			if (tp->send_head &&			    (mss_now - skb->len) > 0) {				copy = skb->len;				if (skb_tailroom(skb) > 0) {					int last_byte_was_odd = (copy % 4);					copy = mss_now - copy;					if(copy > skb_tailroom(skb))						copy = skb_tailroom(skb);					if(copy > seglen)						copy = seglen;					if(last_byte_was_odd) {						if(copy_from_user(skb_put(skb, copy),								  from, copy))							err = -EFAULT;						skb->csum = csum_partial(skb->data,									 skb->len, 0);					} else {						skb->csum =							csum_and_copy_from_user(							from, skb_put(skb, copy),							copy, skb->csum, &err);					}					/*					 * FIXME: the *_user functions should					 *	  return how much data was					 *	  copied before the fault					 *	  occurred and then a partial					 *	  packet with this data should					 *	  be sent.  Unfortunately					 *	  csum_and_copy_from_user doesn't					 *	  return this information.					 *	  ATM it might send partly zeroed					 *	  data in this case.					 */					tp->write_seq += copy;					TCP_SKB_CB(skb)->end_seq += copy;					from += copy;					copied += copy;					seglen -= copy;					if (PSH_NEEDED ||					    after(tp->write_seq, tp->pushed_seq+(tp->max_window>>1))) {						TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;						tp->pushed_seq = tp->write_seq;					}					if (flags&MSG_OOB) {						tp->urg_mode = 1;						tp->snd_up = tp->write_seq;						TCP_SKB_CB(skb)->sacked |= TCPCB_URG;					}					continue;				} else {					TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;					tp->pushed_seq = tp->write_seq;				}			}			copy = min(seglen, mss_now);			/* Determine how large of a buffer to allocate.  */			tmp = MAX_TCP_HEADER + 15 + tp->mss_cache;			if (copy < mss_now && !(flags & MSG_OOB)) {				/* What is happening here is that we want to				 * tack on later members of the users iovec				 * if possible into a single frame.  When we				 * leave this loop our we check to see if				 * we can send queued frames onto the wire.				 */				queue_it = 1;			} else {				queue_it = 0;			}			skb = NULL;			if (tcp_memory_free(sk))				skb = tcp_alloc_skb(sk, tmp, sk->allocation);			if (skb == NULL) {				/* If we didn't get any memory, we need to sleep. */				set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);				set_bit(SOCK_NOSPACE, &sk->socket->flags);				__tcp_push_pending_frames(sk, tp, mss_now, 1);				if (!timeo) {					err = -EAGAIN;					goto do_interrupted;				}				if (signal_pending(current)) {					err = sock_intr_errno(timeo);					goto do_interrupted;				}				timeo = wait_for_tcp_memory(sk, timeo);				/* 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. */			if (PSH_NEEDED ||			    after(tp->write_seq+copy, tp->pushed_seq+(tp->max_window>>1))) {				TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK|TCPCB_FLAG_PSH;				tp->pushed_seq = tp->write_seq + copy;			} else {				TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;			}			TCP_SKB_CB(skb)->sacked = 0;			if (flags & MSG_OOB) {				TCP_SKB_CB(skb)->sacked |= TCPCB_URG;				tp->urg_mode = 1;				tp->snd_up = tp->write_seq + copy;			}			/* 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_TCP_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, mss_now);		}	}	err = copied;out:	__tcp_push_pending_frames(sk, tp, mss_now, tp->nonagle);out_unlock:	TCP_CHECK_TIMER(sk);	release_sock(sk);	return err;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_unlock;do_fault:	__kfree_skb(skb);do_fault2:	if (copied)		err = copied;	else		err = -EFAULT;	goto out;}#undef PSH_NEEDED/* *	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, long timeo,			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 == TCP_URG_READ)		return -EINVAL;	/* Yes this is right ! */	if (sk->state==TCP_CLOSE && !sk->done)		return -ENOTCONN;	if (tp->urg_data & TCP_URG_VALID) {		int err = 0; 		char c = tp->urg_data;		if (!(flags & MSG_PEEK))			tp->urg_data = TCP_URG_READ;		/* Read urgent data. */		msg->msg_flags|=MSG_OOB;		if(len>0) {			if (!(flags & MSG_PEEK))				err = memcpy_toiovec(msg->msg_iov, &c, 1);			len = 1;		} else			msg->msg_flags|=MSG_TRUNC;		return err ? -EFAULT : len;	}	if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN))		return 0;	/* 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 tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	struct sk_buff *skb;	int time_to_ack = 0;	/* 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)			break;		tcp_eat_skb(sk, skb);	}	if (tcp_ack_scheduled(tp)) {		   /* Delayed ACKs frequently hit locked sockets during bulk receive. */		if (tp->ack.blocked		    /* Once-per-two-segments ACK was not sent by tcp_input.c */		    || tp->rcv_nxt - tp->rcv_wup > tp->ack.rcv_mss		    /*		     * If this read emptied read buffer, we send ACK, if		     * connection is not bidirectional, user drained		     * receive buffer and there was a small segment		     * in queue.		     */		    || (copied > 0 &&			(tp->ack.pending&TCP_ACK_PUSHED) &&			!tp->ack.pingpong &&			atomic_read(&sk->rmem_alloc) == 0)) {			time_to_ack = 1;		}	}  	/* We send an ACK if we can now advertise a non-zero window	 * which has been raised "significantly".	 *	 * Even if window raised up to infinity, do not send window open ACK	 * in states, where we will not receive more. It is useless.  	 */	if(copied > 0 && !time_to_ack && !(sk->shutdown&RCV_SHUTDOWN)) {		__u32 rcv_window_now = tcp_receive_window(tp);		/* Optimize, __tcp_select_window() is not cheap. */		if (2*rcv_window_now <= tp->window_clamp) {			__u32 new_window = __tcp_select_window(sk);			/* Send ACK now, if this read freed lots of space			 * in our buffer. Certainly, new_window is new window.			 * We can advertise it now, if it is not less than current one.			 * "Lots" means "at least twice" here.			 */			if(new_window && new_window >= 2*rcv_window_now)				time_to_ack = 1;		}	}	if (time_to_ack)		tcp_send_ack(sk);}/* Now socket state including sk->err is changed only under lock, * hence we may omit checks after joining wait queue. * We check receive queue before schedule() only as optimization; * it is very likely that release_sock() added new data. */static long tcp_data_wait(struct sock *sk, long timeo){	DECLARE_WAITQUEUE(wait, current);	add_wait_queue(sk->sleep, &wait);	__set_current_state(TASK_INTERRUPTIBLE);	set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);	release_sock(sk);	if (skb_queue_empty(&sk->receive_queue))		timeo = schedule_timeout(timeo);	lock_sock(sk);	clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);	remove_wait_queue(sk->sleep, &wait);	__set_current_state(TASK_RUNNING);	return timeo;}static void tcp_prequeue_process(struct sock *sk){	struct sk_buff *skb;	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);	net_statistics[smp_processor_id()*2+1].TCPPrequeued += skb_queue_len(&tp->ucopy.prequeue);	/* RX process wants to run with disabled BHs, though it is not necessary */	local_bh_disable();	while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)		sk->backlog_rcv(sk, skb);	local_bh_enable();	/* Clear memory counter. */	tp->ucopy.memory = 0;}/* *	This routine copies from a sock struct into the user buffer.  * *	Technical note: in 2.3 we work on _locked_ socket, so that *	tricks with *seq access order and skb->users are not required. *	Probably, code can be easily improved even more. */ 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);	int copied = 0;	u32 peek_seq;	u32 *seq;	unsigned long used;	int err;	int target;		/* Read at least this many bytes */	long timeo;	struct task_struct *user_recv = NULL;	lock_sock(sk);	TCP_CHECK_TIMER(sk);	err = -ENOTCONN;	if (sk->state == TCP_LISTEN)		goto out;	timeo = sock_rcvtimeo(sk, nonblock);	/* Urgent data needs to be handled specially. */	if (flags & MSG_OOB)		goto recv_urg;	seq = &tp->copied_seq;	if (flags & MSG_PEEK) {		peek_seq = tp->copied_seq;		seq = &peek_seq;	}	target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);	do {		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 = timeo ? sock_intr_errno(timeo) : -EAGAIN;			break;		}		/* Next get a buffer. */		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);		/* Well, if we have backlog, try to process it now yet. */		if (copied >= target && sk->backlog.tail == NULL)			break;		if (copied) {			if (sk->err ||			    sk->state == TCP_CLOSE ||			    (sk->shutdown & RCV_SHUTDOWN) ||			    !timeo)

⌨️ 快捷键说明

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