TCP/IP源码(22)——tcp_sendmsg(1)

本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以*拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
    


今天开始学习tcp_sendmsg
  1. int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  2.         size_t size)
  3. {
  4.     struct iovec *iov;
  5.     /*
  6.     从通用的struct sock *sk得到struct tcp_sock *tp
  7.     其实只是一个强制类型转换,因为strcut sock为所有其它socket类型的第一个成员,所有可以直接对指针进行     强制类型转换
  8.     */
  9.     struct tcp_sock *tp = tcp_sk(sk);
  10.     struct sk_buff *skb;
  11.     int iovlen, flags;
  12.     int mss_now, size_goal;
  13.     int sg, err, copied;
  14.     long timeo;

  15.     lock_sock(sk);
  16.     TCP_CHECK_TIMER(sk);

  17.     flags = msg->msg_flags;
  18.     /* 
  19.        设置发送等待时间,如果设置了DONTWAIT,则timeo为0. 
  20.        如果没有该标志,则timeo就为sock->sk_sndtimeo
  21.        */
  22.     timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);

  23.     /* Wait for a connection to finish. */
  24.     /* 等到直到连接完成 */
  25.     if ((1 sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
  26.         if ((err = sk_stream_wait_connect(sk, &timeo)) != 0)
  27.             goto out_err;

  28.     /* This should be in poll */
  29.     clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
     /* 计算当前的MSS, size_goal为可发送数据的大小 */
  1.     mss_now = tcp_send_mss(sk, &size_goal, flags);

  2.     /* Ok commence sending. */
  3.     iovlen = msg->msg_iovlen;
  4.     iov = msg->msg_iov;
  5.     copied = 0;

  6.     err = -EPIPE;
  7.     if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
  8.         goto out_err;

  9.     sg = sk->sk_route_caps & NETIF_F_SG;
     /* 开始发送数据 */
  1.     while (--iovlen >= 0) {
  2.         size_t seglen = iov->iov_len;
  3.         unsigned char __user *from = iov->iov_base;

  4.         iov++;

  5.         while (seglen > 0) {
  6.             int copy = 0;
  7.             int max = size_goal;

  8.             skb = tcp_write_queue_tail(sk);
  9.             /* 计算需要复制的字节数为copy */
  10.             if (tcp_send_head(sk)) {
  11.                 if (skb->ip_summed == CHECKSUM_NONE)
  12.                     max = mss_now;
  13.                 copy = max - skb->len;
  14.             }

  15.             if (copy = 0) {
  16.                 /* 已复制完以前的数据了 */
  17. new_segment:
  18.                 /* Allocate new segment. If the interface is SG,
  19.                  * allocate skb fitting to single page.
  20.                  */
                    /* 检验是否还有空闲send buffer,若没有则跳到wait_for_sndbuf */
  21.                 if (!sk_stream_memory_free(sk))
  22.                     goto wait_for_sndbuf;
                 /* 申请新的skb buffer */
  1.                 skb = sk_stream_alloc_skb(sk,
  2.                              select_size(sk, sg),
  3.                              sk->sk_allocation);
  4.                 /* 若分配失败,则跳转到wait_for_memory */
  5.                 if (!skb)
  6.                     goto wait_for_memory;

  7.                 /*
  8.                  * Check whether we can use HW checksum.
  9.                  */
  10.                 if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
  11.                     skb->ip_summed = CHECKSUM_PARTIAL;
                 /* 将新分配的skb添加到sk上 */
  1.                 skb_entail(sk, skb);
  2.                 copy = size_goal;
  3.                 max = size_goal;
  4.             }
             /* 下面开始复制数据,未完待续 */

今天学习的代码不多,一方面是今天的空闲时间不多,家里有不少事情,另一方面,tcp的确实比较复杂。




上一篇:JQuery Tables 的应用(一)


下一篇:TCP/IP源码(59)——TCP中的三个接收队列