日期:2014-05-16  浏览次数:20600 次

Linux内核网络协议栈5-socket地址绑定

?

一、socket绑定入口

1、示例代码
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("0.0.0.0");
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
?

2、绑定入口
前面介绍了socket从库函数到内核的过程,其最终都是通过102号中断进入内核,所不同的是子中断号不同;对于绑定,其子中断号是2;

和创建socket一样,绑定socket的处理函数都是:
asmlinkage long sys_socketcall(int call, unsigned long __user *args)
{
   	unsigned long a[6];
   	unsigned long a0, a1;
   	int err;
   	if (copy_from_user(a, args, nargs[call]))
          	return -EFAULT;
   	a0 = a[0];
   	a1 = a[1];

   	switch (call) {
          	…...
   	case SYS_BIND:
          	err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
          	…...
}
?
根据子中断号,内核会执行sys_bind()函数来完成地址的绑定;

二、绑定的具体过程
sys_bind()函数如下,一起来分析一下它的主要过程:
asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{
   	struct socket *sock;
   	char address[MAX_SOCK_ADDR];
   	int err, fput_needed;
    // 1, 根据fd查找相应的socket结构
   	sock = sockfd_lookup_light(fd, &err, &fput_needed);
   	if (sock) {
            // 2, 将用户空间的地址结构拷贝到内核空间
          	err = move_addr_to_kernel(umyaddr, addrlen, address);
          	if (err >= 0) {
                 	err = security_socket_bind(sock,
                                      	  (struct sockaddr *)address,
                                      	  addrlen);
                 	if (!err)
                        	// 3, 根据协议域及socket类型,调用相应的bind函数
                        	err = sock->ops->bind(sock,
                                      	     (struct sockaddr *)
                                      	     address, addrlen);
          	}
          	fput_light(sock->file, fput_needed);
   	}
   	ret