tcp/ip 分析(1)

2438阅读 0评论2012-08-07 datao0907
分类:LINUX

tcp/ip 协议分析(1)

在tcp/ip中有一些比较重要的数据结构,主要是一些内核态的数据结构和用户态的数据结构.其中用户态系统调用的入口为socketcall函数:


  1. net/socket.c
  2. SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
  3. {
  4. .......
  5. switch (call) {
  6. case SYS_SOCKET:
  7. err = sys_socket(a0, a1, a[2]);
  8. break;
  9. case SYS_BIND:
  10. err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
  11. break;
  12. case SYS_CONNECT:
  13. err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
  14. break;
  15. case SYS_LISTEN:
  16. err = sys_listen(a0, a1);
  17. break;
  18. case SYS_ACCEPT:
  19. err = sys_accept4(a0, (struct sockaddr __user *)a1,
  20. (int __user *)a[2], 0);
  21. break;
  22. case SYS_GETSOCKNAME:
  23. err = sys_getsockname(a0, (struct sockaddr __user *)a1,
  24. (int __user *)a[2]);
  25. break;
  26. case SYS_GETPEERNAME:
  27. err =
  28. sys_getpeername(a0, (struct sockaddr __user *)a1,
  29. (int __user *)a[2]);
  30. break;
  31. ........
  32. default:
  33. err = -EINVAL;
  34. break;
  35. }
  36. return err;
  37. }

当创建一个socket时,则调用函数sys_socket,该函数就创建了一个与用户态交流的socket数据结构,该函数部分源码如下:


点击(此处)折叠或打开

  1. include/linux/net.h
  2.    
  3.     struct socket {
  4.        socket_state state; //socket 当前状态(SS_FREE,SS_UNCONNECTED,SS_CONNECTING,SS_CONNECTED,SS_DISCONNECTING)
  5.        ....
  6.        struct faysnc_struct *fasync_list;
  7.        wait_queue_head_t wait;
  8.        
  9.        struct file *file; //与文件系统VFS联系起来
  10.        struct sock *sk; //内核态维护的数据结构
  11.        const struct proto_ops *ops;//所有的相关操作
  12.    }

接着就是sys_socket函数:


点击(此处)折叠或打开

  1. net/socket.c
  2.     
  3.     SYSCALL_DEFINE3(socket,int,family,int,type,int,protocol)
  4.     {
  5.         struct socket *sock;
  6.         ........
  7.         retval = sock_create(family,type,protocol,&sock);
  8.         .......
  9.         retval = sock_map_fd(sock,flags & (O_CLOEXEC | O_NONBLOCK));
  10.         .......
  11.     }

而函数sock_create中就是与对应的协议相关联起来并建立内核态(sock)和用户态(socket)的数据结构,sock_create中主要有两件事情:


  1. net/socket.c

  2.     sock_create
  3.               ----> __sock_create
  4.               
  5.     static int __sock_create(struct net *net,int family,int type,int protocol,struct socket **res,int kern)
  6.     {
  7.            struct socket *sock;
  8.         const struct net_proto_family *pf;
  9.         .......
  10.         sock = sock_alloc(); //这里分配两项:inode 和 socket
  11.         ......
  12.         pf = rcu_deference(net_families[family]); //调用具体的协议创建与之相对应的操作
  13.         ......
  14.         pf->create(net,sock,protocol);
  15.         .....
  16.     }

假设在socket系统调用中domain(family)为AF_INET,type为SOCK_STREAM,则调用ipv4中的创建函数:


  1. net/af_inet.c
  2.      
  3.      static struct net_proto_family inet_family_ops = {
  4.          .family = PF_INET,
  5.         .create = inet_create,
  6.         .owner = THIS_MODULE,
  7.      };

