書式
#include <sys/socket.h>#include <sys/un.h>
unix_socket = socket(AF_UNIX, type, 0);
error = socketpair(AF_UNIX, type, 0, int *sv);
説明
AF_UNIX (AF_LOCAL とも言われる) ソケットファミリーは、同じマシン上で プロセス同士が 効率的に通信するために用いられる。伝統的に、UNIX ドメイン ソケットは、名前なしにもできるし、 (ソケット型であると印のついた) ファイル システムのパス名に 結び付けることもできる。さらに Linux では、ファイル システムに依存しない抽象名前空間 (abstract namespace) もサポートしている。有効なタイプを以下に示す。 SOCK_STREAM はストリーム指向のソケットである。 SOCK_DGRAM はメッセージ境界を保存するデータグラム指向のソケットである (ほとんどの UNIX の実装では、UNIX ドメイン・データグラム・ソケットは 常に 信頼でき、データグラムの並び替えは行わない)。 SOCK_SEQPACKET はメッセージ境界を保存し、送信された順序でメッセージを 届ける接続指向ソケット である (Linux 2.6.4 以降で利用できる)。
UNIX ドメインソケットでは、補助データを使って ファイルディスクリプタや プロセスの信任状 (credential) を 送受信することもできる。
アドレスのフォーマット
UNIX ドメインソケットのアドレスは以下の構造体で表現される。#define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ };
sun_family には必ず AF_UNIX が入っている。
この構造体では 3 種類のアドレスが区別される。
- *
-
pathname (パス名): bind(2) を使って、UNIX ドメインソケットをヌル終端されたファイルシステム上の
パス名に結び付けることができる。 getsockname(2), getpeername(2), accept(2)
がソケットのアドレスを返す際には、その長さは
offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1であり、 sun_path にヌル終端されたパス名が格納される。
- *
- unnamed (名前なし): bind(2) を使ってパス名に結び付けることができないストリーム型のソケットは 名前を持たない。同様に、 socketpair(2) で作成される 2 つのソケットも名前を持たない。 getsockname(2), getpeername(2), accept(2) が名前なしのソケットのアドレスを返す際には、 その長さは sizeof(sa_family_t) であり、 sun_path は検査すべきではない。
- *
- abstract (抽象): 抽象ソケットアドレスは、 sun_path[0] がヌルバイト ('\0') であることで区別される。この名前空間におけるソケットのアドレス は、 sun_path の残りのバイトの、アドレス構造体の指定された長さの範囲で表さ れる (名前中のヌルバイトには特別な意味はない)。この名前はファイルシステムの パス名とは何の関係もない。 getsockname(2), getpeername(2), accept(2) が抽象ソケットのアドレスを返す際には、返される addrlen は sizeof(sa_family_t) より大きく (つまり 2 より大きく)、ソケットの名前は sun_path の最初の (addrlen - sizeof(sa_family_t)) バイトに格納される。 ソケットの抽象名前空間は Linux による拡張であり、移植性はない。
ソケットオプション
歴史的な理由により、これらのオプションは たとえ AF_UNIX 固有のオプションであっても SOL_SOCKET 型で指定する。 ソケットファミリーとして SOL_SOCKET を指定すると、 setsockopt(2) でオプションが設定でき、 getsockopt(2) で取得ができる。- SO_PASSCRED
- 送信プロセスの補助メッセージで信任状を受信できるようにする。このオプションが セットされていて、まだソケットが接続されていないと、抽象名前空間に他と重なら ない名前が自動的に生成される。ブール整数値のフラグを取る。
自動バインド (autobind) 機能
bind(2) 呼び出しで sizeof(sa_family_t) として addrlen を指定するか、 アドレスに明示的にバインドされていないソケットに対して SO_PASSCRED ソケットオプションが指定されていた場合、 そのソケットは抽象アドレスに自動的にバインドされる。 このアドレスは、1 個のヌルバイトの後に、文字集合 [0-9a-f] のバイトが 5 個続く形式である。したがって、自動的にバインドされるアドレス数には 2^20 個という上限が存在する。 (Linux 2.1.15 以降で、自動バインド機能が追加されたときには、 8 バイトが使われており、自動バインドアドレス数の上限は 2^32 であった。 Linux 2.3.15 で 5 バイトに変更された。)ソケット API
この節では、Linux の UNIX ドメインソケットでの、ドメイン固有の詳細仕様と ソケット API でサポートされていない機能について説明する。UNIX ドメインソケットでは、帯域外データ (out-of-band data) の 送信 (send(2) と recv(2) の MSG_OOB フラグ) はサポートされていない。
send(2) MSG_MORE フラグは UNIX ドメインソケットではサポートされていない。
recv(2) の flags 引き数での MSG_TRUNC の使用は UNIX ドメイン ソケットではサポートされていない。
SO_SNDBUF ソケットオプションは UNIX ドメインソケットで効果を持つが、 SO_RCVBUF は効果がない。 データグラム・ソケットでは、 SO_SNDBUF の値が 出力データグラムの上限サイズとなる。 実際の上限値は、 SO_SNDBUF オプション として設定された値の 2倍 (socket(7) 参照) からオーバヘッドとして使用される 32 バイトを引いた値となる。
補助メッセージ
補助データを送受するには、 sendmsg(2) や recvmsg(2) を使用する。 歴史的な理由により、以下に示す補助メッセージの型は たとえ AF_UNIX 固有のものであっても SOL_SOCKET 型で指定する。 これらを送るには、構造体 cmsghdr の cmsg_level フィールドに SOL_SOCKET をセットし、 cmsg_type フィールドにタイプをセットする。 詳細は cmsg(3) を見よ。- SCM_RIGHTS
- 他のプロセスでオープンされたファイルディスクリプタのセットを送受信する。 データ部分にファイルディスクリプタの整数配列が入っている。 渡されたファイルディスクリプタは、あたかも dup(2) で生成されたかのように振る舞う。
- SCM_CREDENTIALS
-
UNIX 信任状を送受信する。これは認証に用いることができる。
信任状は struct ucred の補助メッセージとして渡される。
この構造体は <sys/socket.h> で以下のように定義されている。
struct ucred { pid_t pid; /* process ID of the sending process */ uid_t uid; /* user ID of the sending process */ gid_t gid; /* group ID of the sending process */ };
glibc 2.8 以降では、この構造体の定義を得るためには (どのヘッダファイルをインクルードするよりも前に) 機能検査マクロ _GNU_SOURCE を定義しなければならない。
送信側が指定した信任状は、カーネルがチェックする。 実効ユーザー ID が 0 のプロセスには、 自分自身以外の値を指定する事が許される。 送信側は以下の 3 つを指定しなければならない。 1) 自分自身のプロセス ID (CAP_SYS_ADMIN 権限を持っていない場合)、 2) 自分自身のユーザー ID あるいは実効ユーザー ID か保存 set-user-ID (CAP_SETUID 権限を持っていない場合)、 3) 自分自身のグループ ID あるいは実行グループ ID か保存 set-group-ID (CAP_SETGID を持っていない場合)。 struct ucred メッセージを受信するためには、ソケットに対し SO_PASSCRED オプションを有効にしなくてはならない。
ioctl
以下の ioctl(2) 呼び出しは value に情報を入れて返す。 正しい書式は以下の通り。
-
int value; error = ioctl(unix_socket, ioctl_type, &value);
ioctl_type には以下を指定できる:
- SIOCINQ
- 受信バッファのキューにある、まだ読んでいないデータの量を返す。ソケットは LISTEN 状態にあってはならず、さもないとエラー (EINVAL) が返る。 SIOCINQ は <linux/sockios.h> で定義されている。 代わりに、<sys/ioctl.h> で定義されている、同義語の FIONREAD を使うこともできる。
エラー
- EADDRINUSE
- 指定したローカルアドレスが既に使用されているか、ファイルシステムの ソケットオブジェクトが既に存在している。
- ECONNREFUSED
- connect(2) により指定されたリモートアドレスが接続待ちソケットではなかった。 ターゲットアドレスがソケットではない場合にもこのエラーが発生する。
- ECONNRESET
- リモートソケットが予期しないかたちでクローズされた。
- EFAULT
- ユーザーメモリアドレスが不正。
- EINVAL
- 渡した引数が不正。よくある原因としては、渡したアドレスの sun_type フィール ドに AF_UNIX が指定されていなかった、行おうとした操作に対してソケットが有 効な状態ではなかった、など。
- EISCONN
- 既に接続されているソケットに対して connect(2) が呼ばれた。または、指定したターゲットアドレスが 既に接続済みのソケットだった。
- ENOENT
- connect(2) に指定されたリモートアドレスのパス名が存在しなかった。
- ENOMEM
- メモリが足りない。
- ENOTCONN
- ソケット操作にターゲットアドレスが必要だが、 このソケットは接続されていない。
- EOPNOTSUPP
- ストリーム指向でないソケットに対してストリーム操作が呼び出された。 または帯域外データオプションを用いようとした。
- EPERM
- 送信者が struct ucred に不正な信任状を渡した。
- EPIPE
- リモートソケットがストリームソケット上でクローズされた。 可能な場合は SIGPIPE も同時に送られる。これを避けるには MSG_NOSIGNAL フラグを sendmsg(2) や recvmsg(2) に渡す。
- EPROTONOSUPPORT
- 渡されたプロトコルが AF_UNIX でない。
- EPROTOTYPE
- リモートソケットとローカルソケットのタイプが一致していなかった (SOCK_DGRAM と SOCK_STREAM)。
- ESOCKTNOSUPPORT
- 未知のソケットタイプ。
他にも汎用のソケット層でエラーが起こったり、 ファイルシステム上にソケットオブジェクトを作ろうとした場合に ファイルシステムのエラーが起こることがある。 それぞれの詳細は適切な man ページを参照すること。
バージョン
SCM_CREDENTIALS と抽象名前空間は、Linux 2.2 で導入された。 移植性が必要なプログラムでは使うべきではない。 (BSD 由来のシステムの中にも信任状の送受信をサポートしているものがあるが、 その実装の詳細はシステムによって異なる)注意
Linux の実装では、 ファイルシステム上から見えるソケットは、 それらが置かれているディレクトリのパーミッションに従う。 ソケットの所有者、 グループ、 パーミッションは変更できる。 新しいソケットを作るとき、 作ろうとするディレクトリに対して プロセスが書き込みと検索 (実行) 権限を持っていなければ、 作成に失敗する。 ソケットオブジェクトに接続するには、 read/write 権限が必要である。 この動作は、 多くの BSD 由来のシステムとは異なっている (BSD では UNIX ドメインソケットに対してはパーミッションを無視する)。 移植性の必要なプログラムでは、セキュリティをこの仕様に依存してはならない。ファイル名を指定してソケットにバインドすると、ファイルシステムにソケットが 生成される。これは必要なくなったときに呼びだしたユーザーが削除しなければ ならない (unlink(2) を用いる)。 UNIX で通常使われる「背後で閉じる方式」 が適用される。ソケットはいつでも unlink することができ、最後の参照が クローズされたときにファイルシステムから削除される。
SOCK_STREAM 上でファイルディスクリプタや信任状を渡すためには、同じ sendmsg(2) や recvmsg(2) コールで補助データ以外のデータを少なくとも 1 バイト送信/受信する必要がある。
UNIX ドメインのストリーム・ソケットでは、 帯域外データの概念はサポートされない。
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。