Linux中socket的構造過程

來源:互聯網
上載者:User

grep -irn "int socket"   path_4_linux_src
 
或者 souceinsight  類似的工具查看
 
看了部分,發現bind  ---> sys_bind 搜尋如下
*
* AUTHOR: anhk
* DATE: 2007-5-23
*
* 這是學習網路部分的筆記, 比較粗糙, 並且把一些引用計數代碼去掉了.
* 還有部分加鎖的代碼
* sys_socketcall[net/socket.c]函數是整個網路的中斷入口函數
*/
 
asmlinkage long sys_socketcall(int call, unsigned long __user *args);
{
        unsigned long a[6];
        /* 從使用者空間得到資訊,該函數是SMP安全的 */
        if (copy_from_user(a, args, nargs[call]))
                return -EFAULT;
 
        switch (call) {
                case SYS_SOCKET:
                        err = sys_socket(a[0], a[1], a[2]);
                        break;
                case SYS_BIND:
                        err = sys_bind(a[0], (struct sockaddr __user *)a[1], a[2]);
                        break;
                case SYS_CONNECT:
                        err = sys_connect(a[0], (struct sockaddr __user *)a[1], a[2]);
                        break;
 
                        ....
        }
}
 
/*
* 然後跟進到sys_socket[net/socket.c]函數, 該函數調用sock_create函數,  
* sock_create函數調用__sock_create函數,  
* __sock_create函數, 產生一個inode, 加入到inode_in_use隊列中, 並把其中的inode的使用者id和
* 組id設成當前進程的使用者id及組id
*
* sock_map_fd函數建立一個struct file *newfile結構, 加入到當前進程的current->files
* 然後尋找當前進程的一個可用的fd描述符,並與該newfile結構進行綁定
* sock->file = newfile
*/
 
asmlinkage long sys_socket(int family, int type, int protocol)
{
        int retval;
        struct socket *sock;
 
        retval = sock_create(family, type, protocol, &sock);
        if (retval < 0)
                goto out;
 
        retval = sock_map_fd(sock);
        if (retval < 0)
                goto out_release;
 
out:
        /* It may be already another descriptor 8) Not kernel problem. */
        return retval;
 
out_release:
        sock_release(sock);
        return retval;
}
 
int sock_create(int family, int type, int protocol, struct socket **res)
{
        return __sock_create(family, type, protocol, res, 0);
}
 
/*
* 下邊看__sock_create函數, 調用sock_alloc()
* sock_alloc負責產生new_inode()
*         inode->i_mode = S_IFSOCK | S_IRWXUGO;
*         inode->i_uid = current->fsuid;
*         inode->i_gid = current->fsgid;
*         list_add(&inode->i_list, &inode_in_use);
*         然後綁定sock及這個inode
*         sock = SOCKET_I(inode);
* 然後根據family在net_families[family]中找到create函數, 在tcp/udp/raw中該函數都是inet_create()
*/
 
static int __sock_create(int family, int type, int protocol,
                         struct socket **res, int kern)
{
        int err;
        struct socket *sock;
        const struct net_proto_family *pf;
 
        /* 檢查type, family是否越界 */
        ....;
 
        /* 產生inode並初始化 */
        sock = sock_alloc();
        if (!sock) {
                if (net_ratelimit())
                        printk(KERN_WARNING "socket: no more sockets/n");
                return -ENFILE;        /* Not exactly a match, but its the
                                   closest posix thing */
        }
 
        sock->type = type;
 
        /*
         * 定義:
         * struct net_proto_family {
         *         int                family;
         *         int                (*create)(struct socket *sock, int protocol);
         *         struct module        *owner;
         * };
         *
         * static const struct net_proto_family *net_families[NPROTO] __read_mostly;
         * 該結構在 int sock_register(const struct net_proto_family *ops)中被初始化
                net_families[ops->family] = ops;
         * 如果在tcp/ip協議中,該sock_register在net/ipv4/af_inet.c:inet_init(void)調用  
         */
 
