From: Pablo Neira Ayuso pablo@gnumonks.org
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 | 11 ++++++++--- src/gsmtap_util.c | 6 ++++-- src/socket.c | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 15 deletions(-)
diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h index b2601c7..612b12c 100644 --- a/include/osmocom/core/socket.h +++ b/include/osmocom/core/socket.h @@ -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); diff --git a/src/gsmtap_util.c b/src/gsmtap_util.c index eddde04..47fa37d 100644 --- a/src/gsmtap_util.c +++ b/src/gsmtap_util.c @@ -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; } diff --git a/src/socket.c b/src/socket.c index 0be98b9..f1fcccd 100644 --- a/src/socket.c +++ b/src/socket.c @@ -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>
@@ -18,12 +19,16 @@ #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,
hi pablo,
the patch looks fine to me, feel free to commit it to master (I'm on ahort holidays until tuesday).
Please make sure to fix all callers at least in openbsc, osmoxom-bb, insideclibosmocore (gsmtap) and osmo-tetra. I don't fully recall which code uses the function and which not.
Regards, Harald -- Sent from a mobile device, excuse my short response
On 13/06/11 08:23, Harald Welte wrote:
hi pablo,
the patch looks fine to me, feel free to commit it to master (I'm on ahort holidays until tuesday).
Please make sure to fix all callers at least in openbsc, osmoxom-bb, insideclibosmocore (gsmtap) and osmo-tetra. I don't fully recall which code uses the function and which not.
grep shows no clients of these functions outside libosmocore yet, so it's the moment to change the API :-).
I'm going to push the patch.