分析socket.c 文件

分析socket.c文件

下图为linux网络栈实现与ISO/OSI网络栈七层分层之间的对应关系,BSD socket层对应函数集定义在socket.c文件中,其中函数将作为对socket、bind、accept等系统调用的直接下层响应函数。所有的网络调用函数都具有共同的入口函数sys_socket,由该入口函数调用具体的处理函数。Socket.c文件中函数的实现绝大多数都是简单的调用下层函数,而这些下层函数就是af_inet.c文件中定义的函数。

分析socket.c 文件

内核对一个系统调用的响应是层层下放的,而传输层才会真正进行实质的上的处理,在BSD层和INET层并不进行实际处理,而是仅仅进行某些检查后,调用下一层函数;BSD层调用INET层,INET层调用传输层。
BSD层调用INET层函数通过socket结构中的ops字段完成。ops字段是一个proto_ops结构类型,该结构主要由函数指针组成,socket_ops_bind(inet_bind)或者socket_ops_accept(inet_accept).
INET层对传输层函数的调用也是通过函数指针的形式完成,只不过在此起桥梁作用的是sock结构。sock结构中的prot字段是一个proto结构类型。

下面分析socket.c文件:

可以将其作为BSD socket层对应的函数来看待。系统调用通过INT $ox80进入内核执行函数,该函数根据AX寄存器中的系统调用号进一步调用内核网络栈相应的实现函数。
file_operations定义了普通文件操作函数集,系统中每个文件对应一个file结构,file结构中有一个file_operations变量,系统首先根据文件描述符索引到对应的file结构,然后调用其成员变量file_operations中对应函数完成请求。
分析socket.c 文件

socket_file_ops变量中声明的函数即是网络协议对应的普通文件操作函数集合,从而使得read、write、ioctl等这些常见普通文件操作函数也可以被使用在网络接口的处理上。这些普通文件接口中没有定义open函数,这是因为socket函数完成了类似功能。

move_addr_to_kernel和move_addr_to_user实现用户空间和内核空间之间的复制。

下面分析sock_alloc函数:
首先分析一下sock_alloc()函数的调用路径:sock_alloc()----new_inode_pseudo()-----alloc_inode()—sb->s_op->alloc_inode。
根据new_inode_pseudo的入参函数sock_mnt->mnt_sb,
分析socket.c 文件

在sock_init()函数中,继续分析kern_mount()的路径:
Kern_mount()----kern_mount_data()----vfs_kern_mount()—mount_fs()—type->mount()-----sockfs_mount()----mount_pseudo().s_op相当于ops,也就是sockfs_ops,所以sock_alloc()最终调用的就是sock_alloc_inode.

在socket_alloc这个结构体中,

分析socket.c 文件

Sock_alloc()所做的事:分配一个socket_alloc结构体,将sockfs相关属性填充在socket_alloc结构体的vfs_inode变量中,最终返回socket_alloc结构体中的socket变量。

分析socket.c 文件

继续分析sock_release函数:实现socket关闭及释放。
在sock->ops->release函数调用中,sock->ops字段是一个proto_ops结构,这个结构是一个操作函数集合定义,即一个接口函数集,只完成将请求送往下层函数。
在INET域中,sock->ops字段被赋值inet_proto_ops变量,即inet_release.也只是完成调用工作。
分析socket.c 文件

释放是指当前进程对应的,而不是套接字对应的,因为一个套接字可能同时被多个进程所使用的,通过fork系统调用创建一个子进程时,子进程将继承当前进程打开的所有文件,对于网络套接字,虽然他们属于不同的进程空间,但在底层使用的同一个inode结构。所以底层通过维护一个使用计数来表示是否被使用,只有当使用计数变为0,才能进行结构的真正释放。iput函数即进行inode结构的计数减1操作,同时将进程对应的事件通知通道关闭。
fasync_list是一个fasync_struct结构,这个结构用于异步唤醒。

分析socket.c 文件

sock_socket:首先根据family输入参数决定域操作函数集用于socket结构中ops字段的赋值,之后分配inode结构和socket结构,并对socket结构中ops字段赋值。再根据sock_ops_create分配下层sock结构,最后调用get_fd分配一个文件描述符并返回。

sock_get_info:系统当前使用的套接字总数目。

小结:没有重复之前看的sock_accept/sock_bind等,绝大多数函数没有进行具体的所请求功能的实现,而是将请求传递给了下一层函数,即af_inet.c文件中定义的函数。主要是对一些标志位进行检查后调用下层函数进行处理。