网络函数bind源码分析

static int sock_bind(int fd, struct sockaddr *umyaddr, int addrlen) { struct socket *sock; int i; char address[MAX_SOCK_ADDR]; int err; if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL) return(-EBADF); // 通过文件描述符找到对应的socket,见socket函数源码分析的视图 if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0) return err; if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0) { return(i); } return(0); } 可见bind函数是直接调用底层af_inet.c的inet_bind // 给socket绑定一个地址 static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in *addr=(struct sockaddr_in *)uaddr; struct sock *sk=(struct sock *)sock->data, *sk2; unsigned short snum = 0 /* Stoopid compiler.. this IS ok */; int chk_addr_ret; /* check this error. */ if (sk->state != TCP_CLOSE) return(-EIO); if(addr_len<sizeof(struct sockaddr_in)) return -EINVAL; // raw是链路层,不需要端口 if(sock->type != SOCK_RAW) { // 已经绑定了端口 if (sk->num != 0) return(-EINVAL); snum = ntohs(addr->sin_port); /* * We cant just leave the socket bound wherever it is, it might * be bound to a privileged port. However, since there seems to * be a bug here, we will leave it if the port is not privileged. */ // 端口无效则随机获取一个非root才能使用的端口 if (snum == 0) { snum = get_new_socknum(sk->prot, 0); } // 小于1024的端口需要超级用户权限 if (snum < PROT_SOCK && !suser()) return(-EACCES); } // 判断ip chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr); if (addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR && chk_addr_ret != IS_MULTICAST) return(-EADDRNOTAVAIL); /* Source address MUST be ours! */ if (chk_addr_ret || addr->sin_addr.s_addr == 0) sk->saddr = addr->sin_addr.s_addr; if(sock->type != SOCK_RAW) { /* Make sure we are allowed to bind here. */ cli(); for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)]; sk2 != NULL; sk2 = sk2->next) { /* should be below! */ if (sk2->num != snum) continue; // 端口已经被使用,没有设置可重用标记,比如断开了解后在2msl内是否可以重用 if (!sk->reuse) { sti(); return(-EADDRINUSE); } if (sk2->num != snum) continue; /* more than one */ if (sk2->saddr != sk->saddr) continue; /* socket per slot ! -FB */ // 被监听的端口不能同时被使用 if (!sk2->reuse || sk2->state==TCP_LISTEN) { sti(); return(-EADDRINUSE); } } sti(); // 保证该sk不在sock_array队列里 remove_sock(sk); // 挂载到sock_array里 put_sock(snum, sk); // tcp头中的源端口 sk->dummy_th.source = ntohs(sk->num); sk->daddr = 0; sk->dummy_th.dest = 0; } return(0); } 由代码中可以看到,bind函数主要做的事情是判断一下端口和ip和可用性,然后把sock结构体挂载到协议对应的sock_array哈希列表中。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片