xref: /minix/minix/lib/libc/sys/getpeername.c (revision 03de4d97)
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
4 
5 #include <errno.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <sys/ioctl.h>
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 
12 #include <net/gen/in.h>
13 #include <net/gen/tcp.h>
14 #include <net/gen/tcp_io.h>
15 #include <net/gen/udp.h>
16 #include <net/gen/udp_io.h>
17 #include <sys/un.h>
18 
19 static int _tcp_getpeername(int sock, struct sockaddr *__restrict address,
20 	socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp);
21 
22 static int _udp_getpeername(int sock, struct sockaddr *__restrict address,
23 	socklen_t *__restrict address_len, nwio_udpopt_t *tcpconfp);
24 
25 static int _uds_getpeername(int sock, struct sockaddr *__restrict address,
26 	socklen_t *__restrict address_len, struct sockaddr_un *uds_addr);
27 
28 /*
29  * Get the remote address of a socket.
30  */
31 static int
32 __getpeername(int fd, struct sockaddr * __restrict address,
33 	socklen_t * __restrict address_len)
34 {
35 	message m;
36 
37 	if (address_len == NULL) {
38 		errno = EFAULT;
39 		return -1;
40 	}
41 
42 	memset(&m, 0, sizeof(m));
43 	m.m_lc_vfs_sockaddr.fd = fd;
44 	m.m_lc_vfs_sockaddr.addr = (vir_bytes)address;
45 	m.m_lc_vfs_sockaddr.addr_len = *address_len;
46 
47 	if (_syscall(VFS_PROC_NR, VFS_GETPEERNAME, &m) < 0)
48 		return -1;
49 
50 	*address_len = m.m_vfs_lc_socklen.len;
51 	return 0;
52 }
53 
54 int getpeername(int sock, struct sockaddr *__restrict address,
55 	socklen_t *__restrict address_len)
56 {
57 	int r;
58 	nwio_tcpconf_t tcpconf;
59 	nwio_udpopt_t udpopt;
60 	struct sockaddr_un uds_addr;
61 
62 	r = __getpeername(sock, address, address_len);
63 	if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
64 		return r;
65 
66 	r= ioctl(sock, NWIOGTCPCONF, &tcpconf);
67 	if (r != -1 || errno != ENOTTY)
68 	{
69 		if (r == -1)
70 		{
71 			/* Bad file descriptor */
72 			return -1;
73 		}
74 		return _tcp_getpeername(sock, address, address_len,
75 			&tcpconf);
76 	}
77 
78 	r= ioctl(sock, NWIOGUDPOPT, &udpopt);
79 	if (r != -1 || errno != ENOTTY)
80 	{
81 		if (r == -1)
82 		{
83 			/* Bad file descriptor */
84 			return -1;
85 		}
86 		return _udp_getpeername(sock, address, address_len,
87 			&udpopt);
88 	}
89 
90 	r= ioctl(sock, NWIOGUDSPADDR, &uds_addr);
91 	if (r != -1 || errno != ENOTTY)
92 	{
93 		if (r == -1)
94 		{
95 			/* Bad file descriptor */
96 			return -1;
97 		}
98 		return _uds_getpeername(sock, address, address_len,
99 			&uds_addr);
100 	}
101 
102 	errno = ENOTSOCK;
103 	return -1;
104 }
105 
106 static int _tcp_getpeername(int sock, struct sockaddr *__restrict address,
107 	socklen_t *__restrict address_len, nwio_tcpconf_t *tcpconfp)
108 {
109 	socklen_t len;
110 	struct sockaddr_in sin;
111 
112 	if (tcpconfp->nwtc_remaddr == 0 ||
113 		tcpconfp->nwtc_remport == 0)
114 	{
115 		errno= ENOTCONN;
116 		return -1;
117 	}
118 
119 	memset(&sin, '\0', sizeof(sin));
120 	sin.sin_family= AF_INET;
121 	sin.sin_addr.s_addr= tcpconfp->nwtc_remaddr;
122 	sin.sin_port= tcpconfp->nwtc_remport;
123 	sin.sin_len = sizeof(sin);
124 
125 	len= *address_len;
126 	if (len > sizeof(sin))
127 		len= sizeof(sin);
128 	memcpy(address, &sin, len);
129 	*address_len= len;
130 
131 	return 0;
132 }
133 
134 static int _udp_getpeername(int sock, struct sockaddr *__restrict address,
135 	socklen_t *__restrict address_len, nwio_udpopt_t *udpopt)
136 {
137 	socklen_t len;
138 	struct sockaddr_in sin;
139 
140 	if (udpopt->nwuo_remaddr == 0 ||
141 		udpopt->nwuo_remport == 0)
142 	{
143 		errno= ENOTCONN;
144 		return -1;
145 	}
146 
147 	memset(&sin, '\0', sizeof(sin));
148 	sin.sin_family= AF_INET;
149 	sin.sin_addr.s_addr= udpopt->nwuo_remaddr;
150 	sin.sin_port= udpopt->nwuo_remport;
151 	sin.sin_len = sizeof(sin);
152 
153 	len= *address_len;
154 	if (len > sizeof(sin))
155 		len= sizeof(sin);
156 	memcpy(address, &sin, len);
157 	*address_len= len;
158 
159 	return 0;
160 }
161 
162 static int _uds_getpeername(int sock, struct sockaddr *__restrict address,
163 	socklen_t *__restrict address_len, struct sockaddr_un *uds_addr)
164 {
165 	socklen_t len;
166 
167 	if (uds_addr->sun_family != AF_UNIX)
168 	{
169 		errno= ENOTCONN;
170 		return -1;
171 	}
172 
173 	len= *address_len;
174 	if (len > sizeof(struct sockaddr_un))
175 		len = sizeof(struct sockaddr_un);
176 
177 	memcpy(address, uds_addr, len);
178 	*address_len= len;
179 
180 	return 0;
181 }
182