一、Linux 4.9内核bind系统调用代码注释
int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{struct socket *sock; // 定义socket对象的指针struct sockaddr_storage address; // 用于存储从用户空间复制过来的地址int err, fput_needed; // 错误码和文件指针释放标志// 通过文件描述符获取socket对象,并检查是否需要释放文件指针sock = sockfd_lookup_light(fd, &err, &fput_needed);if (sock) { // 如果获取socket对象成功// 将用户空间的socket地址复制到内核空间err = move_addr_to_kernel(umyaddr, addrlen, &address);if (err >= 0) { // 如果地址复制成功// 进行安全检查,判断是否允许绑定操作err = security_socket_bind(sock, (struct sockaddr *)&address, addrlen);if (!err) // 安全检查通过// 调用协议层的bind函数完成实际的绑定操作err = sock->ops->bind(sock, (struct sockaddr *)&address, addrlen);}// 根据fput_needed标志决定是否释放文件指针fput_light(sock->file, fput_needed);}return err; // 返回操作结果
}// 定义bind系统调用
SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
{// 调用__sys_bind函数,并返回其结果return __sys_bind(fd, umyaddr, addrlen);
}
二、代码解释
这段代码来自较老的版本的Linux内核,是`bind`系统调用的实现,其作用是将一个本地地址绑定到一个socket上。在Linux网络编程中,`bind`函数用于指定socket的本地地址,通常用在服务端指定端口号。下面将逐段用中文解读这段代码:
int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{
定义了函数`__sys_bind`,它接收三个参数:一个文件描述符`fd`,一个指向用户空间socket地址的指针`umyaddr`,以及地址的长度`addrlen`。
struct socket *sock;struct sockaddr_storage address;int err, fput_needed;
定义几个局部变量:`sock`用于存储内核中的socket对象的指针,`address`用于临时存储socket地址信息,`err`用于记录错误代码,`fput_needed`用于标记是否需要释放文件指针。
sock = sockfd_lookup_light(fd, &err, &fput_needed);
通过文件描述符`fd`获取对应的socket对象,并将该对象的地址存入`sock`。此外,记录任何查找错误到`err`,并设定是否需要释放文件指针到`fput_needed`。
if (sock) {
如果成功获取到了socket对象(即`sock`不为NULL)。
err = move_addr_to_kernel(umyaddr, addrlen, &address);
将用户空间中的socket地址`umyaddr`复制到内核空间中的`address`变量中,检查地址的有效性,如果成功则`err`为非负值。
if (err >= 0) {err = security_socket_bind(sock,(struct sockaddr *)&address,addrlen);
如果地址成功移动到内核空间,接着进行安全检查,看是否允许bind操作。
if (!err)err = sock->ops->bind(sock,(struct sockaddr *)&address, addrlen);}
如果通过了安全检查,调用对应协议的`bind`函数,以进行实际的绑定操作。
fput_light(sock->file, fput_needed);
完成绑定操作后,根据之前记录的`fput_needed`变量的值来决定是否释放文件指针。
}return err;
}
返回操作结果,如果`err`为0,则表示绑定成功;如果为负值,则表示绑定过程中出现了错误。
最后是`SYSCALL_DEFINE3`宏定义的`bind`函数,这是一个宏来方便地定义具有三个参数的系统调用,并最终调用`__sys_bind`来完成实际的工作:
SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
{return __sys_bind(fd, umyaddr, addrlen);
}
这部分定义了系统调用`bind`,接收三个参数,内部简单地调用了`__sys_bind`函数,并返回它的返回值。这个宏用于定义一个系统调用,它定义了一个名为bind
的系统调用,该系统调用接受三个参数:fd
、umyaddr
和addrlen
。SYSCALL_DEFINE3
宏会生成一个系统调用的实现,该实现会将参数从用户空间复制到内核空间,然后调用__sys_bind
函数来处理请求。
总之,这段代码实现了bind
系统调用,它允许用户空间程序将套接字与本地地址和端口号关联起来。在绑定过程中,还进行了必要的安全检查和地址结构体的复制操作。