From: Pablo Neira Ayuso <[email protected]>

This patch adds make_sock_stream_connect() which allows to perform
a non-blocking connect to some host and port.

This only support TCP by now, but it could be easily extensible
to support other stream-based layer 4 protocols.
---
 openbsc/include/openbsc/socket.h |    2 +
 openbsc/src/libcommon/socket.c   |   54 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/openbsc/include/openbsc/socket.h b/openbsc/include/openbsc/socket.h
index 87ef37f..af5f729 100644
--- a/openbsc/include/openbsc/socket.h
+++ b/openbsc/include/openbsc/socket.h
@@ -11,4 +11,6 @@ int make_sock(struct bsc_fd *bfd, int proto,
              uint32_t ip, uint16_t port, int priv_nr,
              int (*cb)(struct bsc_fd *fd, unsigned int what), void *data);
 
+int make_sock_stream_connect(struct bsc_fd *bfd, int proto, struct in_addr 
addr, uint16_t port, int priv_nr, int (*cb)(struct bsc_fd *fd, unsigned int 
what), void *data);
+
 #endif /* _BSC_SOCKET_H */
diff --git a/openbsc/src/libcommon/socket.c b/openbsc/src/libcommon/socket.c
index dd25dd7..f4a533d 100644
--- a/openbsc/src/libcommon/socket.c
+++ b/openbsc/src/libcommon/socket.c
@@ -107,3 +107,57 @@ int make_sock(struct bsc_fd *bfd, int proto,
        }
        return 0;
 }
+
+/* this function performs a non-blocking stream connect. */
+int make_sock_stream_connect(struct bsc_fd *bfd, int proto,
+                            struct in_addr addr, uint16_t port, int priv_nr,
+                            int (*cb)(struct bsc_fd *fd, unsigned int what),
+                            void *data)
+{
+       int ret, flags, type;
+       struct sockaddr_in saddr;
+
+       switch (proto) {
+       case IPPROTO_TCP:
+               type = SOCK_STREAM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       bfd->fd = socket(AF_INET, type, proto);
+       bfd->cb = cb;
+       /* non-blocking connect() confirms by setting BSC_FD_READ. */
+       bfd->when = BSC_FD_READ | BSC_FD_WRITE;
+       bfd->data = data;
+       bfd->priv_nr = priv_nr;
+
+       if (bfd->fd < 0) {
+               LOGP(DINP, LOGL_ERROR, "could not create socket.\n");
+               return -EIO;
+       }
+       flags = fcntl(bfd->fd, F_GETFL, 0);
+       if (fcntl(bfd->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
+               LOGP(DINP, LOGL_ERROR, "could not fcntl.\n");
+               return -EIO;
+       }
+       memset(&saddr, 0, sizeof(addr));
+       saddr.sin_family = AF_INET;
+       saddr.sin_port = port;
+       memcpy(&saddr.sin_addr, &addr, sizeof(struct in_addr));
+
+       ret = connect(bfd->fd, (struct sockaddr *) &saddr, sizeof(saddr));
+       if (ret < 0 && errno != EINPROGRESS) {
+               LOGP(DINP, LOGL_ERROR, "could not connect socket %s\n",
+                       strerror(errno));
+               close(bfd->fd);
+               return -EIO;
+       }
+       ret = bsc_register_fd(bfd);
+       if (ret < 0) {
+               perror("register_listen_fd");
+               close(bfd->fd);
+               return ret;
+       }
+       return 0;
+}
-- 
1.7.2.3


Reply via email to