etc/services - sync with NetBSD-8
[minix.git] / minix / lib / libc / sys / getsockopt.c
blob7c000fb05a365cd80ce6a2bf8d3a07c420040640
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
5 #include <assert.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/ioctl.h>
10 #include <sys/socket.h>
11 #include <sys/types.h>
12 #include <sys/ucred.h>
13 #include <netinet/tcp.h>
15 #include <net/gen/in.h>
16 #include <net/gen/tcp.h>
17 #include <net/gen/tcp_io.h>
18 #include <net/gen/udp.h>
19 #include <net/gen/udp_io.h>
21 #include <minix/type.h>
23 #define DEBUG 0
25 static int _tcp_getsockopt(int sock, int level, int option_name,
26 void *__restrict option_value, socklen_t *__restrict option_len);
27 static int _udp_getsockopt(int sock, int level, int option_name,
28 void *__restrict option_value, socklen_t *__restrict option_len);
29 static int _uds_getsockopt(int sock, int level, int option_name,
30 void *__restrict option_value, socklen_t *__restrict option_len);
31 static void getsockopt_copy(void *return_value, size_t return_len,
32 void *__restrict option_value, socklen_t *__restrict option_len);
35 * Get socket options.
37 static int
38 __getsockopt(int fd, int level, int option_name,
39 void * __restrict option_value, socklen_t * __restrict option_len)
41 message m;
43 if (option_len == NULL) {
44 errno = EFAULT;
45 return -1;
48 memset(&m, 0, sizeof(m));
49 m.m_lc_vfs_sockopt.fd = fd;
50 m.m_lc_vfs_sockopt.level = level;
51 m.m_lc_vfs_sockopt.name = option_name;
52 m.m_lc_vfs_sockopt.buf = (vir_bytes)option_value;
53 m.m_lc_vfs_sockopt.len = *option_len;
55 if (_syscall(VFS_PROC_NR, VFS_GETSOCKOPT, &m) < 0)
56 return -1;
58 *option_len = m.m_vfs_lc_socklen.len;
59 return 0;
62 int getsockopt(int sock, int level, int option_name,
63 void *__restrict option_value, socklen_t *__restrict option_len)
65 int r;
66 nwio_tcpopt_t tcpopt;
67 nwio_udpopt_t udpopt;
68 struct sockaddr_un uds_addr;
70 r = __getsockopt(sock, level, option_name, option_value, option_len);
71 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
72 return r;
74 r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
75 if (r != -1 || errno != ENOTTY)
77 if (r == -1)
79 /* Bad file descriptor */
80 return -1;
82 return _tcp_getsockopt(sock, level, option_name,
83 option_value, option_len);
86 r= ioctl(sock, NWIOGUDPOPT, &udpopt);
87 if (r != -1 || errno != ENOTTY)
89 if (r == -1)
91 /* Bad file descriptor */
92 return -1;
94 return _udp_getsockopt(sock, level, option_name,
95 option_value, option_len);
98 r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
99 if (r != -1 || errno != ENOTTY)
101 if (r == -1)
103 /* Bad file descriptor */
104 return -1;
106 return _uds_getsockopt(sock, level, option_name,
107 option_value, option_len);
110 errno = ENOTSOCK;
111 return -1;
114 static void getsockopt_copy(void *return_value, size_t return_len,
115 void *__restrict option_value, socklen_t *__restrict option_len)
117 /* copy as much data as possible */
118 if (*option_len < return_len)
119 memcpy(option_value, return_value, *option_len);
120 else
121 memcpy(option_value, return_value, return_len);
123 /* return length */
124 *option_len = return_len;
127 static int _tcp_getsockopt(int sock, int level, int option_name,
128 void *__restrict option_value, socklen_t *__restrict option_len)
130 int i, r, err;
132 if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
134 i = 1; /* Binds to TIME_WAIT sockets never cause errors */
135 getsockopt_copy(&i, sizeof(i), option_value, option_len);
136 return 0;
138 if (level == SOL_SOCKET && option_name == SO_KEEPALIVE)
140 i = 1; /* Keepalive is always on */
141 getsockopt_copy(&i, sizeof(i), option_value, option_len);
142 return 0;
144 if (level == SOL_SOCKET && option_name == SO_ERROR)
146 r = ioctl(sock, NWIOTCPGERROR, &err);
147 if (r != 0)
148 return r;
150 getsockopt_copy(&err, sizeof(err), option_value, option_len);
151 return 0;
153 if (level == SOL_SOCKET && option_name == SO_RCVBUF)
155 i = 32 * 1024; /* Receive buffer in the current
156 * implementation
158 getsockopt_copy(&i, sizeof(i), option_value, option_len);
159 return 0;
161 if (level == SOL_SOCKET && option_name == SO_SNDBUF)
163 i = 32 * 1024; /* Send buffer in the current implementation */
164 getsockopt_copy(&i, sizeof(i), option_value, option_len);
165 return 0;
167 if (level == SOL_SOCKET && option_name == SO_TYPE)
169 i = SOCK_STREAM; /* this is a TCP socket */
170 getsockopt_copy(&i, sizeof(i), option_value, option_len);
171 return 0;
173 if (level == IPPROTO_TCP && option_name == TCP_NODELAY)
175 i = 0; /* nodelay is always off */
176 getsockopt_copy(&i, sizeof(i), option_value, option_len);
177 return 0;
179 #if DEBUG
180 fprintf(stderr, "_tcp_getsocketopt: level %d, name %d\n",
181 level, option_name);
182 #endif
184 errno= ENOPROTOOPT;
185 return -1;
188 static int _udp_getsockopt(int sock, int level, int option_name,
189 void *__restrict option_value, socklen_t *__restrict option_len)
191 int i;
193 if (level == SOL_SOCKET && option_name == SO_TYPE)
195 i = SOCK_DGRAM; /* this is a UDP socket */
196 getsockopt_copy(&i, sizeof(i), option_value, option_len);
197 return 0;
199 #if DEBUG
200 fprintf(stderr, "_udp_getsocketopt: level %d, name %d\n",
201 level, option_name);
202 #endif
204 errno= ENOSYS;
205 return -1;
208 static int _uds_getsockopt(int sock, int level, int option_name,
209 void *__restrict option_value, socklen_t *__restrict option_len)
211 int i, r;
212 size_t size;
214 if (level == SOL_SOCKET && option_name == SO_RCVBUF)
216 r= ioctl(sock, NWIOGUDSRCVBUF, &size);
217 if (r == -1) {
218 return r;
221 getsockopt_copy(&size, sizeof(size), option_value, option_len);
222 return 0;
225 if (level == SOL_SOCKET && option_name == SO_SNDBUF)
227 r= ioctl(sock, NWIOGUDSSNDBUF, &size);
228 if (r == -1) {
229 return r;
232 getsockopt_copy(&size, sizeof(size), option_value, option_len);
233 return 0;
236 if (level == SOL_SOCKET && option_name == SO_TYPE)
238 r= ioctl(sock, NWIOGUDSSOTYPE, &i);
239 if (r == -1) {
240 return r;
243 getsockopt_copy(&i, sizeof(i), option_value, option_len);
244 return 0;
247 #ifdef SO_PEERCRED
248 if (level == SOL_SOCKET && option_name == SO_PEERCRED)
250 struct uucred cred;
252 r= ioctl(sock, NWIOGUDSPEERCRED, &cred);
253 if (r == -1) {
254 return -1;
257 getsockopt_copy(&cred, sizeof(struct uucred), option_value,
258 option_len);
259 return 0;
261 #endif
264 if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
266 i = 1; /* as long as nobody is listen()ing on the address,
267 * it can be reused without waiting for a
268 * timeout to expire.
270 getsockopt_copy(&i, sizeof(i), option_value, option_len);
271 return 0;
274 #ifdef SO_PASSCRED
275 if (level == SOL_SOCKET && option_name == SO_PASSCRED)
277 i = 1; /* option is always 'on' */
278 getsockopt_copy(&i, sizeof(i), option_value, option_len);
279 return 0;
281 #endif
283 #if DEBUG
284 fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n",
285 level, option_name);
286 #endif
288 errno= ENOSYS;
289 return -1;