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

📄 tcp.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 5 页
字号:
}static inline int select_size(struct sock *sk, struct tcp_opt *tp){	int tmp = tp->mss_cache;	if (sk->route_caps&NETIF_F_SG) {		int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);		if (tmp >= pgbreak && tmp <= pgbreak + (MAX_SKB_FRAGS-1)*PAGE_SIZE)			tmp = pgbreak;	}	return tmp;}int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size){	struct iovec *iov;	struct tcp_opt *tp;	struct sk_buff *skb;	int iovlen, flags;	int mss_now;	int err, copied;	long timeo;	tp = &(sk->tp_pinfo.af_tcp);	lock_sock(sk);	TCP_CHECK_TIMER(sk);	flags = msg->msg_flags;	timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT);	/* Wait for a connection to finish. */	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))		if((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0)			goto out_err;	/* This should be in poll */	clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);	mss_now = tcp_current_mss(sk);	/* Ok commence sending. */	iovlen = msg->msg_iovlen;	iov = msg->msg_iov;	copied = 0;	err = -EPIPE;	if (sk->err || (sk->shutdown&SEND_SHUTDOWN))		goto do_error;	while (--iovlen >= 0) {		int seglen=iov->iov_len;		unsigned char * from=iov->iov_base;		iov++;		while (seglen > 0) {			int copy;						skb = sk->write_queue.prev;			if (tp->send_head == NULL ||			    (copy = mss_now - skb->len) <= 0) {new_segment:				/* Allocate new segment. If the interface is SG,				 * allocate skb fitting to single page.				 */				if (!tcp_memory_free(sk))					goto wait_for_sndbuf;				skb = tcp_alloc_pskb(sk, select_size(sk, tp), 0, sk->allocation);				if (skb == NULL)					goto wait_for_memory;				skb_entail(sk, tp, skb);				copy = mss_now;			}			/* Try to append data to the end of skb. */			if (copy > seglen)				copy = seglen;			/* Where to copy to? */			if (skb_tailroom(skb) > 0) {				/* We have some space in skb head. Superb! */				if (copy > skb_tailroom(skb))					copy = skb_tailroom(skb);				if ((err = skb_add_data(skb, from, copy)) != 0)					goto do_fault;			} else {				int merge = 0;				int i = skb_shinfo(skb)->nr_frags;				struct page *page = TCP_PAGE(sk);				int off = TCP_OFF(sk);				if (can_coalesce(skb, i, page, off) && off != PAGE_SIZE) {					/* We can extend the last page fragment. */					merge = 1;				} else if (i == MAX_SKB_FRAGS ||					   (i == 0 && !(sk->route_caps&NETIF_F_SG))) {					/* Need to add new fragment and cannot					 * do this because interface is non-SG,					 * or because all the page slots are busy.					 */					tcp_mark_push(tp, skb);					goto new_segment;				} else if (page) {					/* If page is cached, align					 * offset to L1 cache boundary					 */					off = (off+L1_CACHE_BYTES-1)&~(L1_CACHE_BYTES-1);					if (off == PAGE_SIZE) {						put_page(page);						TCP_PAGE(sk) = page = NULL;					}				}				if (!page) {					/* Allocate new cache page. */					if (!(page=tcp_alloc_page(sk)))						goto wait_for_memory;					off = 0;				}				if (copy > PAGE_SIZE-off)					copy = PAGE_SIZE-off;				/* Time to copy data. We are close to the end! */				err = tcp_copy_to_page(sk, from, skb, page, off, copy);				if (err) {					/* If this page was new, give it to the					 * socket so it does not get leaked.					 */					if (TCP_PAGE(sk) == NULL) {						TCP_PAGE(sk) = page;						TCP_OFF(sk) = 0;					}					goto do_error;				}				/* Update the skb. */				if (merge) {					skb_shinfo(skb)->frags[i-1].size += copy;				} else {					fill_page_desc(skb, i, page, off, copy);					if (TCP_PAGE(sk)) {						get_page(page);					} else if (off + copy < PAGE_SIZE) {						get_page(page);						TCP_PAGE(sk) = page;					}				}				TCP_OFF(sk) = off+copy;			}			if (!copied)				TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;			tp->write_seq += copy;			TCP_SKB_CB(skb)->end_seq += copy;			from += copy;			copied += copy;			seglen -= copy;			if (skb->len != mss_now || (flags&MSG_OOB))				continue;			if (forced_push(tp)) {				tcp_mark_push(tp, skb);				__tcp_push_pending_frames(sk, tp, mss_now, 1);			} else if (skb == tp->send_head)				tcp_push_one(sk, mss_now);			continue;wait_for_sndbuf:			set_bit(SOCK_NOSPACE, &sk->socket->flags);wait_for_memory:			if (copied)				tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1);			if ((err = wait_for_tcp_memory(sk, &timeo)) != 0)				goto do_error;			mss_now = tcp_current_mss(sk);		}	}out:	if (copied)		tcp_push(sk, tp, flags, mss_now, tp->nonagle);	TCP_CHECK_TIMER(sk);	release_sock(sk);	return copied;do_fault:	if (skb->len == 0) {		if (tp->send_head == skb)			tp->send_head = NULL;		__skb_unlink(skb, skb->list);		tcp_free_skb(sk, skb);	}do_error:	if (copied)		goto out;out_err:	err = tcp_error(sk, flags, err);	TCP_CHECK_TIMER(sk);	release_sock(sk);	return err;}/* *	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_TRUNC))				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);	int time_to_ack = 0;#if TCP_DEBUG	struct sk_buff *skb = skb_peek(&sk->receive_queue);	BUG_TRAP(skb==NULL || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq));#endif	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;			BUG_TRAP(flags&MSG_PEEK);			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 ||			    (flags & MSG_PEEK))				break;		} else {			if (sk->done)				break;			if (sk->err) {				copied = sock_error(sk);				break;			}			if (sk->shutdown & RCV_SHUTDOWN)

⌨️ 快捷键说明

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