socketpairシステムコール
Rev.1を表示中。最新版はこちら。
UNIXドメインソケットは、異なるプロセス間のソケットを接続するため、元のソケットをbindでソケットスペシャルファイルを作成し、そのinode番号をインデックスとするソケットを作成します。それを接続するタスクのconnectで、接続するタスクソケットをpeerとする接続元タスクが使用するソケットを作成、接続元タスクはacceptでそのソケットを取得して、両タスクでの通信を実現します。しかし、親子プロセスのように、ファイルIDを共有するタスク間では、このような実装は不要です。socketpairシステムコールは、互いのソケットのpeerを互いのソケットする2つのソケットを取得し、connect/acceptなく、ソケット間でやり取りを行うためのシステムコールです。
sock1->peer = sock2/sock2->peer = sock1のソケットを作成し、 file->private_data = sockとする
2つのfileを取得します。
SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
int __user *, usockvec)
{
struct socket *sock1, *sock2;
int fd1, fd2, err;
struct file *newfile1, *newfile2;
int flags;
flags = type & ~SOCK_TYPE_MASK;
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
return -EINVAL;
type &= SOCK_TYPE_MASK;
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
err = sock_create(family, type, protocol, &sock1);
if (err < 0)
goto out;
err = sock_create(family, type, protocol, &sock2);
if (err < 0)
goto out_release_1;
err = sock1->ops->socketpair(sock1, sock2);
if (err < 0)
goto out_release_both;
fd1 = sock_alloc_file(sock1, &newfile1, flags);
if (unlikely(fd1 < 0)) {
err = fd1;
goto out_release_both;
}
fd2 = sock_alloc_file(sock2, &newfile2, flags);
if (unlikely(fd2 < 0)) {
err = fd2;
fput(newfile1);
put_unused_fd(fd1);
sock_release(sock2);
goto out;
}
audit_fd_pair(fd1, fd2);
fd_install(fd1, newfile1);
fd_install(fd2, newfile2);
err = put_user(fd1, &usockvec[0]);
if (!err)
err = put_user(fd2, &usockvec[1]);
if (!err)
return 0;
sys_close(fd2);
sys_close(fd1);
return err;
out_release_both:
sock_release(sock2);
out_release_1:
sock_release(sock1);
out:
return err;
}
#define unix_peer(sk) (unix_sk(sk)->peer)
static int unix_socketpair(struct socket *socka, struct socket *sockb)
{
struct sock *ska = socka->sk, *skb = sockb->sk;
sock_hold(ska);
sock_hold(skb);
unix_peer(ska) = skb;
unix_peer(skb) = ska;
init_peercred(ska);
init_peercred(skb);
if (ska->sk_type != SOCK_DGRAM) {
ska->sk_state = TCP_ESTABLISHED;
skb->sk_state = TCP_ESTABLISHED;
socka->state = SS_CONNECTED;
sockb->state = SS_CONNECTED;
}
return 0;
}
static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
{
struct qstr name = { .name = "" };
struct path path;
struct file *file;
int fd;
fd = get_unused_fd_flags(flags);
if (unlikely(fd < 0))
return fd;
path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
if (unlikely(!path.dentry)) {
put_unused_fd(fd);
return -ENOMEM;
}
path.mnt = mntget(sock_mnt);
d_instantiate(path.dentry, SOCK_INODE(sock));
SOCK_INODE(sock)->i_fop = &socket_file_ops;
file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
&socket_file_ops);
if (unlikely(!file)) {
ihold(path.dentry->d_inode);
path_put(&path);
put_unused_fd(fd);
return -ENFILE;
}
sock->file = file;
file->f_flags = O_RDWR | (flags & O_NONBLOCK);
file->f_pos = 0;
file->private_data = sock;
*f = file;
return fd;
}
備考
DGRAMのstruct proto_ops unix_dgram_opsも.socketpair = unix_socketpairとなっており、DGRAMでのsocketpairは、機能的にseqpacketと同じ物ととなります。ざくっと走査したところ、UNIXドメインソケット以外、socketpairを実装しているソケットファミリは無いようです。






