aboutsummaryrefslogtreecommitdiffstats
path: root/src/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/socket.c')
-rw-r--r--src/socket.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..bd4914f
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,143 @@
+#include "../config.h"
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+
+int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
+ const char *host, uint16_t port, int connect0_bind1)
+{
+ struct addrinfo hints, *result, *rp;
+ int sfd, rc;
+ char portbuf[16];
+
+ sprintf(portbuf, "%u", port);
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = family;
+ hints.ai_socktype = type;
+ hints.ai_flags = 0;
+ hints.ai_protocol = proto;
+
+ rc = getaddrinfo(host, portbuf, &hints, &result);
+ if (rc != 0) {
+ perror("getaddrinfo returned NULL");
+ return -EINVAL;
+ }
+
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (sfd == -1)
+ continue;
+ if (connect0_bind1 == 0) {
+ if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+ break;
+ } else {
+ if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+ break;
+ }
+ close(sfd);
+ }
+ freeaddrinfo(result);
+
+ if (rp == NULL) {
+ perror("unable to connect/bind socket");
+ return -ENODEV;
+ }
+ return sfd;
+}
+
+int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
+ uint8_t proto, int connect0_bind1)
+{
+ char host[NI_MAXHOST];
+ uint16_t port;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int s, sa_len;
+
+ /* determine port and host from ss */
+ switch (ss->sa_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *) ss;
+ sa_len = sizeof(struct sockaddr_in);
+ port = ntohs(sin->sin_port);
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ss;
+ sa_len = sizeof(struct sockaddr_in6);
+ port = ntohs(sin6->sin6_port);
+ break;
+ default:
+ return -EINVAL;
+ }
+ fprintf(stderr, "==> PORT = %u\n", port);
+
+ s = getnameinfo(ss, sa_len, host, NI_MAXHOST,
+ NULL, 0, NI_NUMERICHOST);
+ if (s != 0) {
+ perror("getnameinfo failed");
+ return s;
+ }
+
+ return osmo_sock_init(ss->sa_family, type, proto, host,
+ port, connect0_bind1);
+}
+
+static int sockaddr_equal(const struct sockaddr *a,
+ const struct sockaddr *b, socklen_t len)
+{
+ struct sockaddr_in *sin_a, *sin_b;
+ struct sockaddr_in6 *sin6_a, *sin6_b;
+
+ if (a->sa_family != b->sa_family)
+ return 0;
+
+ switch (a->sa_family) {
+ case AF_INET:
+ sin_a = (struct sockaddr_in *)a;
+ sin_b = (struct sockaddr_in *)b;
+ if (!memcmp(&sin_a->sin_addr, &sin_b->sin_addr,
+ sizeof(struct in_addr)))
+ return 1;
+ break;
+ case AF_INET6:
+ sin6_a = (struct sockaddr_in6 *)a;
+ sin6_b = (struct sockaddr_in6 *)b;
+ if (!memcmp(&sin6_a->sin6_addr, &sin6_b->sin6_addr,
+ sizeof(struct in6_addr)))
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+/* determine if the given address is a local address */
+int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen)
+{
+ struct ifaddrs *ifaddr, *ifa;
+
+ if (getifaddrs(&ifaddr) == -1) {
+ perror("getifaddrs");
+ return -EIO;
+ }
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (sockaddr_equal(ifa->ifa_addr, addr, addrlen))
+ return 1;
+ }
+
+ return 0;
+}