浏览 2127 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-06-24
最后修改:2011-06-24
接上篇《socket地址绑定》
三、根据不同的协议来完成绑定
上面代码中的第3步是根据应用程序在创建socket时传递到内核的协议域及socket类型来决定调用采用哪个方法,具体可以参考创建socket一文,这里不再赘述;下面以AF_IENT及SOCK_STREAM为例来说明绑定的过程; 1、调用链: net/Socket.c:sys_bind()->net/ipv4/Af_inet.c:inet_bind(); 2、inet_bind()逻辑: 1) 地址类型检查 chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); if (!sysctl_ip_nonlocal_bind && !inet->freebind && addr->sin_addr.s_addr != htonl(INADDR_ANY) && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) goto out; inet_addr_type()函数根据设置的ip地址检查其类型: static inline unsigned __inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr) { …… if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) return RTN_BROADCAST; if (ipv4_is_multicast(addr)) return RTN_MULTICAST; …… local_table = fib_get_table(net, RT_TABLE_LOCAL); if (local_table) { ret = RTN_UNICAST; if (!local_table->tb_lookup(local_table, &fl, &res)) { if (!dev || dev == res.fi->fib_dev) ret = res.type; fib_res_put(&res); } } return ret; } 其中: a. ipv4_is_zeronet()用于检查地址的高8位是否为0,即地址是否为0.x.x.x,这类地址称为零网地址,零网地址也属于广播地址; b. ipv4_is_lbcast()用于检查地址是否是广播地址(广播地址有两种,一种是有限广播,即255.255.255.255,它不会被路由但是会发送到物理网段上的所有主机;另一种是直接广播,该类地址的主机字段为255,如192.168.1.255,该广播会路由到192.168.1网段的所有主机上);这里只是检查是否是有限广播地址; c. ipv4_is_multicast()用于检查地址是否是多播地址,即224.x.x.x的D类地址; 当ip地址既不是多播,也不是广播时,需要通过查找路由表来确定地址的类型(关于路由表,后面再叙述); 拿到地址类型后,inet_bind()函数会检查地址是否是单播、多播或广播地址;否则就直接出错并返回; 2) 端口范围检查 snum = ntohs(addr->sin_port); if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) goto out; /* Sockets 0-1023 can't be bound to unless you are superuser */ #define PROT_SOCK 1024 这里检查如果端口小于1024,且具有超级用户权限,否则直接出错并返回; 3) 设置源地址和接收地址 if (sk->sk_state != TCP_CLOSE || inet->num) goto out_release_sock; inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) inet->saddr = 0; /* Use device */ 这里先检查sock的状态,如果不是TCP_CLOSE或端口为0,则出错返回(这里也映射到创建socket时要将sock结构体变量的状态设置为TCP_CLOSE上了); 如果地址类型是多播或广播,则源地址设置为0,而接收地址为设置的ip地址; 4) 检查端口是否被占用 if (sk->sk_prot->get_port(sk, snum)) { inet->saddr = inet->rcv_saddr = 0; err = -EADDRINUSE; goto out_release_sock; } 这里根据创建socket协议族初始化时设置的sk_prot来判断端口是否被占用,如果被占用则直接出错返回;关于端口是否被占用,后面会有专门的一章来描述; 5) 初始化目标地址和端口 inet->sport = htons(inet->num); inet->daddr = 0; inet->dport = 0; 至此,地址绑定就完成了。 总结: 1、 根据文件描述符从进程描述符中取出相应的文件,再得到socket结构; 2、 检查ip地址的类型是否是单播、多播或广播; 3、 检查端口是否被占用; 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |