GSMTAP/socket code: Check for sys/socket.h and conditionally compile
[osmocom-bb.git] / src / socket.c
1 #include "../config.h"
2
3 #ifdef HAVE_SYS_SOCKET_H
4
5 #include <osmocom/core/logging.h>
6 #include <osmocom/core/select.h>
7 #include <osmocom/core/socket.h>
8
9 #include <arpa/inet.h>
10 #include <sys/socket.h>
11 #include <sys/types.h>
12 #include <netinet/in.h>
13
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <netdb.h>
20 #include <ifaddrs.h>
21
22 int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
23                    const char *host, uint16_t port, int connect0_bind1)
24 {
25         struct addrinfo hints, *result, *rp;
26         int sfd, rc;
27         char portbuf[16];
28
29         sprintf(portbuf, "%u", port);
30         memset(&hints, 0, sizeof(struct addrinfo));
31         hints.ai_family = family;
32         hints.ai_socktype = type;
33         hints.ai_flags = 0;
34         hints.ai_protocol = proto;
35
36         rc = getaddrinfo(host, portbuf, &hints, &result);
37         if (rc != 0) {
38                 perror("getaddrinfo returned NULL");
39                 return -EINVAL;
40         }
41
42         for (rp = result; rp != NULL; rp = rp->ai_next) {
43                 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
44                 if (sfd == -1)
45                         continue;
46                 if (connect0_bind1 == 0) {
47                         if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
48                                 break;
49                 } else {
50                         if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
51                                 break;
52                 }
53                 close(sfd);
54         }
55         freeaddrinfo(result);
56
57         if (rp == NULL) {
58                 perror("unable to connect/bind socket");
59                 return -ENODEV;
60         }
61         return sfd;
62 }
63
64 int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
65                       uint8_t proto, int connect0_bind1)
66 {
67         char host[NI_MAXHOST];
68         uint16_t port;
69         struct sockaddr_in *sin;
70         struct sockaddr_in6 *sin6;
71         int s, sa_len;
72
73         /* determine port and host from ss */
74         switch (ss->sa_family) {
75         case AF_INET:
76                 sin = (struct sockaddr_in *) ss;
77                 sa_len = sizeof(struct sockaddr_in);
78                 port = ntohs(sin->sin_port);
79                 break;
80         case AF_INET6:
81                 sin6 = (struct sockaddr_in6 *) ss;
82                 sa_len = sizeof(struct sockaddr_in6);
83                 port = ntohs(sin6->sin6_port);
84                 break;
85         default:
86                 return -EINVAL;
87         }
88         fprintf(stderr, "==> PORT = %u\n", port);
89
90         s = getnameinfo(ss, sa_len, host, NI_MAXHOST,
91                         NULL, 0, NI_NUMERICHOST);
92         if (s != 0) {
93                 perror("getnameinfo failed");
94                 return s;
95         }
96
97         return osmo_sock_init(ss->sa_family, type, proto, host,
98                               port, connect0_bind1);
99 }
100
101 static int sockaddr_equal(const struct sockaddr *a,
102                           const struct sockaddr *b, unsigned int len)
103 {
104         struct sockaddr_in *sin_a, *sin_b;
105         struct sockaddr_in6 *sin6_a, *sin6_b;
106
107         if (a->sa_family != b->sa_family)
108                 return 0;
109
110         switch (a->sa_family) {
111         case AF_INET:
112                 sin_a = (struct sockaddr_in *)a;
113                 sin_b = (struct sockaddr_in *)b;
114                 if (!memcmp(&sin_a->sin_addr, &sin_b->sin_addr,
115                             sizeof(struct in_addr)))
116                         return 1;
117                 break;
118         case AF_INET6:
119                 sin6_a = (struct sockaddr_in6 *)a;
120                 sin6_b = (struct sockaddr_in6 *)b;
121                 if (!memcmp(&sin6_a->sin6_addr, &sin6_b->sin6_addr,
122                             sizeof(struct in6_addr)))
123                         return 1;
124                 break;
125         }
126         return 0;
127 }
128
129 /* determine if the given address is a local address */
130 int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen)
131 {
132         struct ifaddrs *ifaddr, *ifa;
133
134         if (getifaddrs(&ifaddr) == -1) {
135                 perror("getifaddrs");
136                 return -EIO;
137         }
138
139         for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
140                 if (sockaddr_equal(ifa->ifa_addr, addr, addrlen))
141                         return 1;
142         }
143
144         return 0;
145 }
146
147 #endif /* HAVE_SYS_SOCKET_H */