免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 974 | 回复: 0
打印 上一主题 下一主题

bind()系统调用 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-05 23:18 |只看该作者 |倒序浏览

====
用户程序调用bind()系统调用,将会执行内核中的sys_bind()函数:
   1213 /*
   1214  *  Bind a name to a socket. Nothing much to do here since it's
   1215  *  the protocol's responsibility to handle the local address.
   1216  *
   1217  *  We move the socket address to kernel space before we call
   1218  *  the protocol layer (having also checked the address is ok).
   1219  */
   1220
   1221 asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
   1222 {
   1223     struct socket *sock;
   1224     char address[MAX_SOCK_ADDR];
   1225     int err;
   1226
先查找fd对应的sock
   1227     if((sock = sockfd_lookup(fd,&err))!=NULL)
   1228     {
把用户地址umyaddr转换为内核地址address
   1229         if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
安全性检查,如果失败,释放sock,返回
   1230             err = security_socket_bind(sock, (struct sockaddr *)address, addrlen);
   1231             if (err) {
   1232                 sockfd_put(sock);
   1233                 return err;
   1234             }
如果是TCP,调用inet_bind(),其他协议则调用相应协议的函数
   1235             err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen);
   1236         }
   1237         sockfd_put(sock);
   1238     }           
   1239     return err;
   1240 }
====
inet_bind()函数如下,实现在net/ipv4/af_inet.c文件中
    586 /* It is off by default, see below. */
    587 int sysctl_ip_nonlocal_bind;
    588
    589 int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
    590 {
    591     struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
    592     struct sock *sk = sock->sk;
    593     struct inet_opt *inet = inet_sk(sk);
    594     unsigned short snum;
    595     int chk_addr_ret;
    596     int err;
    597
下面这段程序由于有注释,很容易理解。
如果我们增加自己的bind()函数,是否可以通过sk->sk_prot->bind()?
    598     /* If the socket has its own bind function then use it. (RAW) */
    599     if (sk->sk_prot->bind) {
    600         err = sk->sk_prot->bind(sk, uaddr, addr_len);
    601         goto out;
    602     }
    603     err = -EINVAL;
    604     if (addr_len sin_addr.s_addr是u32类型,表示一个IP地址,是网络序。
inet_addr_type()函数返回这个ip地址的类型,比如是广播地址,还是组播地址?
    607     chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
    608
如果bind的不是本地的地址,则goto out
    609     /* Not specified by any standard per-se, however it breaks too
    610      * many applications when removed.  It is unfortunate since
    611      * allowing applications to make a non-local bind solves
    612      * several problems with systems using dynamic addressing.
    613      * (ie. your servers still start up even if your ISDN link
    614      *  is temporarily down)
    615      */
    616     err = -EADDRNOTAVAIL;
    617     if (!sysctl_ip_nonlocal_bind &&
    618         !inet->freebind &&
    619         addr->sin_addr.s_addr != INADDR_ANY &&
    620         chk_addr_ret != RTN_LOCAL &&
    621         chk_addr_ret != RTN_MULTICAST &&
    622         chk_addr_ret != RTN_BROADCAST)
    623         goto out;
    624
snum代表了端口号,主机序
    625     snum = ntohs(addr->sin_port);
    626     err = -EACCES;
如果snum是小于1024的端口,还要检查权限
    627     if (snum && snum sk_state != TCP_CLOSE || inet->num)
    642         goto out_release_sock;
    643
rcv_saddr,saddr原来都是一样的,都表示源ip地址
    644     inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr;
如果是广博或者组播,inet->saddr = 0
    645     if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
    646         inet->saddr = 0;  /* Use device */
    647
如果get_port()返回0,则表示ip和端口已经绑定好了,否则表示绑定失败
如果是TCPv4, sk->sk_prot->get_port()函数就是tcp_v4_get_port()
tcp_v4_get_port()太负责,以后再继续吧
    648     /* Make sure we are allowed to bind here. */
    649     if (sk->sk_prot->get_port(sk, snum)) {
    650         inet->saddr = inet->rcv_saddr = 0;
    651         err = -EADDRINUSE;
    652         goto out_release_sock;
    653     }
    654
剩下的都不重要了
    655     if (inet->rcv_saddr)
    656         sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
    657     if (snum)
    658         sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
    659     inet->sport = htons(inet->num);
    660     inet->daddr = 0;
    661     inet->dport = 0;
    662     sk_dst_reset(sk);
    663     err = 0;
    664 out_release_sock:
    665     release_sock(sk);
    666 out:
    667     return err;
    668 }
=================
    231 /* Obtain a reference to a local port for the given sock,
    232  * if snum is zero it means select any available local port.
    233  */
    234 static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
    235 {              
    236     struct tcp_bind_hashbucket *head;
    237     struct hlist_node *node;
    238     struct tcp_bind_bucket *tb;
    239     int ret;
    240     
    241     local_bh_disable();
    242     if (!snum) {
    243         int low = sysctl_local_port_range[0];
    244         int high = sysctl_local_port_range[1];
    245         int remaining = (high - low) + 1;
    246         int rover;
    247
    248         spin_lock(&tcp_portalloc_lock);
    249         rover = tcp_port_rover;
    250         do {
    251             rover++;
    252             if (rover  high)
    253                 rover = low;
    254             head = &tcp_bhash[tcp_bhashfn(rover)];
    255             spin_lock(&head->lock);
    256             tb_for_each(tb, node, &head->chain)
    257                 if (tb->port == rover)
    258                     goto next;
    259             break;
    260         next:
    261             spin_unlock(&head->lock);
    262         } while (--remaining > 0);
    263         tcp_port_rover = rover;
    264         spin_unlock(&tcp_portalloc_lock);
    265
    266         /* Exhausted local port range during search? */
    267         ret = 1;
    268         if (remaining lock);
    278         tb_for_each(tb, node, &head->chain)
    279             if (tb->port == snum)
    280                 goto tb_found;
    281     }
    282     tb = NULL;
    283     goto tb_not_found;
    284 tb_found:
    285     if (!hlist_empty(&tb->owners)) {
    286         if (sk->sk_reuse > 1)
    287             goto success;
    288         if (tb->fastreuse > 0 &&
    289             sk->sk_reuse && sk->sk_state != TCP_LISTEN) {
    290             goto success;
    291         } else {
    292             ret = 1;
    293             if (tcp_bind_conflict(sk, tb))
    294                 goto fail_unlock;
    295         }
    296     }
    297 tb_not_found:
    298     ret = 1;
    299     if (!tb && (tb = tcp_bucket_create(head, snum)) == NULL)
    300         goto fail_unlock;
    301     if (hlist_empty(&tb->owners)) {
    302         if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
    303             tb->fastreuse = 1;
    304         else
    305             tb->fastreuse = 0;
    306     } else if (tb->fastreuse &&
    307            (!sk->sk_reuse || sk->sk_state == TCP_LISTEN))
    308         tb->fastreuse = 0;
    309 success:
    310     if (!tcp_sk(sk)->bind_hash)
    311         tcp_bind_hash(sk, tb, snum);
    312     BUG_TRAP(tcp_sk(sk)->bind_hash == tb);
    313     ret = 0;
    314
    315 fail_unlock:
    316     spin_unlock(&head->lock);
    317 fail:
    318     local_bh_enable();
    319     return ret;
    320 }
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/1938/showart_123778.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP