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を実装しているソケットファミリは無いようです。


最終更新 2015/12/27 20:07:32 - north
(2015/12/27 20:07:32 作成)


検索

アクセス数
3694358
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。