struct socket構造の詳細


ユーザがsocketシステムを使用してアプリケーションの作成を呼び出すと、ソケット記述子と呼ばれるすべての操作が1つの数字で表されます.システム呼び出しの実装関数では、この数字はsocketを表す構造体にマッピングされ、この構造体はsocketのすべての属性とデータを保存します.カーネルのプロトコル実装では,socketを表す構造体について,比較的複雑なものであり,以下で紹介する.
    struct socket.
これは基本的なBSD socketであり、socketシステム呼び出しによって作成された様々な異なるタイプのsocketを呼び出し、作成を開始したのはすべてそれであり、その後、様々な異なるタイプのsocketがそれに基づいて様々な拡張を行う.struct socketは仮想ファイルシステム上で作成され、ファイルと見なすことができ、安全に拡張することができます.以下に完全な定義を示します.
    struct socket {
        socket_state            state;
        unsigned long           flags;
        const struct proto_ops *ops;
        struct fasync_struct    *fasync_list;
        struct file             *file;
        struct sock             *sk;
        wait_queue_head_t       wait;
        short                   type;
    };

stateはsocketが置かれている状態を表すために使用され、列挙変数であり、そのタイプは以下のように定義されています.
    typedef enum {
        SS_FREE = 0,            // socket    
        SS_UNCONNECTED,         //     socket
        SS_CONNECTING,          //       
        SS_CONNECTED,           //     socket
        SS_DISCONNECTING        //          
    }socket_state;

このメンバーは、tcpのみが接続向けプロトコルであるため、udpとrawはsocket状態を維持する必要がないため、TCP socketにのみ有用である.
flagsはフラグビットのセットであり、カーネルでは使用されていない.
opsはプロトコルに関連する一連の操作セットであり、構造体struct proto_opsの定義は以下の通りです.
   
struct proto_ops {
        int     family;
        struct module   *owner;
        int (*release)(struct socket *sock);
        int (*bind)(struct socket *sock, struct sockaddr *myaddr, int sockaddr_len);
        int (*connect)(struct socket *sock, struct sockaddr *vaddr, int sockaddr_len, int flags);
        int (*socketpair)(struct socket *sock1, struct socket *sock2);
        int (*accept)(struct socket *sock,struct socket *newsock, int flags);
        int (*getname)(struct socket *sock, struct sockaddr *addr,int *sockaddr_len, int peer);
        unsigned int (*poll)(struct file *file, struct socket *sock,
                        struct poll_table_struct *wait);
        int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
        int (*listen)(struct socket *sock, int len);
        int (*shutdown)(struct socket *sock, int flags);
        int (*setsockopt)(struct socket *sock, int level,
                        int optname, char __user *optval, int optlen);
        int (*getsockopt)(struct socket *sock, int level,
                        int optname, char __user *optval, int __user *optlen);
        int (*sendmsg)(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *m, size_t total_len);
        int (*recvmsg)(struct kiocb *iocb, struct socket *sock,
                        struct msghdr *m, size_t total_len, int flags);
        int (*mmap)(struct file *file, struct socket *sock,struct vm_area_struct * vma);
        ssize_t (*sendpage)(struct socket *sock, struct page *page,
                        int offset, size_t size, int flags);
    };
    
プロトコルスタックには、合計3つのstrcut proto_が定義されています.opsタイプの変数、それぞれmyinet_stream_ops, myinet_dgram_ops, myinet_sockraw_ops,ストリームプロトコル,データレポート,および元のインタフェースプロトコルに対する操作関数セット.
typeはsocketのタイプで、対応する値は以下の通りです.
    enum sock_type {
        SOCK_DGRAM = 1,
        SOCK_STREAM = 2,
        SOCK_RAW    = 3,
        SOCK_RDM    = 4,
        SOCK_SEQPACKET = 5,
        SOCK_DCCP   = 6,
        SOCK_PACKET = 10,
    };

skはネットワーク層のsocketの表現であり、構造体struct sockは比較的膨大であり、ここでは詳細にはリストされず、重要なメンバーだけを紹介している.
    sk_protとsk_prot_creator、この2つのメンバーは特定のプロトコル処理関数セットを指し、そのタイプは構造体struct protoであり、この構造体もstruct proto_と同じである.opsに似たプロトコル操作関数セットのセット.この2つの概念は少し混同されているようですが、struct proto_opsのメンバーはstruct socket階層上のデータを操作し、処理が完了し、メンバーsk->skを呼び出すprotの関数はstruct sock階層上のデータを操作します.つまり、それらの間には階層的な違いがあります.struct protoタイプの変数はプロトコルスタックに全部で3つあり、それぞれmytcp_である.prot,myudp_prot,myraw_Protは、TCP、UDP、RAWプロトコルに対応します.
    sk_stateはsocketの現在の接続状態を表し、struct socketのstateよりも細かい状態であり、その可能な値は以下の通りである.
     enum {
        TCP_ESTABLISHED = 1,
        TCP_SYN_SENT,
        TCP_SYN_RECV,
        TCP_FIN_WAIT1,
        TCP_FIN_WAIT2,
        TCP_TIME_WAIT,
        TCP_CLOSE,
        TCP_CLOSE_WAIT,
        TCP_LAST_ACK,
        TCP_LISTEN,
        TCP_CLOSING,

        TCP_MAX_STATES
    };

