赞
踩
我们回到__sock_create() 函数中继续往下分析,创建了socket以后,代码1150行与1153行在net_families[]数组中检查对应family的协议族操作表有没有安装,回忆下服务器程序创建socket时代码。
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
我们先不关心其他参数,重点注意传递的family参数是AF_INET, 这个值定义为2,这里也就是检查数组net_families[2] 处是否安装了AF_INET协议组操作表,这当然也是被内核初始化安装完成的,该安装是在net/ipv4/af_inet.c 中,采用initcall 机制对inet_init函数进行了安装擦欧总,从而完成AF_INET协议族操作表的注册。
fs_initcall(inet_init)
fs_initcall 是一个宏定义,它的定义在include/linux/init.h中
fs_initcall宏将inet_init安装到了initcall中,因此Linux在初始化时会执行inet_init函数。
static int __init inet_init(void)
(void)sock_register(&inet_family_ops);//安装协议族操作表
代码1426行转入sock_register 中完成注册
inet_init()->sock_register()
int sock_register(const struct net_proto_family *ops)
{
spin_lock(&net_family_lock);
if (net_families[ops->family])
err = - EEXIST;
else {
net_familys[p[s->family] = ops;//将操作表登记到全局数组中
err = 0;
}
}
2122 行把AF_INET协议族的操作表结构inet_family_ops注册到net_families数组中,
这个操作表结构定义在/net/ipv4/af_inet.c中。
static struct net_proto_family inet_family_ops = {
.family = PF_INET,
.create = inet_create,
.owner = THIS_MODULE,
};
928行的family 值PF_INET就是AF_INET。
#define PF_INET AF_INET
结构体net_proto_family的内容比较简单,在此就不列出了。找到了协议族操作表之后,
_sock_create函数1169行处的pf->create(net,sock,protocol)语句就得以执行, 对照inet_family_ops结构的create 钩子函数,挂入的是inet_create()函数,代码比较多,因此分段分析。
sys_socketcall()->sys_socket()->sock_create()->__sock_create()->inet_create()
static int inet_create(struct net *net, struct socket *sock, int protocol)
{
struct sock *sk;
struct list_head *p;
struct inet_protosw *anser;
struct inet_sock *inet;
struct proto *anser_prot;
unsigned char anwer_flags;
char answer_no_check;
int try_loading_module = 0;
int err;
//检查SOCKET类型和加密字符
if (sock->type != SOCK_RAM &&
sock->type != SOCK_DGRAM && !inet_ehash_secret) build_ehash_secret()
sock->state = SS_UNCONNECTED;
answer = NULL;
}
前面在__sock_create() 函数1140行处将服务器程序设置的类型赋值给了新分配的sock,从而将sock设置成了SOCK_STREAM, 即数据流类型。这里首先检查sock的类型,查看是否SOCK_RAW和SOCK_DGRAM 类型的socket,并且判断是否已经有了加密字符,如果没有就会在282行处调用build_ehash_secret()
来设置.
sys_sockcall()->sys_socket->sock_create->sock_create_inet_create
void build _ehash_secret(void)
{
u32 rnd;
do {//获得随机数
get_random_bytes(&rnd, sizeof(rnd));
}while(rnd == 0);
spin_lock_bh(&inetsw_lock);
if (!inet_ehash_secret)
inet_ehash_secret = rnd; //使用随机数作为加密字符
spin_unlock_bh(&inetsw_lock);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。