Chinaunix首页 | 论坛 | 博客
  • 博客访问: 68767
  • 博文数量: 11
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 120
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-06 15:04
文章分类
文章存档

2018年(11)

我的朋友

分类: LINUX

2018-04-07 14:55:22

socket要执行绑定这个操作,搜索一下ret = bind(sockfd, (struct sockaddr *)&addr, addrlen);绑定操作将一个地址同一个socket进行关联,网络socket 使用struct sockaddr_in,本地socket使用struct sockaddr_un;
struct sockaddr_un {

  sa_family_t sun_family; /*PF_UNIX或AF_UNIX */

  char sun_path[UNIX_PATH_MAX]; /* 路径名 */

  };
#define UNIX_PATH_MAX 108 可见本地socket路径最大的长度是108

在内核执行的系统调用代码

点击(此处)折叠或打开

  1. SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
  2. {
  3.     struct socket *sock;
  4.     struct sockaddr_storage address;
  5.     int err, fput_needed;

  6.     sock = sockfd_lookup_light(fd, &err, &fput_needed);
  7.     if (sock) {
  8.         err = move_addr_to_kernel(umyaddr, addrlen, &address);
  9.         if (err >= 0) {
  10.             err = security_socket_bind(sock,
  11.                          (struct sockaddr *)&address,
  12.                          addrlen);
  13.             if (!err)
  14.                 err = sock->ops->bind(sock,
  15.                          (struct sockaddr *)
  16.                          &address, addrlen);
  17.         }
  18.         fput_light(sock->file, fput_needed);
  19.     }
  20.     return err;
  21. }

内核中会根据socket描述符找到struct socket结构,然后将用户传到内核的地址拷贝到内核,最终调用的sock->ops->bind 执行最终的绑定操作,对本地socket就是unix_stream_ops->bind,也就是执行unix_bind函数

点击(此处)折叠或打开

  1. static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
  2. {
  3.     struct sock *sk = sock->sk;
  4.     struct net *net = sock_net(sk);
  5.     struct unix_sock *u = unix_sk(sk);
  6.     struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
  7.     char *sun_path = sunaddr->sun_path;
  8.     int err;
  9.     unsigned int hash;
  10.     struct unix_address *addr;
  11.     struct hlist_head *list;
  12.     struct path path = { };

  13.     err = -EINVAL;
  14.     if (addr_len < offsetofend(struct sockaddr_un, sun_family) ||
  15.      sunaddr->sun_family != AF_UNIX)
  16.         goto out;

  17.     if (addr_len == sizeof(short)) {
  18.         err = unix_autobind(sock);
  19.         goto out;
  20.     }

  21.     err = unix_mkname(sunaddr, addr_len, &hash);
  22.     if (err < 0)
  23.         goto out;
  24.     addr_len = err;

  25.     if (sun_path[0]) {
  26.         umode_t mode = S_IFSOCK |
  27.          (SOCK_INODE(sock)->i_mode & ~current_umask());
  28.         err = unix_mknod(sun_path, mode, &path);
  29.         if (err) {
  30.             if (err == -EEXIST)
  31.                 err = -EADDRINUSE;
  32.             goto out;
  33.         }
  34.     }

  35.     err = mutex_lock_interruptible(&u->bindlock);
  36.     if (err)
  37.         goto out_put;

  38.     err = -EINVAL;
  39.     if (u->addr)
  40.         goto out_up;

  41.     err = -ENOMEM;
  42.     addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
  43.     if (!addr)
  44.         goto out_up;

  45.     memcpy(addr->name, sunaddr, addr_len);
  46.     addr->len = addr_len;
  47.     addr->hash = hash ^ sk->sk_type;
  48.     refcount_set(&addr->refcnt, 1);

  49.     if (sun_path[0]) {
  50.         addr->hash = UNIX_HASH_SIZE;
  51.         hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
  52.         spin_lock(&unix_table_lock);
  53.         u->path = path;
  54.         list = &unix_socket_table[hash];
  55.     } else {
  56.         spin_lock(&unix_table_lock);
  57.         err = -EADDRINUSE;
  58.         if (__unix_find_socket_byname(net, sunaddr, addr_len,
  59.                      sk->sk_type, hash)) {
  60.             unix_release_addr(addr);
  61.             goto out_unlock;
  62.         }

  63.         list = &unix_socket_table[addr->hash];
  64.     }

  65.     err = 0;
  66.     __unix_remove_socket(sk);
  67.     u->addr = addr;
  68.     __unix_insert_socket(list, sk);

  69. out_unlock:
  70.     spin_unlock(&unix_table_lock);
  71. out_up:
  72.     mutex_unlock(&u->bindlock);
  73. out_put:
  74.     if (err)
  75.         path_put(&path);
  76. out:
  77.     return err;
  78. }
unix_mkname 会检查传入的socket地址,然后unix_mknod在文件系统创建这个socket文件
内核根据地址计算哈希值,然后将这个socket对应的传输控制块结构加入对应的哈希表中。至此绑定操作完成
阅读(1843) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~