これらの値は名前から見るとTCPプロトコルのみで使用されているようですが、実際にはUDPとRAWもいくつかの値を借りており、1つのsocketが作成された当初はTCP_CLOSE、UDPソケット接続が完了したら、この値をTCP_に変更します.ESTABLISHED、最後に、socktを閉じてTCPに戻るCLOSE、RAWも同じです.
    sk_rcvbufとsk_sndbufは、受信バッファと送信バッファのサイズをそれぞれ表す.sk_receive_queueとsk_write_Queueはそれぞれ受信バッファキューと送信バッファキューであり、キューにはソケットバッファstruct sk_が並んでいるbuff,キュー内のstruct sk_buffのバイト数の合計はバッファサイズの設定を超えてはいけません.
続いて前編ではstruct sockについて引き続きご紹介します.
    sk_rmem_alloc, sk_wmem_allocとsk_omem_allocは、バッファの使用状況を追跡するために、受信バッファキュー、送信バッファキュー、および他のバッファキューに割り当てられたバイト数をそれぞれ表す.
struct sockにはstruct sockがありますcommonメンバー、struct inet_timewait_sockも使用するので、構造体に単独で分類します.定義は次のとおりです.
    struct sock_common {
        unsigned short      skc_family;
        volatile unsigned char skc_state;
        unsigned char       skc_reuse;
        int         skc_bound_dev_if;
        struct hlist_node   skc_node;
        struct hlist_node   skc_bind_node;
        atomic_t        skc_refcnt;
        unsigned int        skc_hash;
        struct proto        *skc_prot;
    };

    struct inet_sock.
これはINETドメイン専用のsocket表現で、struct sockに基づいて拡張され、基本的なsocketの属性がすでに備えられている上で、struct inet_sockは、TTL、マルチキャストリスト、IPアドレス、ポートなど、INETドメイン固有のいくつかの属性を提供しています.以下は、その完全な定義です.
struct inet_sock {
            struct sock     sk;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
            struct ipv6_pinfo   *pinet6;
#endif
            __u32           daddr;          //IPv4     。
            __u32           rcv_saddr;      //IPv4       。
            __u16           dport;          //    。
            __u16           num;            //    (     )。
            __u32           saddr;          //    。
            __s16           uc_ttl;         //   ttl。
            __u16           cmsg_flags;
            struct ip_options   *opt;
            __u16           sport;          //   。
            __u16           id;             //        ,    iphdr id 。
            __u8            tos;            //    。
            __u8            mc_ttl;         //   ttl
            __u8            pmtudisc;
            __u8            recverr:1,
                            is_icsk:1,
                            freebind:1,
                            hdrincl:1,      //      ip  (  raw  )
                            mc_loop:1;      //        。
            int             mc_index;       //              。
            __u32           mc_addr;        //     。
            struct ip_mc_socklist   *mc_list;   //     。
            struct {
                unsigned int        flags;
                unsigned int        fragsize;
                struct ip_options   *opt;
                struct rtable       *rt;
                int                 length;
                u32                 addr;
                struct flowi        fl;
            } cork;
        };

    struct raw_sock
これはRAWプロトコル専用のsocketの表現で、struct inet_RAWプロトコルはICMPプロトコルのフィルタ設定を処理するため、以下のように定義されている.
    struct raw_sock {
        struct inet_sock   inet;
        struct icmp_filter filter;
    };

    struct udp_sock
これはUDPプロトコル専用のsocket表現で、struct inet_sockベースの拡張は、以下のように定義されています.
    struct udp_sock {
        struct inet_sock inet;
        int             pending;
        unsigned int    corkflag;
        __u16           encap_type;
        __u16           len;
    };

    struct inet_connection_sock
上の2つを見て、3つ目はstruct tcpだと思います.だが実際はstruct tcpsockはstruct inetから直接sock上で拡張するのではなくstruct inet_からconnection_sockベースで拡張、struct inet_connection_sockは接続向けのすべてのsocketの表現であり,このsocket,および以下のすべてのtcpに関連するsocketについて,tcp実装を解析する際に詳細に説明するが,ここではそれらの関係のみをリストする.
    strcut tcp_sock
これはTCPプロトコル専用のsocket表現でありstruct inet_connection_sockベースは拡張され,主にスライドウィンドウプロトコルを追加し,混雑アルゴリズムなどのTCP固有属性を回避した.
    struct inet_timewait_sock
    struct tcp_timewait_sock
struct inet_timewait_sockに基づいて拡張します.
    struct inet_request_sock
    struct tcp_request_sock
struct inet_request_sockに基づいて拡張します.