FreeBSD kernel SOCKET I/F 探検

第6回 socket() システムコール (4)

2013.12.04

必要とする知識など:
  • UNIX (含む Linux) 上での C 言語と SOCKET によるプログラミング経験および TCP/IP に関する知識。

socket() システムコール、四回目です。falloc() から sys_socket() に戻ったところです。

error = socreate(uap->domain, &so, uap->type, uap->protocol,
    td->td_ucred, td);

socreate() は、/usr/src/sys/kern/uipc_socket.c (http://svnweb.freebsd.org/base/release/9.1.0/sys/kern/uipc_socket.c?view=markup) で以下のように定義されています。

int
socreate(int dom, struct socket **aso, int type, int proto,
    struct ucred *cred, struct thread *td)

第一引数は socket() システムコールの第一引数の int domain が渡されます。第二引数 struct socket **aso は、socreate() 関数内で struct socket 用の領域を確保しそれを返却します。第三引数と第四引数は、socket() システムコールの第二、第三引数の int type と int protocolが渡されます。第五引数には前前回(http://www.soum.co.jp/misc/asou/fbsd-kernel-socket/4.html) で出てきた認証情報が渡されます。第六引数は今までにも頻繁に出てきた struct thread です。

socreate() の最初の処理は以下のようになっています。

if (proto)
        prp = pffindproto(dom, proto, type);
else
        prp = pffindtype(dom, type);

server.c から socket() システムコールを呼び出す際 (http://www.soum.co.jp/misc/asou/fbsd-kernel-socket/3.html)、proto には 0 を指定しているので、pffindtype() が呼ばれます。pffindtype() は、/usr/src/sys/kern/uipc_domain.c (http://svnweb.freebsd.org/base/release/9.1.0/sys/kern/uipc_domain.c?view=markup) で以下のように定義されています。

 struct protosw *
 pffindtype(int family, int type)
 {
       struct domain *dp;
       struct protosw *pr;

       for (dp = domains; dp; dp = dp->dom_next)
               if (dp->dom_family == family)
                       goto found;
       return (0);
found:
       for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
               if (pr->pr_type && pr->pr_type == type)
                       return (pr);
       return (0);

最初の for 文で使用している domains は、uipc_domain.c 内で以下のように定義されています。

struct domain *domains;

詳細な説明は省きますが、struct domain *domains は、下図のように struct domain と struct protosw で構成されるリスト構造の先頭の struct domain のポインタを保持します。

図では AF_INET, AF_INET6 という順番になっていますが、実際の kernel 内での順番を示すものではありません。

なお、struct domain inetdomain/struct protosw inetsw, struct domain inet6domain/struct ip6protosw inet6sw は、それぞれ /usr/src/sys/netinet/in_proto.c (http://svnweb.freebsd.org/base/release/9.1.0/sys/netinet/in_proto.c?view=markup), /usr/src/sys/netinet6/in6_proto.c (http://svnweb.freebsd.org/base/release/9.1.0/sys/netinet6/in6_proto.c?view=markup) で定義されています。

ちょっと脱線
本連載の 4回目 の最初のところで SOCKET(2) からの引用を示し、「domain には PF_* を指定する。」ことを示していますが、上図の inetdomain と inet6domain で dom_family に AF_* を代入しているのは SOCKET(2) の記述と矛盾しているなと思います。

pffindtype() ですが、まずは domains が保持するリストから pffindtype() の第一引数 family と一致する dom_family を探します。、一致するものが見つかればその dom_protosw が示す struct protosw の配列から、pffindtype() の第二引数type と一致する pr_type を探します。一致するものが見つかれば、その struct protosw へのポインタを返却し、見つからなかった場合には 0 (NULL) を返却して終了します。

socreate() からの呼び出しは pffindtype(PF_INET, SOCK_DGRAM) となるので、上図左側の struct protosw inetsw の 2番目の要素のポインタ &inetsw[1] が返却されます。

今回の処理で変更した変数を青、変更した値は赤で示しています。

pffindtype() から socreate() に戻ると、エラー処理の次に prison_check_af() を呼び出します。

if (prison_check_af(cred, prp->pr_domain->dom_family) != 0)

prison_check_af() は、/usr/src/sys/kern/kern_jail.c (http://svnweb.freebsd.org/base/release/9.1.0/sys/kern/kern_jail.c?view=markup) で定義されています。prison_check_af() の詳細に関しては割愛しますが、socreate() の第五引数 struct ucred *cred で prp->pr_domain->dom_family がサポートされていることを確認しています。

prison_check_af() の次は soalloc() の呼び出しですが、今回はここで終了です。

著者プロフィール

asou

好きな OS は、FreeBSD です。が、最近購入した Mac mini がなかなか快適なので、Mac でいいかなと思うようになってきました。

記事一覧Index