socket: add OSMO_SOCK_F_[CONNECT|BIND|NON_BLOCK] flags
authorPablo Neira Ayuso <pablo@gnumonks.org>
Thu, 9 Jun 2011 13:04:30 +0000 (15:04 +0200)
committerPablo Neira Ayuso <pablo@gnumonks.org>
Mon, 13 Jun 2011 17:15:59 +0000 (19:15 +0200)
This extends the socket infrastructure in libosmocore to allow
to create non-blocking sockets.

Basically, it replaces the connect0_bind1 parameter by one
flags parameter.

include/osmocom/core/socket.h
src/gsmtap_util.c
src/socket.c

index b2601c7..612b12c 100644 (file)
@@ -5,14 +5,19 @@
 
 struct sockaddr;
 
+/* flags for osmo_sock_init. */
+#define OSMO_SOCK_F_CONNECT    (1 << 0)
+#define OSMO_SOCK_F_BIND       (1 << 1)
+#define OSMO_SOCK_F_NONBLOCK   (1 << 2)
+
 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);
 
 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 osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
-                     uint8_t proto, int connect0_bind1);
+                     uint8_t proto, unsigned int flags);
 
 /* determine if the given address is a local address */
 int osmo_sockaddr_is_local(struct sockaddr *addr, unsigned int addrlen);
index 9545865..c8c26c6 100644 (file)
@@ -124,7 +124,8 @@ int gsmtap_source_init_fd(const char *host, uint16_t port)
        if (host == NULL)
                host = "localhost";
 
-       return osmo_sock_init(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host, port, 0);
+       return osmo_sock_init(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host, port,
+                               OSMO_SOCK_F_CONNECT);
 }
 
 int gsmtap_source_add_sink_fd(int gsmtap_fd)
@@ -138,7 +139,8 @@ int gsmtap_source_add_sink_fd(int gsmtap_fd)
                return rc;
 
        if (osmo_sockaddr_is_local((struct sockaddr *)&ss, ss_len) == 1) {
-               rc = osmo_sock_init_sa((struct sockaddr *)&ss, SOCK_DGRAM, IPPROTO_UDP, 1);
+               rc = osmo_sock_init_sa((struct sockaddr *)&ss, SOCK_DGRAM,
+                                       IPPROTO_UDP, OSMO_SOCK_F_BIND);
                if (rc >= 0)
                        return rc;
        }
index 0be98b9..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,7 +36,7 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
        hints.ai_flags = 0;
        hints.ai_protocol = proto;
 
-       if (connect0_bind1)
+       if (flags & OSMO_SOCK_F_BIND)
                hints.ai_flags |= AI_PASSIVE;
 
        rc = getaddrinfo(host, portbuf, &hints, &result);
@@ -44,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;
                }
@@ -63,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:
@@ -75,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;
 
@@ -96,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;
@@ -127,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,