aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-12-20 22:29:40 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2011-01-01 14:22:28 +0100
commitc94e90298cea3eaf7fca31be3069f6ad274f05e9 (patch)
tree6f83de80a9f7bcb4f525aad517e2617be3e17db9
parentc3dcfa79b90f6f43d651329046846c8a0189b98f (diff)
linkset: Move the UDP socket into the bsc_data to share it between a linkset
Move the write_queue from the link_data to the bsc_data. This way the socket can be used for many links in the same linkset.
-rw-r--r--include/bsc_data.h9
-rw-r--r--src/link_udp.c87
-rw-r--r--src/links.c5
3 files changed, 72 insertions, 29 deletions
diff --git a/include/bsc_data.h b/include/bsc_data.h
index 7906130..4c04e10 100644
--- a/include/bsc_data.h
+++ b/include/bsc_data.h
@@ -52,9 +52,8 @@ struct link_data {
struct timer_list mtp_timeout;
} c7;
struct {
- struct write_queue write_queue;
- struct sockaddr_in remote;
struct snmp_mtp_session *session;
+ struct sockaddr_in remote;
int link_index;
int reset_timeout;
} udp;
@@ -128,6 +127,9 @@ struct bsc_data {
uint16_t lac;
int forward_only;
+
+ /* UDP socket code */
+ struct write_queue udp_write_queue;
};
/* bsc related functions */
@@ -155,7 +157,8 @@ unsigned int sls_for_src_ref(struct sccp_source_reference *ref);
int link_c7_init(struct link_data *data);
/* udp init */
-int link_udp_init(struct link_data *data, int src_port, const char *dest_ip, int port);
+int link_udp_network_init(struct bsc_data *bsc);
+int link_udp_init(struct link_data *link, const char *ip, int port);
/* MGCP */
void mgcp_forward(struct bsc_data *bsc, const uint8_t *data, unsigned int length);
diff --git a/src/link_udp.c b/src/link_udp.c
index 405c7f7..5c24064 100644
--- a/src/link_udp.c
+++ b/src/link_udp.c
@@ -36,12 +36,32 @@
#include <string.h>
#include <unistd.h>
+#define OSMO_CB_LI(msg) msg->cb[0]
+
+static struct link_data *find_link(struct bsc_data *bsc, int link_index)
+{
+ struct link_data *link;
+
+ llist_for_each_entry(link, &bsc->links, entry)
+ if (link->udp.link_index == link_index)
+ return link;
+
+ return NULL;
+}
+
static int udp_write_cb(struct bsc_fd *fd, struct msgb *msg)
{
+ struct bsc_data *bsc;
struct link_data *link;
int rc;
- link = (struct link_data *) fd->data;
+ bsc = (struct bsc_data *) fd->data;
+
+ link = find_link(bsc, OSMO_CB_LI(msg));
+ if (!link) {
+ LOGP(DINP, LOGL_ERROR, "No link_data for %lu\n", OSMO_CB_LI(msg));
+ return -1;
+ }
LOGP(DINP, LOGL_DEBUG, "Sending MSU: %s\n", hexdump(msg->data, msg->len));
if (link->pcap_fd >= 0)
@@ -60,6 +80,7 @@ static int udp_write_cb(struct bsc_fd *fd, struct msgb *msg)
static int udp_read_cb(struct bsc_fd *fd)
{
+ struct bsc_data *bsc;
struct link_data *link;
struct udp_data_hdr *hdr;
struct msgb *msg;
@@ -73,7 +94,7 @@ static int udp_read_cb(struct bsc_fd *fd)
}
- link = (struct link_data *) fd->data;
+ bsc = (struct bsc_data *) fd->data;
rc = read(fd->fd, msg->data, 2096);
if (rc < sizeof(*hdr)) {
LOGP(DINP, LOGL_ERROR, "Failed to read at least size of the header: %d\n", rc);
@@ -81,6 +102,15 @@ static int udp_read_cb(struct bsc_fd *fd)
goto exit;
}
+ hdr = (struct udp_data_hdr *) msgb_put(msg, sizeof(*hdr));
+
+ link = find_link(bsc, ntohs(hdr->data_link_index));
+ if (!link) {
+ LOGP(DINP, LOGL_ERROR, "Failed to find a link.\n");
+ rc = -1;
+ goto exit;
+ }
+
/* throw away data as the link is down */
if (link->the_link->available == 0) {
LOGP(DINP, LOGL_ERROR, "The link is down. Not forwarding.\n");
@@ -88,7 +118,6 @@ static int udp_read_cb(struct bsc_fd *fd)
goto exit;
}
- hdr = (struct udp_data_hdr *) msgb_put(msg, sizeof(*hdr));
if (hdr->data_type == UDP_DATA_RETR_COMPL || hdr->data_type == UDP_DATA_RETR_IMPOS) {
LOGP(DINP, LOGL_ERROR, "Link retrieval done. Restarting the link.\n");
@@ -161,7 +190,9 @@ static int udp_link_write(struct link_data *link, struct msgb *msg)
hdr->user_context = 0;
hdr->data_length = htonl(msgb_l2len(msg));
- if (write_queue_enqueue(&link->udp.write_queue, msg) != 0) {
+ OSMO_CB_LI(msg) = link->udp.link_index;
+
+ if (write_queue_enqueue(&link->bsc->udp_write_queue, msg) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to enqueue msg.\n");
msgb_free(msg);
return -1;
@@ -177,29 +208,21 @@ static int udp_link_start(struct link_data *link)
return 0;
}
-int link_udp_init(struct link_data *link, int src_port, const char *remote, int remote_port)
+int link_udp_network_init(struct bsc_data *bsc)
{
struct sockaddr_in addr;
int fd;
int on;
- write_queue_init(&link->udp.write_queue, 100);
-
- /* function table */
- link->shutdown = udp_link_dummy;
- link->clear_queue = udp_link_dummy;
-
- link->reset = udp_link_reset;
- link->start = udp_link_start;
- link->write = udp_link_write;
+ write_queue_init(&bsc->udp_write_queue, 100);
/* socket creation */
- link->udp.write_queue.bfd.data = link;
- link->udp.write_queue.bfd.when = BSC_FD_READ;
- link->udp.write_queue.read_cb = udp_read_cb;
- link->udp.write_queue.write_cb = udp_write_cb;
+ bsc->udp_write_queue.bfd.data = bsc;
+ bsc->udp_write_queue.bfd.when = BSC_FD_READ;
+ bsc->udp_write_queue.read_cb = udp_read_cb;
+ bsc->udp_write_queue.write_cb = udp_write_cb;
- link->udp.write_queue.bfd.fd = fd = socket(AF_INET, SOCK_DGRAM, 0);
+ bsc->udp_write_queue.bfd.fd = fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
LOGP(DINP, LOGL_ERROR, "Failed to create UDP socket.\n");
return -1;
@@ -210,7 +233,7 @@ int link_udp_init(struct link_data *link, int src_port, const char *remote, int
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
- addr.sin_port = htons(src_port);
+ addr.sin_port = htons(bsc->src_port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
@@ -220,12 +243,8 @@ int link_udp_init(struct link_data *link, int src_port, const char *remote, int
}
/* now connect the socket to the remote */
- memset(&link->udp.remote, 0, sizeof(link->udp.remote));
- link->udp.remote.sin_family = AF_INET;
- link->udp.remote.sin_port = htons(remote_port);
- inet_aton(remote, &link->udp.remote.sin_addr);
- if (bsc_register_fd(&link->udp.write_queue.bfd) != 0) {
+ if (bsc_register_fd(&bsc->udp_write_queue.bfd) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to register BFD.\n");
close(fd);
return -1;
@@ -233,3 +252,21 @@ int link_udp_init(struct link_data *link, int src_port, const char *remote, int
return 0;
}
+
+int link_udp_init(struct link_data *link, const char *remote, int remote_port)
+{
+ /* function table */
+ link->shutdown = udp_link_dummy;
+ link->clear_queue = udp_link_dummy;
+
+ link->reset = udp_link_reset;
+ link->start = udp_link_start;
+ link->write = udp_link_write;
+
+ memset(&link->udp.remote, 0, sizeof(link->udp.remote));
+ link->udp.remote.sin_family = AF_INET;
+ link->udp.remote.sin_port = htons(remote_port);
+ inet_aton(remote, &link->udp.remote.sin_addr);
+
+ return 0;
+}
diff --git a/src/links.c b/src/links.c
index e9bd5f6..4478d76 100644
--- a/src/links.c
+++ b/src/links.c
@@ -111,8 +111,11 @@ int link_setup_start(struct bsc_data *bsc)
if (!bsc->first_link.udp.session)
return -1;
+ if (link_udp_network_init(bsc) != 0)
+ return -1;
+
/* now connect to the transport */
- if (link_udp_init(&bsc->first_link, bsc->src_port, bsc->udp_ip, bsc->udp_port) != 0)
+ if (link_udp_init(&bsc->first_link, bsc->udp_ip, bsc->udp_port) != 0)
return -1;
/*