Merge commit '620f7ab35034f78f894319e027a151568c331eea'
[osmocom-bb.git] / src / shared / libosmocore / src / socket.c
index 014bbaa..f1fcccd 100644 (file)
@@ -6,6 +6,7 @@
 #include <osmocom/core/select.h>
 #include <osmocom/core/socket.h>
 
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/types.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, 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;
                }
@@ -60,7 +82,7 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
        setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 
        /* Make sure to call 'listen' on a bound, connection-oriented sock */
-       if (connect0_bind1 == 1) {
+       if (flags & OSMO_SOCK_F_BIND) {
                switch (type) {
                case SOCK_STREAM:
                case SOCK_SEQPACKET:
@@ -72,11 +94,11 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
 }
 
 int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto,
-                       const char *host, uint16_t port, int connect0_bind1)
+                       const char *host, uint16_t port, unsigned int flags)
 {
        int sfd, rc;
 
-       sfd = osmo_sock_init(family, type, proto, host, port, connect0_bind1);
+       sfd = osmo_sock_init(family, type, proto, host, port, flags);
        if (sfd < 0)
                return sfd;
 
@@ -93,7 +115,7 @@ int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto,
 }
 
 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;
@@ -124,8 +146,7 @@ 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,