在tcp/ip中有一些比较重要的数据结构,主要是一些内核态的数据结构和用户态的数据结构.其中用户态系统调用的入口为socketcall函数:
- net/socket.c
- SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
- {
- .......
- switch (call) {
- case SYS_SOCKET:
- err = sys_socket(a0, a1, a[2]);
- break;
- case SYS_BIND:
- err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
- break;
- case SYS_CONNECT:
- err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
- break;
- case SYS_LISTEN:
- err = sys_listen(a0, a1);
- break;
- case SYS_ACCEPT:
- err = sys_accept4(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2], 0);
- break;
- case SYS_GETSOCKNAME:
- err = sys_getsockname(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2]);
- break;
- case SYS_GETPEERNAME:
- err =
- sys_getpeername(a0, (struct sockaddr __user *)a1,
- (int __user *)a[2]);
- break;
- ........
- default:
- err = -EINVAL;
- break;
- }
- return err;
- }
当创建一个socket时,则调用函数sys_socket,该函数就创建了一个与用户态交流的socket数据结构,该函数部分源码如下:
点击(此处)折叠或打开
- include/linux/net.h
-
- struct socket {
- socket_state state; //socket 当前状态(SS_FREE,SS_UNCONNECTED,SS_CONNECTING,SS_CONNECTED,SS_DISCONNECTING)
- ....
- struct faysnc_struct *fasync_list;
- wait_queue_head_t wait;
-
- struct file *file; //与文件系统VFS联系起来
- struct sock *sk; //内核态维护的数据结构
- const struct proto_ops *ops;//所有的相关操作
- }
接着就是sys_socket函数:
点击(此处)折叠或打开
- net/socket.c
-
- SYSCALL_DEFINE3(socket,int,family,int,type,int,protocol)
- {
- struct socket *sock;
- ........
- retval = sock_create(family,type,protocol,&sock);
- .......
- retval = sock_map_fd(sock,flags & (O_CLOEXEC | O_NONBLOCK));
- .......
- }
而函数sock_create中就是与对应的协议相关联起来并建立内核态(sock)和用户态(socket)的数据结构,sock_create中主要有两件事情:
- net/socket.c
- sock_create
- ----> __sock_create
-
- static int __sock_create(struct net *net,int family,int type,int protocol,struct socket **res,int kern)
- {
- struct socket *sock;
- const struct net_proto_family *pf;
- .......
- sock = sock_alloc(); //这里分配两项:inode 和 socket
- ......
- pf = rcu_deference(net_families[family]); //调用具体的协议创建与之相对应的操作
- ......
- pf->create(net,sock,protocol);
- .....
- }
假设在socket系统调用中domain(family)为AF_INET,type为SOCK_STREAM,则调用ipv4中的创建函数:
- net/af_inet.c
-
- static struct net_proto_family inet_family_ops = {
- .family = PF_INET,
- .create = inet_create,
- .owner = THIS_MODULE,
- };
inet_create 就开始初始化与具体协议相关的数据项,这里创建内核态数据结构(struct sock)及初始化部分socket中的字段:
- net/af_inet.c
-
- static int inet_create(struct net *net,struct socket *sock,int protocol)
- {
- struct sock *sk;
- struct inet_protosw *answer;
- struct inet_sock *inet;
- struct proto *answer_prot;
- .......
- sock->type = SS_UNCONNECTED;
- ....
- //从对应的协议中找出支持的协议(默认为0,因为一般只有与type对应的一种协议)
- list_for_each_entry_rcu(answer,&inetsw[sock->type],list) {
- ........
- }
-
- sock->ops = answer->ops;
- answer_prot = answer->prot;
- ......
- //初始化内核数据结构 struct sock
- sk = sk_alloc(net,PF_INET,GFP_KERNEL,answer_prot);
- .....
- sock_init_data(sock,sk);
-
- sk->sk_destruct = inet_sock_destruct;
- sk->sk_protocol = protocol;
- sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
-
- .......
- }
这里最关键的部分就是 sock->ops = answer->ops 将对应协议操作具体化.该链表数据实际的数据定义如下:
- net/af_inet.c
-
- static struct inet_protosw inetsw_array[] =
- {
- {
- .type = SOCK_STREAM,
- .protocol = IPPROTO_TCP,
- .prot = &tcp_prot,
- .ops = &inet_stream_ops,
- .capcability = -1,
- .no_check = 0,
- .flags = INEET_PROTOSW_PERMANET | INET_PROTOSW_ICSK,
- },
-
- ...........
- }
而具体的操作函数inet_stream_ops 定义如下:
- net/af_inet.c
-
- const struct proto_ops inet_stream_ops = {
- .family = PF_INET,
- .owner = THIS_MODULE,
- .bind = inet_bind,
- .release = inet_release,
- .........
- }
当创建完用户态与内核态的数据结构后,剩下部分就是安装在文件系统VFS中,也就是函数sock_map_fd了.
点击(此处)折叠或打开
- net/socket.c
-
- int sock_map_fd(struct socket *sock,int flags)
- {
- struct file *newfile;
- int fd = sock_alloc_fd(&newfile,flags);
-
- if(likely(fd >= 0)) {
- //将socket 与 file 相关联
- int err = sock_attach_fd(sock,newfile,flags);
-
- .......
- //放到符号表中
- fd_install(fd,newfile);
-
- .......
- }
-
- return fd;
- }
sock_attach_fd函数原型如下:
- net/socket.c
-
- static int sock_attach_fd(struct socket *sock,struct file *file,int flags)
- {
- struct dentry *dentry;
-
- ......
-
- dentry->d_op = &sockfs_dentry_operations;
-
- .......
- //关键部分在这里,将文件系统与socket连接起来
- sock->file =file;
- ...
- SOCK_INDOE(sock)->i_fop = &socket_file_ops;
- file->private_data = sock;
- .......
-
- return 0;
- }
而socket_file_ops的具体定义如下:
- net/socket.c
-
- static const struct file_operations socket_file_ops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .aio_read = sock_aio_read,
- .aio_writ = sock_aio_write,
- .poll = sock_poll,
- .mmap = sock_mmap,
- ........
- }
这样整个初始化就完成了.