1/*
2 * Copyright (c) 1999 - 2000 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <config.h>
35
36#include "roken.h"
37#include <err.h>
38
39/*
40 * Set `sa' to the unitialized address of address family `af'
41 */
42
43ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
44socket_set_any (struct sockaddr *sa, int af)
45{
46    switch (af) {
47    case AF_INET : {
48	struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
49
50	memset (sin4, 0, sizeof(*sin4));
51	sin4->sin_family = AF_INET;
52	sin4->sin_port   = 0;
53	sin4->sin_addr.s_addr = INADDR_ANY;
54	break;
55    }
56#ifdef HAVE_IPV6
57    case AF_INET6 : {
58	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
59
60	memset (sin6, 0, sizeof(*sin6));
61	sin6->sin6_family = AF_INET6;
62	sin6->sin6_port   = 0;
63	sin6->sin6_addr   = in6addr_any;
64	break;
65    }
66#endif
67    default :
68	errx (1, "unknown address family %d", sa->sa_family);
69    }
70}
71
72/*
73 * set `sa' to (`ptr', `port')
74 */
75
76ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
77socket_set_address_and_port (struct sockaddr *sa, const void *ptr, int port)
78{
79    switch (sa->sa_family) {
80    case AF_INET : {
81	struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
82
83	memset (sin4, 0, sizeof(*sin4));
84	sin4->sin_family = AF_INET;
85	sin4->sin_port   = port;
86	memcpy (&sin4->sin_addr, ptr, sizeof(struct in_addr));
87	break;
88    }
89#ifdef HAVE_IPV6
90    case AF_INET6 : {
91	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
92
93	memset (sin6, 0, sizeof(*sin6));
94	sin6->sin6_family = AF_INET6;
95	sin6->sin6_port   = port;
96	memcpy (&sin6->sin6_addr, ptr, sizeof(struct in6_addr));
97	break;
98    }
99#endif
100    default :
101	errx (1, "unknown address family %d", sa->sa_family);
102    }
103}
104
105/*
106 * Return the size of an address of the type in `sa'
107 */
108
109ROKEN_LIB_FUNCTION size_t ROKEN_LIB_CALL
110socket_addr_size (const struct sockaddr *sa)
111{
112    switch (sa->sa_family) {
113    case AF_INET :
114	return sizeof(struct in_addr);
115#ifdef HAVE_IPV6
116    case AF_INET6 :
117	return sizeof(struct in6_addr);
118#endif
119    default :
120	return 0;
121    }
122}
123
124/*
125 * Return the size of a `struct sockaddr' in `sa'.
126 */
127
128ROKEN_LIB_FUNCTION socklen_t ROKEN_LIB_CALL
129socket_sockaddr_size (const struct sockaddr *sa)
130{
131    switch (sa->sa_family) {
132    case AF_INET :
133	return sizeof(struct sockaddr_in);
134#ifdef HAVE_IPV6
135    case AF_INET6 :
136	return sizeof(struct sockaddr_in6);
137#endif
138    default:
139	return 0;
140    }
141}
142
143/*
144 * Return the binary address of `sa'.
145 */
146
147ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
148socket_get_address (const struct sockaddr *sa)
149{
150    switch (sa->sa_family) {
151    case AF_INET : {
152	const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
153	return rk_UNCONST(&sin4->sin_addr);
154    }
155#ifdef HAVE_IPV6
156    case AF_INET6 : {
157	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
158	return rk_UNCONST(&sin6->sin6_addr);
159    }
160#endif
161    default:
162	return NULL;
163    }
164}
165
166/*
167 * Return the port number from `sa'.
168 */
169
170ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
171socket_get_port (const struct sockaddr *sa)
172{
173    switch (sa->sa_family) {
174    case AF_INET : {
175	const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
176	return sin4->sin_port;
177    }
178#ifdef HAVE_IPV6
179    case AF_INET6 : {
180	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
181	return sin6->sin6_port;
182    }
183#endif
184    default :
185	return 0;
186    }
187}
188
189/*
190 * Set the port in `sa' to `port'.
191 */
192
193ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
194socket_set_port (struct sockaddr *sa, int port)
195{
196    switch (sa->sa_family) {
197    case AF_INET : {
198	struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
199	sin4->sin_port = port;
200	break;
201    }
202#ifdef HAVE_IPV6
203    case AF_INET6 : {
204	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
205	sin6->sin6_port = port;
206	break;
207    }
208#endif
209    default :
210	errx (1, "unknown address family %d", sa->sa_family);
211    }
212}
213
214/*
215 * Set the range of ports to use when binding with port = 0.
216 */
217ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
218socket_set_portrange (rk_socket_t sock, int restr, int af)
219{
220#if defined(IP_PORTRANGE)
221	if (af == AF_INET) {
222		int on = restr ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
223		setsockopt (sock, IPPROTO_IP, IP_PORTRANGE, &on, sizeof(on));
224	}
225#endif
226#if defined(IPV6_PORTRANGE)
227	if (af == AF_INET6) {
228		int on = restr ? IPV6_PORTRANGE_HIGH : IPV6_PORTRANGE_DEFAULT;
229		setsockopt (sock, IPPROTO_IPV6, IPV6_PORTRANGE, &on, sizeof(on));
230	}
231#endif
232}
233
234/*
235 * Enable debug on `sock'.
236 */
237
238ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
239socket_set_debug (rk_socket_t sock)
240{
241#if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT)
242    int on = 1;
243    setsockopt (sock, SOL_SOCKET, SO_DEBUG, (void *) &on, sizeof (on));
244#endif
245}
246
247/*
248 * Set the type-of-service of `sock' to `tos'.
249 */
250
251ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
252socket_set_tos (rk_socket_t sock, int tos)
253{
254#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
255    setsockopt (sock, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(int));
256#endif
257}
258
259/*
260 * Set the non-blocking-ness of the socket.
261 */
262
263ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
264socket_set_nonblocking(rk_socket_t sock, int nonblock)
265{
266    int flags;
267#if defined(O_NONBLOCK)
268    flags = fcntl(sock, F_GETFL, 0);
269    if (flags == -1)
270	return;
271    if (nonblock)
272	flags |= O_NONBLOCK;
273    else
274	flags &= ~O_NONBLOCK;
275    fcntl(sock, F_SETFL, flags);
276#elif defined(FIOBIO)
277    flags = !!nonblock;
278    return ioctl(sock, FIOBIO, &flags);
279#endif
280}
281
282/*
283 * Set the non-blocking-ness of the socket.
284 */
285
286ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
287socket_set_nopipe(rk_socket_t sock, int nopipe)
288{
289#if defined(SOL_SOCKET) && defined(SO_NOSIGPIPE)
290    setsockopt (sock, SOL_SOCKET, SO_NOSIGPIPE, (void *) &nopipe, sizeof(int));
291#endif
292}
293
294
295
296/*
297 * set the reuse of addresses on `sock' to `val'.
298 */
299
300ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
301socket_set_reuseaddr (rk_socket_t sock, int val)
302{
303#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
304    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(val));
305#endif
306}
307
308/*
309 * Set the that the `sock' should bind to only IPv6 addresses.
310 */
311
312ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
313socket_set_ipv6only (rk_socket_t sock, int val)
314{
315#if defined(IPV6_V6ONLY) && defined(HAVE_SETSOCKOPT)
316    setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val, sizeof(val));
317#endif
318}
319
320/**
321 * Create a file descriptor from a socket
322 *
323 * While the socket handle in \a sock can be used with WinSock
324 * functions after calling socket_to_fd(), it should not be closed
325 * with rk_closesocket().  The socket will be closed when the associated
326 * file descriptor is closed.
327 */
328ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
329socket_to_fd(rk_socket_t sock, int flags)
330{
331#ifndef _WIN32
332    return sock;
333#else
334    return _open_osfhandle((intptr_t) sock, flags);
335#endif
336}
337
338#ifdef HAVE_WINSOCK
339ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
340rk_SOCK_IOCTL(SOCKET s, long cmd, int * argp) {
341    u_long ul = (argp)? *argp : 0;
342    int rv;
343
344    rv = ioctlsocket(s, cmd, &ul);
345    if (argp)
346	*argp = (int) ul;
347    return rv;
348}
349#endif
350
351#ifndef HEIMDAL_SMALLER
352#undef socket
353
354int rk_socket(int, int, int);
355
356int
357rk_socket(int domain, int type, int protocol)
358{
359    int s;
360    s = socket (domain, type, protocol);
361#ifdef SOCK_CLOEXEC
362    if ((SOCK_CLOEXEC & type) && s < 0 && errno == EINVAL) {
363	type &= ~SOCK_CLOEXEC;
364	s = socket (domain, type, protocol);
365    }
366#endif
367    return s;
368}
369
370#endif /* HEIMDAL_SMALLER */
371