现在的位置: 首页 > 综合 > 正文

Linux中socket的构造过程

2013年09月21日 ⁄ 综合 ⁄ 共 8167字 ⁄ 字号 评论关闭

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的强制转换, 不大明白是什么意思?
*/

抱歉!评论已关闭.