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
__getpeername(int fd,struct sockaddr * __restrict address,socklen_t * __restrict address_len)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
getpeername(int sock,struct sockaddr * __restrict address,socklen_t * __restrict address_len)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
_tcp_getpeername(int sock,struct sockaddr * __restrict address,socklen_t * __restrict address_len,nwio_tcpconf_t * tcpconfp)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
_udp_getpeername(int sock,struct sockaddr * __restrict address,socklen_t * __restrict address_len,nwio_udpopt_t * udpopt)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
_uds_getpeername(int sock,struct sockaddr * __restrict address,socklen_t * __restrict address_len,struct sockaddr_un * uds_addr)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