- 论坛徽章:
- 0
|
====
用户程序调用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 |
|