From 135a45c833d48e7ddcae973ac1d772ad277a56c1 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 26 Mar 2010 12:14:37 +0100 Subject: msc: Create a real interface for BSC MSC and start handling reconnects Create a BSC<->MSC interface and use it for the BSC MSC IP and the BSC NAT to reduce code duplication on handling reconnects to the MSC and cleaning up the local state. The code is only partially tested and will contain bugs. Currently both the BSC and the NAT will just exit on connection loss and this way have the current behavior. --- openbsc/include/openbsc/bsc_msc.h | 20 ++++++++- openbsc/src/bsc_msc.c | 87 +++++++++++++++++++++++++++++++++------ openbsc/src/bsc_msc_ip.c | 43 +++++++++++++------ openbsc/src/nat/bsc_nat.c | 29 ++++++++----- 4 files changed, 140 insertions(+), 39 deletions(-) diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h index 49fe68cdc..29ce065d1 100644 --- a/openbsc/include/openbsc/bsc_msc.h +++ b/openbsc/include/openbsc/bsc_msc.h @@ -23,8 +23,24 @@ #ifndef BSC_MSC_H #define BSC_MSC_H -#include +#include +#include -int connect_to_msc(struct bsc_fd *fd, const char *ip, int port); +struct bsc_msc_connection { + struct write_queue write_queue; + int is_connected; + const char *ip; + int port; + + void (*connection_loss) (struct bsc_msc_connection *); + void (*connected) (struct bsc_msc_connection *); + struct timer_list reconnect_timer; +}; + +struct bsc_msc_connection *bsc_msc_create(const char *ip, int port); +int bsc_msc_connect(struct bsc_msc_connection *); +void bsc_msc_schedule_connect(struct bsc_msc_connection *); + +void bsc_msc_lost(struct bsc_msc_connection *); #endif diff --git a/openbsc/src/bsc_msc.c b/openbsc/src/bsc_msc.c index 9df4696a6..5682767b8 100644 --- a/openbsc/src/bsc_msc.c +++ b/openbsc/src/bsc_msc.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -33,11 +34,27 @@ #include #include +static void connection_loss(struct bsc_msc_connection *con) +{ + struct bsc_fd *fd; + + fd = &con->write_queue.bfd; + + close(fd->fd); + fd->fd = -1; + fd->cb = write_queue_bfd_cb; + fd->when = 0; + + con->is_connected = 0; + con->connection_loss(con); +} + /* 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 bsc_msc_connection *con; struct write_queue *queue; socklen_t len = sizeof(val); @@ -47,6 +64,9 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what) return -1; } + queue = container_of(fd, struct write_queue, bfd); + con = container_of(queue, struct bsc_msc_connection, write_queue); + /* check the socket state */ rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len); if (rc != 0) { @@ -60,19 +80,17 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what) /* 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; + + con->is_connected = 1; + if (con->connected) + con->connected(con); return 0; error: bsc_unregister_fd(fd); - close(fd->fd); - fd->fd = -1; - fd->cb = write_queue_bfd_cb; - fd->when = 0; + connection_loss(con); return -1; } static void setnonblocking(struct bsc_fd *fd) @@ -97,13 +115,17 @@ static void setnonblocking(struct bsc_fd *fd) } } -int connect_to_msc(struct bsc_fd *fd, const char *ip, int port) +int bsc_msc_connect(struct bsc_msc_connection *con) { + struct bsc_fd *fd; struct sockaddr_in sin; int on = 1, ret; - printf("Attempting to connect MSC at %s:%d\n", ip, port); + LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n", con->ip, con->port); + con->is_connected = 0; + + fd = &con->write_queue.bfd; fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); fd->data = NULL; fd->priv_nr = 1; @@ -118,8 +140,8 @@ int connect_to_msc(struct bsc_fd *fd, const char *ip, int port) memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; - sin.sin_port = htons(port); - inet_aton(ip, &sin.sin_addr); + sin.sin_port = htons(con->port); + inet_aton(con->ip, &sin.sin_addr); setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin)); @@ -130,12 +152,14 @@ int connect_to_msc(struct bsc_fd *fd, const char *ip, int port) fd->cb = msc_connection_connect; } else if (ret < 0) { perror("Connection failed"); - close(fd->fd); - fd->fd = -1; + connection_loss(con); return ret; } else { fd->when = BSC_FD_READ; fd->cb = write_queue_bfd_cb; + con->is_connected = 1; + if (con->connected) + con->connected(con); } ret = bsc_register_fd(fd); @@ -149,3 +173,40 @@ int connect_to_msc(struct bsc_fd *fd, const char *ip, int port) } +struct bsc_msc_connection *bsc_msc_create(const char *ip, int port) +{ + struct bsc_msc_connection *con; + + con = talloc_zero(NULL, struct bsc_msc_connection); + if (!con) { + LOGP(DMSC, LOGL_FATAL, "Failed to create the MSC connection.\n"); + return NULL; + } + + con->ip = ip; + con->port = port; + write_queue_init(&con->write_queue, 100); + return con; +} + +void bsc_msc_lost(struct bsc_msc_connection *con) +{ + bsc_unregister_fd(&con->write_queue.bfd); + connection_loss(con); +} + +static void reconnect_msc(void *_msc) +{ + struct bsc_msc_connection *con = _msc; + + LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n"); + bsc_msc_connect(con); +} + +void bsc_msc_schedule_connect(struct bsc_msc_connection *con) +{ + LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n"); + con->reconnect_timer.cb = reconnect_msc; + con->reconnect_timer.data = con; + bsc_schedule_timer(&con->reconnect_timer, 5, 0); +} diff --git a/openbsc/src/bsc_msc_ip.c b/openbsc/src/bsc_msc_ip.c index b8f2279a0..2effc8e7b 100644 --- a/openbsc/src/bsc_msc_ip.c +++ b/openbsc/src/bsc_msc_ip.c @@ -58,7 +58,7 @@ static struct debug_target *stderr_target; struct gsm_network *bsc_gsmnet = 0; static const char *config_file = "openbsc.cfg"; static char *msc_address = "127.0.0.1"; -static struct write_queue msc_queue; +static struct bsc_msc_connection *msc_con; static struct in_addr local_addr; static LLIST_HEAD(active_connections); extern int ipacc_rtp_direct; @@ -540,7 +540,7 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg) DEBUGP(DMSC, "Sending SCCP to MSC: %u\n", msgb_l2len(msg)); DEBUGP(DMI, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg))); - ret = write(msc_queue.bfd.fd, msg->data, msg->len); + ret = write(msc_con->write_queue.bfd.fd, msg->data, msg->len); if (ret < msg->len) perror("MSC: Failed to send SCCP"); @@ -550,7 +550,7 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg) static void msc_sccp_write_ipa(struct msgb *msg, void *data) { ipaccess_prepend_header(msg, IPAC_PROTO_SCCP); - if (write_queue_enqueue(&msc_queue, msg) != 0) { + if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) { LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/SCCP\n"); msgb_free(msg); } @@ -646,6 +646,17 @@ static void send_id_get_response(int fd) msgb_free(msg); } +/* + * The connection to the MSC was lost and we will need to free all + * resources and then attempt to reconnect. + */ +static void msc_connection_was_lost(struct bsc_msc_connection *con) +{ + LOGP(DMSC, LOGL_ERROR, "Lost MSC connection. Freeing information.\n"); + + exit(0); +} + /* * callback with IP access data */ @@ -657,8 +668,9 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd) if (!msg) { if (error == 0) { - fprintf(stderr, "The connection to the MSC was lost, exiting\n"); - exit(-2); + LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n"); + + return -1; } fprintf(stderr, "Failed to parse ip access message: %d\n", error); @@ -771,6 +783,9 @@ static void signal_handler(int signal) case SIGUSR1: talloc_report_full(tall_bsc_ctx, stderr); break; + case SIGUSR2: + bsc_msc_lost(msc_con); + break; default: break; } @@ -822,8 +837,6 @@ extern int bts_model_nanobts_init(void); int main(int argc, char **argv) { - int rc; - debug_init(); tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); stderr_target = debug_target_create_stderr(); @@ -851,15 +864,19 @@ int main(int argc, char **argv) register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL); - write_queue_init(&msc_queue, 100); - msc_queue.read_cb = ipaccess_a_fd_cb; - msc_queue.write_cb = msc_sccp_do_write; - rc = connect_to_msc(&msc_queue.bfd, msc_address, 5000); - if (rc < 0) { - fprintf(stderr, "Opening the MSC connection failed.\n"); + /* setup MSC Connection handling */ + msc_con = bsc_msc_create(msc_address, 5000); + if (!msc_con) { + fprintf(stderr, "Creating a bsc_msc_connection failed.\n"); exit(1); } + msc_con->connection_loss = msc_connection_was_lost; + msc_con->write_queue.read_cb = ipaccess_a_fd_cb; + msc_con->write_queue.write_cb = msc_sccp_do_write; + bsc_msc_connect(msc_con); + + signal(SIGINT, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c index f50e47f35..3bf4b998f 100644 --- a/openbsc/src/nat/bsc_nat.c +++ b/openbsc/src/nat/bsc_nat.c @@ -53,7 +53,7 @@ struct debug_target *stderr_target; static const char *config_file = "bsc-nat.cfg"; static char *msc_address = "127.0.0.1"; static struct in_addr local_addr; -static struct write_queue msc_queue; +static struct bsc_msc_connection *msc_con; static struct bsc_fd bsc_listen; @@ -420,6 +420,12 @@ exit: return 0; } +static void msc_connection_was_lost(struct bsc_msc_connection *con) +{ + LOGP(DMSC, LOGL_FATAL, "Lost the connection.\n"); + exit(0); +} + static int ipaccess_msc_read_cb(struct bsc_fd *bfd) { int error; @@ -429,7 +435,8 @@ static int ipaccess_msc_read_cb(struct bsc_fd *bfd) if (!msg) { if (error == 0) { LOGP(DNAT, LOGL_FATAL, "The connection the MSC was lost, exiting\n"); - exit(-2); + bsc_msc_lost(msc_con); + return -1; } LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error); @@ -576,7 +583,7 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) } /* send the non-filtered but maybe modified msg */ - if (write_queue_enqueue(&msc_queue, msg) != 0) { + if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) { LOGP(DNAT, LOGL_ERROR, "Can not queue message for the MSC.\n"); msgb_free(msg); } @@ -822,8 +829,6 @@ static void signal_handler(int signal) int main(int argc, char** argv) { - int rc; - debug_init(); stderr_target = debug_target_create_stderr(); debug_add_target(stderr_target); @@ -851,15 +856,17 @@ int main(int argc, char** argv) srand(time(NULL)); /* connect to the MSC */ - write_queue_init(&msc_queue, 100); - msc_queue.read_cb = ipaccess_msc_read_cb; - msc_queue.write_cb = ipaccess_msc_write_cb; - rc = connect_to_msc(&msc_queue.bfd, msc_address, 5000); - if (rc < 0) { - fprintf(stderr, "Opening the MSC connection failed.\n"); + msc_con = bsc_msc_create(msc_address, 5000); + if (!msc_con) { + fprintf(stderr, "Creating a bsc_msc_connection failed.\n"); exit(1); } + msc_con->connection_loss = msc_connection_was_lost; + msc_con->write_queue.read_cb = ipaccess_msc_read_cb; + msc_con->write_queue.write_cb = ipaccess_msc_write_cb;; + bsc_msc_connect(msc_con); + /* wait for the BSC */ if (listen_for_bsc(&bsc_listen, &local_addr, 5000) < 0) { fprintf(stderr, "Failed to listen for BSC.\n"); -- cgit v1.2.3