inet_create 就开始初始化与具体协议相关的数据项,这里创建内核态数据结构(struct sock)及初始化部分socket中的字段:


  1. net/af_inet.c
  2.      
  3.      static int inet_create(struct net *net,struct socket *sock,int protocol)
  4.      {
  5.          struct sock *sk;
  6.         struct inet_protosw *answer;
  7.         struct inet_sock *inet;
  8.         struct proto *answer_prot;
  9.         .......
  10.         sock->type = SS_UNCONNECTED;
  11.         ....
  12.         //从对应的协议中找出支持的协议(默认为0,因为一般只有与type对应的一种协议)
  13.         list_for_each_entry_rcu(answer,&inetsw[sock->type],list) {
  14.             ........
  15.         }
  16.         
  17.         sock->ops = answer->ops;
  18.         answer_prot = answer->prot;
  19.         ......
  20.         //初始化内核数据结构 struct sock
  21.         sk = sk_alloc(net,PF_INET,GFP_KERNEL,answer_prot);
  22.         .....
  23.         sock_init_data(sock,sk);
  24.         
  25.         sk->sk_destruct = inet_sock_destruct;
  26.         sk->sk_protocol = protocol;
  27.         sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
  28.         
  29.         .......
  30.      }

这里最关键的部分就是 sock->ops = answer->ops 将对应协议操作具体化.该链表数据实际的数据定义如下:


  1. net/af_inet.c
  2.      
  3.      static struct inet_protosw inetsw_array[] =
  4.      {
  5.         {
  6.            .type = SOCK_STREAM,
  7.            .protocol = IPPROTO_TCP,
  8.            .prot = &tcp_prot,
  9.            .ops = &inet_stream_ops,
  10.            .capcability = -1,
  11.            .no_check = 0,
  12.            .flags = INEET_PROTOSW_PERMANET | INET_PROTOSW_ICSK,
  13.         },
  14.         
  15.         ...........

  16.      }

而具体的操作函数inet_stream_ops 定义如下:


  1. net/af_inet.c
  2.     
  3.     const struct proto_ops inet_stream_ops = {
  4.         .family = PF_INET,
  5.         .owner = THIS_MODULE,
  6.         .bind = inet_bind,
  7.         .release = inet_release,
  8.         .........
  9.     }

当创建完用户态与内核态的数据结构后,剩下部分就是安装在文件系统VFS中,也就是函数sock_map_fd了.


点击(此处)折叠或打开

  1. net/socket.c
  2.     
  3.     int sock_map_fd(struct socket *sock,int flags)
  4.     {
  5.         struct file *newfile;
  6.         int fd = sock_alloc_fd(&newfile,flags);
  7.         
  8.         if(likely(fd >= 0)) {
  9.               //将socket 与 file 相关联
  10.             int err = sock_attach_fd(sock,newfile,flags);
  11.             
  12.             .......
  13.             //放到符号表中
  14.             fd_install(fd,newfile);
  15.             
  16.             .......
  17.         }
  18.         
  19.         return fd;
  20.     }

sock_attach_fd函数原型如下:

  1. net/socket.c
  2.     
  3.     static int sock_attach_fd(struct socket *sock,struct file *file,int flags)
  4.     {
  5.         struct dentry *dentry;
  6.         
  7.         ......
  8.         
  9.         dentry->d_op = &sockfs_dentry_operations;
  10.         
  11.         .......
  12.         //关键部分在这里,将文件系统与socket连接起来
  13.         sock->file =file;
  14.         ...
  15.         SOCK_INDOE(sock)->i_fop = &socket_file_ops;
  16.         file->private_data = sock;
  17.         .......
  18.         
  19.         return 0;
  20.     }

而socket_file_ops的具体定义如下:


  1. net/socket.c
  2.     
  3.     static const struct file_operations socket_file_ops = {
  4.         .owner = THIS_MODULE,
  5.         .llseek = no_llseek,
  6.         .aio_read = sock_aio_read,
  7.         .aio_writ = sock_aio_write,
  8.         .poll = sock_poll,
  9.         .mmap = sock_mmap,
  10.         ........
  11.     }

这样整个初始化就完成了.

上一篇:skiplist 跳跃表
下一篇:sprintf 的小问题