blob: 7e610bf33488cc77ed4f66fe5d00adee54ff2917 [file] [log] [blame]
Harald Welte468b6432014-09-11 13:05:51 +08001/*
2 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
3 *
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
Harald Welte33cb71a2011-05-21 18:54:32 +020022#include "../config.h"
23
Harald Welteba6988b2011-08-17 12:46:48 +020024/*! \addtogroup socket
25 * @{
26 */
27
28/*! \file socket.c
29 * \brief Osmocom socket convenience functions
30 */
31
Harald Weltee4764422011-05-22 12:25:57 +020032#ifdef HAVE_SYS_SOCKET_H
33
Harald Welte33cb71a2011-05-21 18:54:32 +020034#include <osmocom/core/logging.h>
35#include <osmocom/core/select.h>
36#include <osmocom/core/socket.h>
37
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +020038#include <sys/ioctl.h>
Harald Welte33cb71a2011-05-21 18:54:32 +020039#include <sys/socket.h>
40#include <sys/types.h>
Álvaro Neira Ayuso5ade61a2014-03-24 13:02:00 +010041#include <sys/un.h>
Harald Welte33cb71a2011-05-21 18:54:32 +020042
Holger Hans Peter Freyther47723482011-11-09 11:26:15 +010043#include <netinet/in.h>
44
Harald Welte33cb71a2011-05-21 18:54:32 +020045#include <stdio.h>
46#include <unistd.h>
47#include <stdint.h>
48#include <string.h>
49#include <errno.h>
50#include <netdb.h>
51#include <ifaddrs.h>
52
Harald Welteba6988b2011-08-17 12:46:48 +020053/*! \brief Initialize a socket (including bind/connect)
54 * \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
55 * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
56 * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
57 * \param[in] host remote host name or IP address in string form
58 * \param[in] port remote port number in host byte order
59 * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT
Harald Welte2d2e2cc2016-04-25 12:11:20 +020060 * \returns socket file descriptor on success; negative on error
Harald Welteba6988b2011-08-17 12:46:48 +020061 *
62 * This function creates a new socket of the designated \a family, \a
63 * type and \a proto and optionally binds or connects it, depending on
64 * the value of \a flags parameter.
65 */
Harald Welte33cb71a2011-05-21 18:54:32 +020066int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +020067 const char *host, uint16_t port, unsigned int flags)
Harald Welte33cb71a2011-05-21 18:54:32 +020068{
69 struct addrinfo hints, *result, *rp;
Harald Welte68b15742011-05-22 21:47:29 +020070 int sfd, rc, on = 1;
Harald Welte33cb71a2011-05-21 18:54:32 +020071 char portbuf[16];
72
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +020073 if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) ==
74 (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT))
75 return -EINVAL;
76
Harald Welte33cb71a2011-05-21 18:54:32 +020077 sprintf(portbuf, "%u", port);
78 memset(&hints, 0, sizeof(struct addrinfo));
79 hints.ai_family = family;
Pablo Neira Ayusoe04a14d2013-01-14 00:12:28 +010080 if (type == SOCK_RAW) {
81 /* Workaround for glibc, that returns EAI_SERVICE (-8) if
82 * SOCK_RAW and IPPROTO_GRE is used.
83 */
84 hints.ai_socktype = SOCK_DGRAM;
85 hints.ai_protocol = IPPROTO_UDP;
86 } else {
87 hints.ai_socktype = type;
88 hints.ai_protocol = proto;
89 }
Harald Welte33cb71a2011-05-21 18:54:32 +020090
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +020091 if (flags & OSMO_SOCK_F_BIND)
Harald Weltef9e07462011-05-31 17:47:54 +020092 hints.ai_flags |= AI_PASSIVE;
93
Harald Welte33cb71a2011-05-21 18:54:32 +020094 rc = getaddrinfo(host, portbuf, &hints, &result);
95 if (rc != 0) {
96 perror("getaddrinfo returned NULL");
97 return -EINVAL;
98 }
99
100 for (rp = result; rp != NULL; rp = rp->ai_next) {
Pablo Neira Ayusoe04a14d2013-01-14 00:12:28 +0100101 /* Workaround for glibc again */
102 if (type == SOCK_RAW) {
103 rp->ai_socktype = SOCK_RAW;
104 rp->ai_protocol = proto;
105 }
106
Harald Welte33cb71a2011-05-21 18:54:32 +0200107 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
108 if (sfd == -1)
109 continue;
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200110 if (flags & OSMO_SOCK_F_NONBLOCK) {
111 if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {
112 perror("cannot set this socket unblocking");
113 close(sfd);
114 return -EINVAL;
115 }
116 }
117 if (flags & OSMO_SOCK_F_CONNECT) {
118 rc = connect(sfd, rp->ai_addr, rp->ai_addrlen);
119 if (rc != -1 || (rc == -1 && errno == EINPROGRESS))
Harald Welte33cb71a2011-05-21 18:54:32 +0200120 break;
121 } else {
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200122 rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
123 &on, sizeof(on));
124 if (rc < 0) {
125 perror("cannot setsockopt socket");
126 break;
127 }
Harald Welte33cb71a2011-05-21 18:54:32 +0200128 if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
129 break;
130 }
131 close(sfd);
132 }
133 freeaddrinfo(result);
134
135 if (rp == NULL) {
136 perror("unable to connect/bind socket");
137 return -ENODEV;
138 }
Harald Welte68b15742011-05-22 21:47:29 +0200139
140 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
141
142 /* Make sure to call 'listen' on a bound, connection-oriented sock */
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200143 if (flags & OSMO_SOCK_F_BIND) {
Harald Welte68b15742011-05-22 21:47:29 +0200144 switch (type) {
145 case SOCK_STREAM:
146 case SOCK_SEQPACKET:
147 listen(sfd, 10);
148 break;
149 }
150 }
151 return sfd;
152}
153
Max862ba652014-10-13 14:54:25 +0200154/*! \brief fill \ref osmo_fd for a give sfd
155 * \param[out] ofd file descriptor (will be filled in)
156 * \param[in] sfd socket file descriptor
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200157 * \returns socket fd on success; negative on error
Max862ba652014-10-13 14:54:25 +0200158 *
159 * This function fills the \a ofd structure.
160 */
161static inline int osmo_fd_init_ofd(struct osmo_fd *ofd, int sfd)
162{
163 int rc;
164
165 if (sfd < 0)
166 return sfd;
167
168 ofd->fd = sfd;
169 ofd->when = BSC_FD_READ;
170
171 rc = osmo_fd_register(ofd);
172 if (rc < 0) {
173 close(sfd);
174 return rc;
175 }
176
177 return sfd;
178}
179
Harald Welteba6988b2011-08-17 12:46:48 +0200180/*! \brief Initialize a socket and fill \ref osmo_fd
Katerina Barone-Adesic28c6a02013-02-15 13:27:59 +0100181 * \param[out] ofd file descriptor (will be filled in)
Harald Welteba6988b2011-08-17 12:46:48 +0200182 * \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
183 * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
184 * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
185 * \param[in] host remote host name or IP address in string form
186 * \param[in] port remote port number in host byte order
187 * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200188 * \returns socket fd on success; negative on error
Harald Welteba6988b2011-08-17 12:46:48 +0200189 *
190 * This function creates (and optionall binds/connects) a socket using
191 * \ref osmo_sock_init, but also fills the \a ofd structure.
192 */
Harald Welte68b15742011-05-22 21:47:29 +0200193int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto,
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200194 const char *host, uint16_t port, unsigned int flags)
Harald Welte68b15742011-05-22 21:47:29 +0200195{
Max862ba652014-10-13 14:54:25 +0200196 return osmo_fd_init_ofd(ofd, osmo_sock_init(family, type, proto, host, port, flags));
Harald Welte33cb71a2011-05-21 18:54:32 +0200197}
198
Harald Welteba6988b2011-08-17 12:46:48 +0200199/*! \brief Initialize a socket and fill \ref sockaddr
200 * \param[out] ss socket address (will be filled in)
201 * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
202 * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
203 * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200204 * \returns socket fd on success; negative on error
Harald Welteba6988b2011-08-17 12:46:48 +0200205 *
206 * This function creates (and optionall binds/connects) a socket using
207 * \ref osmo_sock_init, but also fills the \a ss structure.
208 */
Harald Welte33cb71a2011-05-21 18:54:32 +0200209int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200210 uint8_t proto, unsigned int flags)
Harald Welte33cb71a2011-05-21 18:54:32 +0200211{
212 char host[NI_MAXHOST];
213 uint16_t port;
214 struct sockaddr_in *sin;
215 struct sockaddr_in6 *sin6;
216 int s, sa_len;
217
218 /* determine port and host from ss */
219 switch (ss->sa_family) {
220 case AF_INET:
221 sin = (struct sockaddr_in *) ss;
222 sa_len = sizeof(struct sockaddr_in);
223 port = ntohs(sin->sin_port);
224 break;
225 case AF_INET6:
226 sin6 = (struct sockaddr_in6 *) ss;
227 sa_len = sizeof(struct sockaddr_in6);
228 port = ntohs(sin6->sin6_port);
229 break;
230 default:
231 return -EINVAL;
232 }
Harald Welte33cb71a2011-05-21 18:54:32 +0200233
234 s = getnameinfo(ss, sa_len, host, NI_MAXHOST,
235 NULL, 0, NI_NUMERICHOST);
236 if (s != 0) {
237 perror("getnameinfo failed");
238 return s;
239 }
240
Pablo Neira Ayuso0849c9a2011-06-09 15:04:30 +0200241 return osmo_sock_init(ss->sa_family, type, proto, host, port, flags);
Harald Welte33cb71a2011-05-21 18:54:32 +0200242}
243
244static int sockaddr_equal(const struct sockaddr *a,
Harald Weltee4764422011-05-22 12:25:57 +0200245 const struct sockaddr *b, unsigned int len)
Harald Welte33cb71a2011-05-21 18:54:32 +0200246{
247 struct sockaddr_in *sin_a, *sin_b;
248 struct sockaddr_in6 *sin6_a, *sin6_b;
249
250 if (a->sa_family != b->sa_family)
251 return 0;
252
253 switch (a->sa_family) {
254 case AF_INET:
255 sin_a = (struct sockaddr_in *)a;
256 sin_b = (struct sockaddr_in *)b;
257 if (!memcmp(&sin_a->sin_addr, &sin_b->sin_addr,
258 sizeof(struct in_addr)))
259 return 1;
260 break;
261 case AF_INET6:
262 sin6_a = (struct sockaddr_in6 *)a;
263 sin6_b = (struct sockaddr_in6 *)b;
264 if (!memcmp(&sin6_a->sin6_addr, &sin6_b->sin6_addr,
265 sizeof(struct in6_addr)))
266 return 1;
267 break;
268 }
269 return 0;
270}
271
Harald Welteba6988b2011-08-17 12:46:48 +0200272/*! \brief Determine if the given address is a local address
273 * \param[in] addr Socket Address
274 * \param[in] addrlen Length of socket address in bytes
275 * \returns 1 if address is local, 0 otherwise.
276 */
Harald Weltebc32d052012-04-08 11:31:32 +0200277int osmo_sockaddr_is_local(struct sockaddr *addr, unsigned int addrlen)
Harald Welte33cb71a2011-05-21 18:54:32 +0200278{
279 struct ifaddrs *ifaddr, *ifa;
280
281 if (getifaddrs(&ifaddr) == -1) {
282 perror("getifaddrs");
283 return -EIO;
284 }
285
286 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
Harald Welte4d3a7b12011-05-24 21:31:53 +0200287 if (!ifa->ifa_addr)
288 continue;
Harald Welte33cb71a2011-05-21 18:54:32 +0200289 if (sockaddr_equal(ifa->ifa_addr, addr, addrlen))
290 return 1;
291 }
292
293 return 0;
294}
Harald Weltee4764422011-05-22 12:25:57 +0200295
Álvaro Neira Ayuso5ade61a2014-03-24 13:02:00 +0100296/*! \brief Initialize a unix domain socket (including bind/connect)
297 * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
298 * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
299 * \param[in] socket_path path to identify the socket
300 * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200301 * \returns socket fd on success; negative on error
Álvaro Neira Ayuso5ade61a2014-03-24 13:02:00 +0100302 *
303 * This function creates a new unix domain socket, \a
304 * type and \a proto and optionally binds or connects it, depending on
305 * the value of \a flags parameter.
306 */
307int osmo_sock_unix_init(uint16_t type, uint8_t proto,
308 const char *socket_path, unsigned int flags)
309{
310 struct sockaddr_un local;
311 int sfd, rc, on = 1;
312 unsigned int namelen;
313
314 if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) ==
315 (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT))
316 return -EINVAL;
317
318 local.sun_family = AF_UNIX;
319 strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
320 local.sun_path[sizeof(local.sun_path) - 1] = '\0';
321
322#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
323 local.sun_len = strlen(local.sun_path);
324#endif
325#if defined(BSD44SOCKETS) || defined(SUN_LEN)
326 namelen = SUN_LEN(&local);
327#else
328 namelen = strlen(local.sun_path) +
329 offsetof(struct sockaddr_un, sun_path);
330#endif
331
332 sfd = socket(AF_UNIX, type, proto);
333 if (sfd < 0)
334 return -1;
335
336 if (flags & OSMO_SOCK_F_CONNECT) {
337 rc = connect(sfd, (struct sockaddr *)&local, namelen);
338 if (rc < 0)
339 goto err;
340 } else {
341 unlink(local.sun_path);
342 rc = bind(sfd, (struct sockaddr *)&local, namelen);
343 if (rc < 0)
344 goto err;
345 }
346
347 if (flags & OSMO_SOCK_F_NONBLOCK) {
348 if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {
349 perror("cannot set this socket unblocking");
350 close(sfd);
351 return -EINVAL;
352 }
353 }
354
355 if (flags & OSMO_SOCK_F_BIND) {
356 rc = listen(sfd, 10);
357 if (rc < 0)
358 goto err;
359 }
360
361 return sfd;
362err:
363 close(sfd);
364 return -1;
365}
366
367/*! \brief Initialize a unix domain socket and fill \ref osmo_fd
368 * \param[out] ofd file descriptor (will be filled in)
369 * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
370 * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
371 * \param[in] socket_path path to identify the socket
372 * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT
Harald Welte2d2e2cc2016-04-25 12:11:20 +0200373 * \returns socket fd on success; negative on error
Álvaro Neira Ayuso5ade61a2014-03-24 13:02:00 +0100374 *
375 * This function creates (and optionall binds/connects) a socket using
376 * \ref osmo_sock_unix_init, but also fills the \a ofd structure.
377 */
378int osmo_sock_unix_init_ofd(struct osmo_fd *ofd, uint16_t type, uint8_t proto,
379 const char *socket_path, unsigned int flags)
380{
Max862ba652014-10-13 14:54:25 +0200381 return osmo_fd_init_ofd(ofd, osmo_sock_unix_init(type, proto, socket_path, flags));
Álvaro Neira Ayuso5ade61a2014-03-24 13:02:00 +0100382}
383
Harald Weltee4764422011-05-22 12:25:57 +0200384#endif /* HAVE_SYS_SOCKET_H */
Harald Welteba6988b2011-08-17 12:46:48 +0200385
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200386/*! @} */