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
在内核执行的系统调用代码
-
SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
-
{
-
struct socket *sock;
-
struct sockaddr_storage address;
-
int err, fput_needed;
-
-
sock = sockfd_lookup_light(fd, &err, &fput_needed);
-
if (sock) {
-
err = move_addr_to_kernel(umyaddr, addrlen, &address);
-
if (err >= 0) {
-
err = security_socket_bind(sock,
-
(struct sockaddr *)&address,
-
addrlen);
-
if (!err)
-
err = sock->ops->bind(sock,
-
(struct sockaddr *)
-
&address, addrlen);
-
}
-
fput_light(sock->file, fput_needed);
-
}
-
return err;
-
}
内核中会根据socket描述符找到struct socket结构,然后将用户传到内核的地址拷贝到内核,最终调用的
sock->ops->bind 执行最终的绑定操作,对本地socket就是unix_stream_ops->bind,也就是执行unix_bind函数
-
static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
-
{
-
struct sock *sk = sock->sk;
-
struct net *net = sock_net(sk);
-
struct unix_sock *u = unix_sk(sk);
-
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
-
char *sun_path = sunaddr->sun_path;
-
int err;
-
unsigned int hash;
-
struct unix_address *addr;
-
struct hlist_head *list;
-
struct path path = { };
-
-
err = -EINVAL;
-
if (addr_len < offsetofend(struct sockaddr_un, sun_family) ||
-
sunaddr->sun_family != AF_UNIX)
-
goto out;
-
-
if (addr_len == sizeof(short)) {
-
err = unix_autobind(sock);
-
goto out;
-
}
-
-
err = unix_mkname(sunaddr, addr_len, &hash);
-
if (err < 0)
-
goto out;
-
addr_len = err;
-
-
if (sun_path[0]) {
-
umode_t mode = S_IFSOCK |
-
(SOCK_INODE(sock)->i_mode & ~current_umask());
-
err = unix_mknod(sun_path, mode, &path);
-
if (err) {
-
if (err == -EEXIST)
-
err = -EADDRINUSE;
-
goto out;
-
}
-
}
-
-
err = mutex_lock_interruptible(&u->bindlock);
-
if (err)
-
goto out_put;
-
-
err = -EINVAL;
-
if (u->addr)
-
goto out_up;
-
-
err = -ENOMEM;
-
addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
-
if (!addr)
-
goto out_up;
-
-
memcpy(addr->name, sunaddr, addr_len);
-
addr->len = addr_len;
-
addr->hash = hash ^ sk->sk_type;
-
refcount_set(&addr->refcnt, 1);
-
-
if (sun_path[0]) {
-
addr->hash = UNIX_HASH_SIZE;
-
hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
-
spin_lock(&unix_table_lock);
-
u->path = path;
-
list = &unix_socket_table[hash];
-
} else {
-
spin_lock(&unix_table_lock);
-
err = -EADDRINUSE;
-
if (__unix_find_socket_byname(net, sunaddr, addr_len,
-
sk->sk_type, hash)) {
-
unix_release_addr(addr);
-
goto out_unlock;
-
}
-
-
list = &unix_socket_table[addr->hash];
-
}
-
-
err = 0;
-
__unix_remove_socket(sk);
-
u->addr = addr;
-
__unix_insert_socket(list, sk);
-
-
out_unlock:
-
spin_unlock(&unix_table_lock);
-
out_up:
-
mutex_unlock(&u->bindlock);
-
out_put:
-
if (err)
-
path_put(&path);
-
out:
-
return err;
-
}
unix_mkname 会检查传入的socket地址,然后unix_mknod在文件系统创建这个socket文件
内核根据地址计算哈希值,然后将这个socket对应的传输控制块结构加入对应的哈希表中。至此绑定操作完成
阅读(1853) | 评论(0) | 转发(0) |