        /* 得到net_families中相應family的資料結構 */
        /* 這裡 pf->create = inet_create[net/ipv4/af_inet.c] */
        pf = rcu_dereference(net_families[family]);
 
        /*  
         * 不管TCP/UDP/RAW, 這裡的pf->create 在[net/ipv4/af_inet.c]中被初始化為inet_create[net/ipv4/af_inet.c]
         */
        err = pf->create(sock, protocol);
        if (err < 0)
                goto out_module_put;
        *res = sock;
        return 0;
}
 
/*
* 該函數設定sock->state = SS_UNCONNECTED;
*
* 這裡有一個結構[net/ipv4/af_inet.c]
* static struct inet_protosw inetsw_array[] =
* {
*         {
*                .type =       SOCK_STREAM,
*                .protocol =   IPPROTO_TCP,
*                .prot =       &tcp_prot,
*                .ops =        &inet_stream_ops,
*                .capability = -1,
*                .no_check =   0,
*                .flags =      INET_PROTOSW_PERMANENT |
*                        INET_PROTOSW_ICSK,
*        },
*  
*         {
*                 .type =       SOCK_DGRAM,
*                 .protocol =   IPPROTO_UDP,
*                 .prot =       &udp_prot,
*                 .ops =        &inet_dgram_ops,
*                 .capability = -1,
*                 .no_check =   UDP_CSUM_DEFAULT,
*                 .flags =      INET_PROTOSW_PERMANENT,
*         },
*  
*  
*         {
*                 .type =       SOCK_RAW,
*                 .protocol =   IPPROTO_IP,        
*                 .prot =       &raw_prot,
*                 .ops =        &inet_sockraw_ops,
*                 .capability = CAP_NET_RAW,
*                 .no_check =   UDP_CSUM_DEFAULT,
*                 .flags =      INET_PROTOSW_REUSE,
*         }
* };
*
* 根據sock->type找到相應的結構地址, 如
*                 tcp: answer = &inetsw_array[0];
*                 udp: answer = &inetsw_array[1];
*                 answer_prot = answer->prot;
*
* 然後申請一個struct sock *sk結構,  
*         如果是TCP, 該結構加入hash表tcp_hashinfo中, 然後調用 tcp_v4_init_sock[net/ipv4/tcp_ipv4.c],
*         如果是UDP, 沒有類似的hash表,且pf->prot->init = NULL
*         udp_prot->hash = udp_lib_hash[include/net/udp.h]
*
*         static inline void udp_lib_hash(struct sock *sk)
*         {
*                 BUG();
*         }
*         可以說udp_prot->hash什麼都沒做, 我想知道如果udp協議,這個struct sock *sk放到哪裡去了?
*/
static int inet_create(struct socket *sock, int protocol)
{
        struct sock *sk;
        struct list_head *p;
        struct inet_protosw *answer;
        struct inet_sock *inet;
        struct proto *answer_prot;
        unsigned char answer_flags;
        char answer_no_check;
        int try_loading_module = 0;
        int err;
 
        sock->state = SS_UNCONNECTED;
 
        /* Look for the requested type/protocol pair. */
        answer = NULL;
lookup_protocol:
        err = -ESOCKTNOSUPPORT;
        rcu_read_lock();
        /*
         * static struct list_head inetsw[SOCK_MAX];
         */
        /*
         * 根據inetsw找到inetsw_array中的相應協議, 並用answer指向該地址
         * 即:
         *         TCP: answer = &inetsw_array[0]
         *         UDP: answer = &inetsw_array[1]
         * answer_prot = answer->prot, tcp為tcp_prot, udp為udp_prot;
         */
        list_for_each_rcu(p, &inetsw[sock->type]) {
                answer = list_entry(p, struct inet_protosw, list);
                /* Check the non-wild match. */
                if (protocol == answer->protocol) {
                        if (protocol != IPPROTO_IP)
                                break;
                } else {
                        /* Check for the two wild cases. */
                        if (IPPROTO_IP == protocol) {
                                protocol = answer->protocol;
                                break;
                        }
                        if (IPPROTO_IP == answer->protocol)
                                break;
                }
                err = -EPROTONOSUPPORT;
                answer = NULL;
        }
 
        if (unlikely(answer == NULL)) {
                /* 載入模組 */
                ...;
        }
 
        err = -EPERM;
        if (answer->capability > 0 && !capable(answer->capability))
                goto out_rcu_unlock;
 
        /*
         * TCP:answer->ops = inetsw_array[0].ops = &inet_stream_ops,
         * UDP:answer->ops = inetsw_array[1].ops = &inet_dgram_ops,
         */
        sock->ops = answer->ops;
        /*
         * TCP:answer->prot = inetsw_array[0].prot = &tcp_prot
         * UDP:answer->prot = inetsw_array[1].prot = &udp_prot
         */
        answer_prot = answer->prot;
        answer_no_check = answer->no_check;
        answer_flags = answer->flags;
        rcu_read_unlock();
 
        BUG_TRAP(answer_prot->slab != NULL);
 
        err = -ENOBUFS;
        /*
         * 在sk_alloc函數中初始化sk
         *         sk = kmalloc(answer_prot->obj_size, 1);
         *         sk->sk_prot = sk->sk_prot_creator = answer_prot = inetsw_array[].prot;
         */
        sk = sk_alloc(PF_INET, GFP_KERNEL, answer_prot, 1);
        if (sk == NULL)
                goto out;
 
        err = 0;
        sk->sk_no_check = answer_no_check;
        if (INET_PROTOSW_REUSE & answer_flags)
                sk->sk_reuse = 1;
 
        /* 強制轉換, 不知道什麼意思 ^_^ */
        inet = inet_sk(sk);
        inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0;
 
        if (SOCK_RAW == sock->type) {
                inet->num = protocol;
                if (IPPROTO_RAW == protocol)
                        inet->hdrincl = 1;
        }
 
        if (ipv4_config.no_pmtu_disc)
                inet->pmtudisc = IP_PMTUDISC_DONT;
        else
                inet->pmtudisc = IP_PMTUDISC_WANT;
 
        inet->id = 0;
 
        /*
         * sk->sk_socket = sock;
         * sock->sk = sk;
         */
        sock_init_data(sock, sk);
 
        sk->sk_destruct           = inet_sock_destruct;
        sk->sk_family           = PF_INET;
        sk->sk_protocol           = protocol;
        sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
 
        inet->uc_ttl        = -1;
        inet->mc_loop        = 1;
        inet->mc_ttl        = 1;
        inet->mc_index        = 0;
        inet->mc_list        = NULL;
 
        sk_refcnt_debug_inc(sk);
 
        if (inet->num) {
                inet->sport = htons(inet->num);
                /*  
                 * tcp: sk 放到tcp_hashinfo, udp呢?
                 *
                 * tcp_prot->hash = &tcp_v4_hash[net/ipv4/tcp_ipv4.c]
                 */
                sk->sk_prot->hash(sk);
        }
 
        /* udp_prot->init = NULL,所以這裡只有tcp,raw */
        if (sk->sk_prot->init) {
                /*
                 * tcp_prot.init = tcp_v4_init_sock,
                 * raw_prot.init = raw_init
                 */
                err = sk->sk_prot->init(sk);
                if (err)
                        sk_common_release(sk);
        }
out:
        return err;
out_rcu_unlock:
        rcu_read_unlock();
        goto out;
}
 
/*
* 一共申請了 4 個結構
* struct inode -> 放到  inode_in_use 鏈表中
* struct socket *sock:         sock->file  = newfile
*                                 被sock_map_fd處理, 最後放到newfile->ops
* struct file *newfile -> 放到  current->files中
* struct sock *sk:                tcp: tcp_hashinfo.ehash[]
*                                 udp: sk放到哪裡了?
* 還有 一些對struct socket *sock或struct sock *sk的強制轉換, 不大明白是什麼意思?
*/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.