套接字之 getsockname && getpeername

getsockname-获取本地地址;比如,在绑定的时候设置端口号为0由系统自动选择端口绑定,或者使用了INADDR_ANY通配所有地址的情况下,后面需要用到具体的地址和端口,就可以用getsockname获取地址信息;

getpeername-获取建立连接的对端的地址和端口;

下面为源码分析:

 1 /*
 2  *    Get the local address ('name') of a socket object. Move the obtained
 3  *    name to user space.
 4  */
 5 
 6 SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
 7         int __user *, usockaddr_len)
 8 {
 9     struct socket *sock;
10     struct sockaddr_storage address;
11     int len, err, fput_needed;
12 
13     /* 查找socket */
14     sock = sockfd_lookup_light(fd, &err, &fput_needed);
15     if (!sock)
16         goto out;
17 
18     err = security_socket_getsockname(sock);
19     if (err)
20         goto out_put;
21 
22     /* 调用socket操作的getname函数 */
23     err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0);
24     if (err)
25         goto out_put;
26 
27     /* 拷贝地址到用户空间 */
28     err = move_addr_to_user(&address, len, usockaddr, usockaddr_len);
29 
30 out_put:
31     fput_light(sock->file, fput_needed);
32 out:
33     return err;
34 }

 

 1 /*
 2  *    Get the remote address ('name') of a socket object. Move the obtained
 3  *    name to user space.
 4  */
 5 
 6 SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
 7         int __user *, usockaddr_len)
 8 {
 9     struct socket *sock;
10     struct sockaddr_storage address;
11     int len, err, fput_needed;
12 
13     /* 查找socket */
14     sock = sockfd_lookup_light(fd, &err, &fput_needed);
15     if (sock != NULL) {
16         err = security_socket_getpeername(sock);
17         if (err) {
18             fput_light(sock->file, fput_needed);
19             return err;
20         }
21 
22         /* 调用socket操作的getname获取对端地址,此时最后一个参数为1 */
23         err =
24             sock->ops->getname(sock, (struct sockaddr *)&address, &len,
25                        1);
26 
27         /* 将地址拷贝到用户空间 */
28         if (!err)
29             err = move_addr_to_user(&address, len, usockaddr,
30                         usockaddr_len);
31         fput_light(sock->file, fput_needed);
32     }
33     return err;
34 }

 

ipv4情况下,getsockname和getpeername都会调用下面的inet_getname函数;

 1 /*
 2  *    This does both peername and sockname.
 3  */
 4 int inet_getname(struct socket *sock, struct sockaddr *uaddr,
 5             int *uaddr_len, int peer)
 6 {
 7     struct sock *sk        = sock->sk;
 8     struct inet_sock *inet    = inet_sk(sk);
 9     DECLARE_SOCKADDR(struct sockaddr_in *, sin, uaddr);
10 
11     /* 设置地址族 */
12     sin->sin_family = AF_INET;
13 
14     /* 获取对端地址 */
15     if (peer) {
16         /* 目的端口为空或者为未连接状态 */
17         if (!inet->inet_dport ||
18             (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
19              peer == 1))
20             return -ENOTCONN;
21         /* 设置目的端口和地址 */
22         sin->sin_port = inet->inet_dport;
23         sin->sin_addr.s_addr = inet->inet_daddr;
24     }
25     /* 获取本地地址 */
26     else {
27         /* 获取接收时ip */
28         __be32 addr = inet->inet_rcv_saddr;
29 
30         /* 不存在则获取发送时ip */
31         if (!addr)
32             addr = inet->inet_saddr;
33 
34         /* 设置端口和地址 */
35         sin->sin_port = inet->inet_sport;
36         sin->sin_addr.s_addr = addr;
37     }
38 
39     /* 填充部分 */
40     memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
41 
42     /* 设置地址长度 */
43     *uaddr_len = sizeof(*sin);
44     return 0;
45 }

 

posted @ 2019-10-27 22:04  AlexAlex  阅读(1135)  评论(0编辑  收藏  举报