aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/bsc_msc.c
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-03-26 10:41:20 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-03-26 10:41:20 +0100
commit1a3d9dbabf94f0138b5eee1f5bde8d9fe8a4bf96 (patch)
tree9a3d18167baf4efb6f29390d07d42f838f6eabd0 /openbsc/src/bsc_msc.c
parenta91d15df7e1dd12b08e85910a51582ac257ce3e7 (diff)
bsc_msc: Connect in a non blocking way to the MSC
The latency of setting up of the TCP connection can be quite high, it is better to connect in a non blocking way. This code is working by setting the socket nonblocking and temporarily replacing the bfd callback with the connect handling. Once the OS has connected our socket we switch back to normal operation.
Diffstat (limited to 'openbsc/src/bsc_msc.c')
-rw-r--r--openbsc/src/bsc_msc.c83
1 files changed, 81 insertions, 2 deletions
diff --git a/openbsc/src/bsc_msc.c b/openbsc/src/bsc_msc.c
index a825fb9aa..9df4696a6 100644
--- a/openbsc/src/bsc_msc.c
+++ b/openbsc/src/bsc_msc.c
@@ -21,13 +21,82 @@
*/
#include <openbsc/bsc_msc.h>
+#include <openbsc/debug.h>
+
+#include <osmocore/write_queue.h>
#include <arpa/inet.h>
#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+/* called in the case of a non blocking connect */
+static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
+{
+ int rc;
+ int val;
+ struct write_queue *queue;
+
+ socklen_t len = sizeof(val);
+
+ if ((what & BSC_FD_WRITE) == 0) {
+ LOGP(DMSC, LOGL_ERROR, "Callback but not readable.\n");
+ return -1;
+ }
+
+ /* check the socket state */
+ rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
+ if (rc != 0) {
+ LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
+ goto error;
+ }
+ if (val != 0) {
+ LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC.\n");
+ goto error;
+ }
+
+
+ /* go to full operation */
+ queue = container_of(fd, struct write_queue, bfd);
+ fd->cb = write_queue_bfd_cb;
+ fd->when = BSC_FD_READ;
+ if (!llist_empty(&queue->msg_queue))
+ fd->when |= BSC_FD_WRITE;
+ return 0;
+
+error:
+ bsc_unregister_fd(fd);
+ close(fd->fd);
+ fd->fd = -1;
+ fd->cb = write_queue_bfd_cb;
+ fd->when = 0;
+ return -1;
+}
+static void setnonblocking(struct bsc_fd *fd)
+{
+ int flags;
+
+ flags = fcntl(fd->fd, F_GETFL);
+ if (flags < 0) {
+ perror("fcntl get failed");
+ close(fd->fd);
+ fd->fd = -1;
+ return;
+ }
+
+ flags |= O_NONBLOCK;
+ flags = fcntl(fd->fd, F_SETFL, flags);
+ if (flags < 0) {
+ perror("fcntl get failed");
+ close(fd->fd);
+ fd->fd = -1;
+ return;
+ }
+}
+
int connect_to_msc(struct bsc_fd *fd, const char *ip, int port)
{
struct sockaddr_in sin;
@@ -36,7 +105,6 @@ int connect_to_msc(struct bsc_fd *fd, const char *ip, int port)
printf("Attempting to connect MSC at %s:%d\n", ip, port);
fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- fd->when = BSC_FD_READ;
fd->data = NULL;
fd->priv_nr = 1;
@@ -45,6 +113,8 @@ int connect_to_msc(struct bsc_fd *fd, const char *ip, int port)
return fd->fd;
}
+ /* make it non blocking */
+ setnonblocking(fd);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
@@ -54,9 +124,18 @@ int connect_to_msc(struct bsc_fd *fd, const char *ip, int port)
setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
- if (ret < 0) {
+ if (ret == -1 && errno == EINPROGRESS) {
+ LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
+ fd->when = BSC_FD_WRITE;
+ fd->cb = msc_connection_connect;
+ } else if (ret < 0) {
perror("Connection failed");
+ close(fd->fd);
+ fd->fd = -1;
return ret;
+ } else {
+ fd->when = BSC_FD_READ;
+ fd->cb = write_queue_bfd_cb;
}
ret = bsc_register_fd(fd);