diff options
author | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2013-10-24 23:42:57 +0400 |
---|---|---|
committer | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2013-10-24 23:42:57 +0400 |
commit | 94a349938b59ba1b3890e956de9f151f03581928 (patch) | |
tree | 4cbaf74d0910077667f84fcd5341d8dd3c529561 | |
parent | 64cb9246346ed991fceb4f749b15daf7177b201c (diff) |
Added unix domain socket for sending and receiving SMS messages to/from external applications.
-rw-r--r-- | openbsc/include/openbsc/gsm_data.h | 3 | ||||
-rw-r--r-- | openbsc/include/openbsc/sms_sock.h | 34 | ||||
-rw-r--r-- | openbsc/src/libcommon/gsm_data.c | 1 | ||||
-rw-r--r-- | openbsc/src/libmsc/Makefile.am | 1 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_11.c | 11 | ||||
-rw-r--r-- | openbsc/src/libmsc/sms_sock.c | 261 | ||||
-rw-r--r-- | openbsc/src/osmo-nitb/bsc_hack.c | 2 |
7 files changed, 311 insertions, 2 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 874150535..04f3a1cc3 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -235,6 +235,9 @@ struct gsm_network { struct mncc_sock_state *mncc_state; int (*mncc_recv) (struct gsm_network *net, struct msgb *msg); struct llist_head upqueue; + struct sms_sock_state *sms_state; + int (*sms_recv) (struct gsm_network *net, struct msgb *msg); + struct llist_head smsqueue; struct llist_head trans_list; struct bsc_api *bsc_api; diff --git a/openbsc/include/openbsc/sms_sock.h b/openbsc/include/openbsc/sms_sock.h new file mode 100644 index 000000000..a3c059703 --- /dev/null +++ b/openbsc/include/openbsc/sms_sock.h @@ -0,0 +1,34 @@ +/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> + * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _SMS_SOCK_H +#define _SMS_SOCK_H + +#include <osmocom/core/linuxlist.h> +#include <stdint.h> + +struct gsm_network; +struct msgb; + +int sms_sock_try_deliver(struct gsm_network *net, struct msgb *msg); + +int sms_sock_init(struct gsm_network *net); + +#endif diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 5f7e32e73..cedb13800 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -110,6 +110,7 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod INIT_LLIST_HEAD(&net->trans_list); INIT_LLIST_HEAD(&net->upqueue); + INIT_LLIST_HEAD(&net->smsqueue); INIT_LLIST_HEAD(&net->bts_list); net->stats.chreq.total = osmo_counter_alloc("net.chreq.total"); diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 2b5059986..b053a0c2a 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -9,6 +9,7 @@ libmsc_a_SOURCES = auth.c \ gsm_04_08.c gsm_04_11.c gsm_04_80.c \ gsm_subscriber.c \ mncc.c mncc_builtin.c mncc_sock.c \ + sms_sock.c \ rrlp.c \ silent_call.c \ sms_queue.c \ diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index e554b7401..698a34bc9 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -406,8 +406,15 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m /* FIXME: handle the error somehow? */ } #else - rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + rc = sms_sock_try_deliver(conn->bts->network, msg); + if (rc == 1) { + rc = 1; /* cause 1: unknown subscriber */ + osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + } else if (rc < 0) { + rc = 21; /* cause 21: short message transfer rejected */ + /* FIXME: handle the error somehow? */ + } + #endif goto out; } diff --git a/openbsc/src/libmsc/sms_sock.c b/openbsc/src/libmsc/sms_sock.c new file mode 100644 index 000000000..8e42d7e3f --- /dev/null +++ b/openbsc/src/libmsc/sms_sock.c @@ -0,0 +1,261 @@ +/* sms_sock.c: SMS interface to a unix domain socket */ + +/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> + * (C) 2009 by Andreas Eversberg <Andreas.Eversberg@versatel.de> + * (C) 2012 by Holger Hans Peter Freyther + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/core/select.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> + +#include <openbsc/debug.h> +#include <openbsc/gsm_data.h> + +struct sms_sock_state { + struct gsm_network *net; + struct osmo_fd listen_bfd; /* fd for listen socket */ + struct osmo_fd conn_bfd; /* fd for connection to lcr */ +}; + +int sms_sock_try_deliver(struct gsm_network *net, struct msgb *msg) +{ + /* Check if we currently have a MNCC handler connected */ + if (net->sms_state->conn_bfd.fd < 0) { + LOGP(DMNCC, LOGL_ERROR, "sms_sock receives for external CC app " + "but socket is gone\n"); + /* free the original message */ + msgb_free(msg); + return -1; + } + + /* FIXME: check for some maximum queue depth? */ + + /* Actually enqueue the message and mark socket write need */ + msgb_enqueue(&net->smsqueue, msg); + net->sms_state->conn_bfd.when |= BSC_FD_WRITE; + return 0; +} + +static void sms_sock_close(struct sms_sock_state *state) +{ + struct osmo_fd *bfd = &state->conn_bfd; + + LOGP(DMNCC, LOGL_NOTICE, "SMS Socket has LOST connection\n"); + + close(bfd->fd); + bfd->fd = -1; + osmo_fd_unregister(bfd); + + /* re-enable the generation of ACCEPT for new connections */ + state->listen_bfd.when |= BSC_FD_READ; + + /* flush the queue */ + while (!llist_empty(&state->net->smsqueue)) { + struct msgb *msg = msgb_dequeue(&state->net->smsqueue); + msgb_free(msg); + } +} + +static int sms_sock_read(struct osmo_fd *bfd) +{ + struct sms_sock_state *state = (struct sms_sock_state *)bfd->data; + struct msgb *msg; + int rc; + + msg = msgb_alloc(256, "sms_sock_rx"); + if (!msg) + return -ENOMEM; + + rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0); + if (rc == 0) + goto close; + + if (rc < 0) { + if (errno == EAGAIN) + return 0; + goto close; + } + + + // TODO: We should parse message here. + LOGP(DMNCC, LOGL_ERROR, "We should parse message here %s \n", osmo_hexdump(msg->tail, msgb_tailroom(msg))); + + msgb_free(msg); + + return rc; + +close: + msgb_free(msg); + sms_sock_close(state); + return -1; +} + +static int sms_sock_write(struct osmo_fd *bfd) +{ + struct sms_sock_state *state = bfd->data; + struct gsm_network *net = state->net; + int rc; + + while (!llist_empty(&net->smsqueue)) { + struct msgb *msg, *msg2; + + /* peek at the beginning of the queue */ + msg = llist_entry(net->smsqueue.next, struct msgb, list); + + bfd->when &= ~BSC_FD_WRITE; + + /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */ + if (!msgb_length(msg)) { + LOGP(DMNCC, LOGL_ERROR, "message type with ZERO " + "bytes!\n"); + goto dontsend; + } + + /* try to send it over the socket */ + rc = write(bfd->fd, msgb_sms(msg), (unsigned) (msg->tail - (uint8_t *)msgb_sms(msg))); + if (rc == 0) + goto close; + if (rc < 0) { + if (errno == EAGAIN) { + bfd->when |= BSC_FD_WRITE; + break; + } + goto close; + } + +dontsend: + /* _after_ we send it, we can deueue */ + msg2 = msgb_dequeue(&net->smsqueue); + assert(msg == msg2); + } + return 0; + +close: + sms_sock_close(state); + return -1; +} + +static int sms_sock_cb(struct osmo_fd *bfd, unsigned int flags) +{ + int rc = 0; + + if (flags & BSC_FD_READ) + rc = sms_sock_read(bfd); + if (rc < 0) + return rc; + + if (flags & BSC_FD_WRITE) + rc = sms_sock_write(bfd); + + return rc; +} + +/* accept a new connection */ +static int sms_sock_accept(struct osmo_fd *bfd, unsigned int flags) +{ + struct sms_sock_state *state = (struct sms_sock_state *)bfd->data; + struct osmo_fd *conn_bfd = &state->conn_bfd; + struct sockaddr_un un_addr; + socklen_t len; + int rc; + + len = sizeof(un_addr); + rc = accept(bfd->fd, (struct sockaddr *) &un_addr, &len); + if (rc < 0) { + LOGP(DMNCC, LOGL_ERROR, "Failed to accept a new connection\n"); + return -1; + } + + if (conn_bfd->fd >= 0) { + LOGP(DMNCC, LOGL_NOTICE, "SMS app connects but we already have " + "another active connection ?!?\n"); + /* We already have one SMS app connected, this is all we support */ + state->listen_bfd.when &= ~BSC_FD_READ; + close(rc); + return 0; + } + + conn_bfd->fd = rc; + conn_bfd->when = BSC_FD_READ; + conn_bfd->cb = sms_sock_cb; + conn_bfd->data = state; + + if (osmo_fd_register(conn_bfd) != 0) { + LOGP(DMNCC, LOGL_ERROR, "Failed to register new connection fd\n"); + close(conn_bfd->fd); + conn_bfd->fd = -1; + return -1; + } + + LOGP(DMNCC, LOGL_NOTICE, "SMS Socket has connection with external " + "SMS application\n"); + + return 0; +} + + +int sms_sock_init(struct gsm_network *net) +{ + struct sms_sock_state *state; + struct osmo_fd *bfd; + int rc; + + state = talloc_zero(tall_bsc_ctx, struct sms_sock_state); + if (!state) + return -ENOMEM; + + state->net = net; + state->conn_bfd.fd = -1; + + bfd = &state->listen_bfd; + + rc = osmo_unixsock_listen(bfd, SOCK_STREAM, "/tmp/bsc_sms"); + if (rc < 0) { + LOGP(DMNCC, LOGL_ERROR, "Could not create unix socket: %s\n", + strerror(errno)); + talloc_free(state); + return rc; + } + + bfd->when = BSC_FD_READ; + bfd->cb = sms_sock_accept; + bfd->data = state; + + rc = osmo_fd_register(bfd); + if (rc < 0) { + LOGP(DMNCC, LOGL_ERROR, "Could not register listen fd: %d\n", rc); + close(bfd->fd); + talloc_free(state); + return rc; + } + + net->sms_state = state; + + return 0; +} diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 172fb8269..30c60239a 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -42,6 +42,7 @@ #include <openbsc/vty.h> #include <openbsc/bss.h> #include <openbsc/mncc.h> +#include <openbsc/sms_sock.h> #include <openbsc/token_auth.h> #include <openbsc/handover_decision.h> #include <openbsc/rrlp.h> @@ -282,6 +283,7 @@ int main(int argc, char **argv) #ifdef BUILD_SMPP smpp_openbsc_set_net(bsc_gsmnet); #endif + sms_sock_init(bsc_gsmnet); bsc_api_init(bsc_gsmnet, msc_bsc_api()); bsc_gsmnet->ctrl = controlif_setup(bsc_gsmnet, 4249); |