📄 tcp.c
字号:
}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 + -