TCP/IP源码(21)——struct inet_socks

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

在前面的博文中,我画出了TCP/IP数据包发送的流程图。现在开始学习TCP部分。今天由sock_aio_write开始。这是第一个进入TCP发送函数write会调用的第一个socket层的函数。
  1. static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
  2.              unsigned long nr_segs, loff_t pos)
  3. {
  4.     struct sock_iocb siocb, *x;

  5.     if (pos != 0)
  6.         return -ESPIPE;
     /* 申请sock iocb */
  1.     x = alloc_sock_iocb(iocb, &siocb);
  2.     if (!x)
  3.         return -ENOMEM;

  4.     return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
  5. }
从函数名字上看,这个函数是一个异步写函数。参数struct kiocb iocb不进行特殊说明了,因为它与TCP/IP协议栈没有直接联系,它存在与所有的I/O操作中。这个函数其实与TCP/IP并不太大联系,更多的是由于VFS。
那么根据前面博文中的流程图http://blog.chinaunix.net/space.php?uid=23629988&do=blog&id=211994,直接跳到tcp_sendmsg,这个真正的TCP对应的4层发送函数。
  1. int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
  2.         size_t size)
  3. {
  4.     struct iovec *iov;
  5.     struct tcp_sock *tp = tcp_sk(sk);
  6.     struct sk_buff *skb;
  7.     int iovlen, flags;
  8.     int mss_now, size_goal;
  9.     int sg, err, copied;
  10.     long timeo;
     
      ...... ......
  1. }
与UDP类似,对应于udp_sock,TCP也有struct tcp_sock。因为TCP的要比UDP复杂的多,所以这个tcp_sock也比udp_sock复杂庞大的多。这个struture非常复杂,超过160多行。不过几乎每一个成员变量都有注释,而我目前暂时也没有能力添加更多的注释,所以这里就不粘贴代码了。

不过我要对其中的struct inet_sock进行一点说明。在struct udp_sock中,struct inet_sock inet为其第一个成员变量。而对应struct tcp_sock,其第一个成员变量是struct inet_connection_sock inet_conn,不过struct inet_connection_sock inet_conn的第一个成员变量依然是struct inet_sock inet。所以无论是udp_sock还是tcp_sock,其内存布局上都保证了struct inet_sock inet为第一个成员变量。
  1. struct inet_sock {
  2.     /* sk and pinet6 has to be the first two members of inet_sock */
  3.     struct sock        sk;
  4. #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  5.     struct ipv6_pinfo    *pinet6;
  6. #endif
  7.     /* Socket demultiplex comparisons on incoming packets. */
  8.     /* 
  9.     通过与下列的值比较,可以demultiplex收到的包。
  10.     通过系统调用connect,bind或setsocktopt可以设置下面的部分值。
  11.     */
  12.     __be32            inet_daddr;
  13.     __be32            inet_rcv_saddr;
  14.     __be16            inet_dport;
  15.     /* inet_num 为主机序的port,即inet_sport为其网络序格式 */
  16.     __u16            inet_num;
  17.     __be32            inet_saddr;
  18.     /* 用户指定的ttl值,如为-1,则使用系统默认值 */
  19.     __s16            uc_ttl;
  20.     __u16            cmsg_flags;
  21.     __be16            inet_sport;
  22.     __u16            inet_id;
/* ip option 信息*/
  1.     struct ip_options    *opt;
  2.     __u8            tos;
  3.     /* 
  4.     最小的ttl,可以通过/proc指定。
  5.     若收到的包的ttl小于该值,则drop掉该包
  6.     */
  7.     __u8            min_ttl;
  8.     /* 多播ttl */
  9.     __u8            mc_ttl;
  10.     /* 
  11.     PMTU value:   
  12. #define IP_PMTUDISC_DONT 0 /* Never send DF frames */
  13. #define IP_PMTUDISC_WANT 1 /* Use per route hints */
  14. #define IP_PMTUDISC_DO 2 /* Always DF */
  15. #define IP_PMTUDISC_PROBE 3       /* Ignore dst pmtu      */
  16.     */
  17.     __u8            pmtudisc;
  18.     /* 下面这些基本上都是socket的option */
  19.     __u8            recverr:1,
  20.                 is_icsk:1, /* 是否是connection socket*/
  21.                 freebind:1, /* 是否enable IP_FREEBIND option*/
  22.                 hdrincl:1, /* 是否enable IP_HDRINCL option*/
  23.                 mc_loop:1,
  24.                 transparent:1,
  25.                 mc_all:1,
  26.                 nodefrag:1;
  27.     /* 多播网卡的索引 */
  28.     int            mc_index;
  29.     /* 用于发送的多播地址 */
  30.     __be32            mc_addr;
  31.     /* 所有加入的多播组 */
  32.     struct ip_mc_socklist    *mc_list;
  33.     /* cork 信息
  34.     主要用于分片时。具体应用请看前面的博文http://blog.chinaunix.net/space.php?uid=23629988&do=blog&id=186822
  35.     */
  36.     struct {
  37.         unsigned int        flags;
  38.         unsigned int        fragsize;
  39.         struct ip_options    *opt;
  40.         struct dst_entry    *dst;
  41.         int            length; /* Total length of all frames */
  42.         __be32            addr;
  43.         struct flowi        fl;
  44.     } cork;
  45. };
从上面可以看出,struct inet_sock为TCP/IP协议栈极为重要的结构,它要位于所有的不同sock类型的顶部。主要用于保存不同socket类型公有的特性和信息。组织结构有些类似于C++的基类——尤其是内存布局上。


上一篇:tcp/ip源码(18)——struct inet_sock中的cork用途


下一篇:搞一搞Main Thread Checker