LAPDm: When Rx DATA from L1, L1 does not know the SAPI
[osmocom-bb.git] / src / socket.c
index bd4914f..f1fcccd 100644 (file)
@@ -1,13 +1,14 @@
 #include "../config.h"
 
+#ifdef HAVE_SYS_SOCKET_H
+
 #include <osmocom/core/logging.h>
 #include <osmocom/core/select.h>
 #include <osmocom/core/socket.h>
 
-#include <arpa/inet.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
-#include <netinet/in.h>
 
 #include <stdio.h>
 #include <unistd.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)
+                  const char *host, uint16_t port, unsigned int flags)
 {
        struct addrinfo hints, *result, *rp;
-       int sfd, rc;
+       int sfd, rc, on = 1;
        char portbuf[16];
 
+       if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) ==
+                    (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT))
+               return -EINVAL;
+
        sprintf(portbuf, "%u", port);
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = family;
@@ -31,6 +36,9 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
        hints.ai_flags = 0;
        hints.ai_protocol = proto;
 
+       if (flags & OSMO_SOCK_F_BIND)
+               hints.ai_flags |= AI_PASSIVE;
+
        rc = getaddrinfo(host, portbuf, &hints, &result);
        if (rc != 0) {
                perror("getaddrinfo returned NULL");
@@ -41,10 +49,24 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
                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)
+               if (flags & OSMO_SOCK_F_NONBLOCK) {
+                       if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {
+                               perror("cannot set this socket unblocking");
+                               close(sfd);
+                               return -EINVAL;
+                       }
+               }
+               if (flags & OSMO_SOCK_F_CONNECT) {
+                       rc = connect(sfd, rp->ai_addr, rp->ai_addrlen);
+                       if (rc != -1 || (rc == -1 && errno == EINPROGRESS))
                                break;
                } else {
+                       rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
+                                                       &on, sizeof(on));
+                       if (rc < 0) {
+                               perror("cannot setsockopt socket");
+                               break;
+                       }
                        if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
                                break;
                }
@@ -56,11 +78,44 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
                perror("unable to connect/bind socket");
                return -ENODEV;
        }
+
+       setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+       /* Make sure to call 'listen' on a bound, connection-oriented sock */
+       if (flags & OSMO_SOCK_F_BIND) {
+               switch (type) {
+               case SOCK_STREAM:
+               case SOCK_SEQPACKET:
+                       listen(sfd, 10);
+                       break;
+               }
+       }
+       return sfd;
+}
+
+int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto,
+                       const char *host, uint16_t port, unsigned int flags)
+{
+       int sfd, rc;
+
+       sfd = osmo_sock_init(family, type, proto, host, port, flags);
+       if (sfd < 0)
+               return sfd;
+
+       ofd->fd = sfd;
+       ofd->when = BSC_FD_READ;
+
+       rc = osmo_fd_register(ofd);
+       if (rc < 0) {
+               close(sfd);
+               return rc;
+       }
+
        return sfd;
 }
 
 int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
-                     uint8_t proto, int connect0_bind1)
+                     uint8_t proto, unsigned int flags)
 {
        char host[NI_MAXHOST];
        uint16_t port;
@@ -83,7 +138,6 @@ int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
        default:
                return -EINVAL;
        }
-       fprintf(stderr, "==> PORT = %u\n", port);
 
        s = getnameinfo(ss, sa_len, host, NI_MAXHOST,
                        NULL, 0, NI_NUMERICHOST);
@@ -92,12 +146,11 @@ int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
                return s;
        }
 
-       return osmo_sock_init(ss->sa_family, type, proto, host,
-                             port, connect0_bind1);
+       return osmo_sock_init(ss->sa_family, type, proto, host, port, flags);
 }
 
 static int sockaddr_equal(const struct sockaddr *a,
-                         const struct sockaddr *b, socklen_t len)
+                         const struct sockaddr *b, unsigned int len)
 {
        struct sockaddr_in *sin_a, *sin_b;
        struct sockaddr_in6 *sin6_a, *sin6_b;
@@ -135,9 +188,13 @@ int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen)
        }
 
        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+               if (!ifa->ifa_addr)
+                       continue;
                if (sockaddr_equal(ifa->ifa_addr, addr, addrlen))
                        return 1;
        }
 
        return 0;
 }
+
+#endif /* HAVE_SYS_SOCKET_H */