SMPP: Introduce ESME reference coounting

In case a ESME disappears after SUBMIT-SM but before the MT-SMS
is delivered (transaction mode), we have to make sure the esme
structure still exists.
This commit is contained in:
Harald Welte
2012-11-08 20:11:05 +01:00
parent d4bdee79e9
commit e94db49698
4 changed files with 64 additions and 18 deletions

View File

@@ -117,6 +117,8 @@ void sms_free(struct gsm_sms *sms)
subscr_put(sms->sender); subscr_put(sms->sender);
if (sms->receiver) if (sms->receiver)
subscr_put(sms->receiver); subscr_put(sms->receiver);
if (sms->smpp.esme)
smpp_esme_put(sms->smpp.esme);
talloc_free(sms); talloc_free(sms);
} }

View File

@@ -43,7 +43,7 @@
#include "smpp_smsc.h" #include "smpp_smsc.h"
/*! \brief find gsm_subscriber for a given SMPP NPI/TON/Address */
static struct gsm_subscriber *subscr_by_dst(struct gsm_network *net, static struct gsm_subscriber *subscr_by_dst(struct gsm_network *net,
uint8_t npi, uint8_t ton, const char *addr) uint8_t npi, uint8_t ton, const char *addr)
{ {
@@ -65,6 +65,7 @@ static struct gsm_subscriber *subscr_by_dst(struct gsm_network *net,
return subscr; return subscr;
} }
/*! \brief find a TLV with given tag in list of libsmpp34 TLVs */
struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag) struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag)
{ {
struct tlv_t *t; struct tlv_t *t;
@@ -76,7 +77,7 @@ struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag)
return NULL; return NULL;
} }
/* convert from submit_sm_t to gsm_sms */ /*! \brief convert from submit_sm_t to gsm_sms */
static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net, static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
const struct submit_sm_t *submit) const struct submit_sm_t *submit)
{ {
@@ -156,6 +157,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
return ESME_ROK; return ESME_ROK;
} }
/*! \brief handle incoming libsmpp34 ssubmit_sm_t from remote ESME */
int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit, int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
struct submit_sm_resp_t *submit_r) struct submit_sm_resp_t *submit_r)
{ {
@@ -167,6 +169,7 @@ int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
submit_r->command_status = rc; submit_r->command_status = rc;
return 0; return 0;
} }
smpp_esme_get(esme);
sms->smpp.esme = esme; sms->smpp.esme = esme;
/* FIXME: TP-PID */ /* FIXME: TP-PID */
@@ -195,6 +198,7 @@ int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
return rc; return rc;
} }
/*! \brief signal handler for status of attempted SMS deliveries */
static int smpp_sms_cb(unsigned int subsys, unsigned int signal, static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data) void *handler_data, void *signal_data)
{ {
@@ -235,7 +239,7 @@ static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
return rc; return rc;
} }
/*! \brief Initialize the OpenBSC SMPP interface */
int smpp_openbsc_init(struct gsm_network *net, uint16_t port) int smpp_openbsc_init(struct gsm_network *net, uint16_t port)
{ {
struct smsc *smsc = talloc_zero(net, struct smsc); struct smsc *smsc = talloc_zero(net, struct smsc);

View File

@@ -46,6 +46,31 @@ enum emse_bind {
ESME_BIND_TX = 0x02, ESME_BIND_TX = 0x02,
}; };
/*! \brief increaes the use/reference count */
void smpp_esme_get(struct osmo_esme *esme)
{
esme->use++;
}
static void esme_destroy(struct osmo_esme *esme)
{
osmo_wqueue_clear(&esme->wqueue);
if (esme->wqueue.bfd.fd >= 0) {
osmo_fd_unregister(&esme->wqueue.bfd);
close(esme->wqueue.bfd.fd);
}
llist_del(&esme->list);
talloc_free(esme);
}
/*! \brief decrease the use/reference count, free if it is 0 */
void smpp_esme_put(struct osmo_esme *esme)
{
esme->use--;
if (esme->use <= 0)
esme_destroy(esme);
}
static struct osmo_esme * static struct osmo_esme *
esme_by_system_id(const struct smsc *smsc, char *system_id) esme_by_system_id(const struct smsc *smsc, char *system_id)
{ {
@@ -59,6 +84,7 @@ esme_by_system_id(const struct smsc *smsc, char *system_id)
} }
/*! \brief initialize the libsmpp34 data structure for a response */
#define INIT_RESP(type, resp, req) { \ #define INIT_RESP(type, resp, req) { \
memset((resp), 0, sizeof(*(resp))); \ memset((resp), 0, sizeof(*(resp))); \
(resp)->command_length = 0; \ (resp)->command_length = 0; \
@@ -67,6 +93,7 @@ esme_by_system_id(const struct smsc *smsc, char *system_id)
(resp)->sequence_number = (req)->sequence_number; \ (resp)->sequence_number = (req)->sequence_number; \
} }
/*! \brief pack a libsmpp34 data strcutrure and send it to the ESME */
#define PACK_AND_SEND(esme, ptr) pack_and_send(esme, (ptr)->command_id, ptr) #define PACK_AND_SEND(esme, ptr) pack_and_send(esme, (ptr)->command_id, ptr)
static int pack_and_send(struct osmo_esme *esme, uint32_t type, void *ptr) static int pack_and_send(struct osmo_esme *esme, uint32_t type, void *ptr)
{ {
@@ -87,6 +114,7 @@ static int pack_and_send(struct osmo_esme *esme, uint32_t type, void *ptr)
return osmo_wqueue_enqueue(&esme->wqueue, msg); return osmo_wqueue_enqueue(&esme->wqueue, msg);
} }
/*! \brief transmit a generic NACK to a remote ESME */
static int smpp_tx_gen_nack(struct osmo_esme *esme, uint32_t seq, uint32_t status) static int smpp_tx_gen_nack(struct osmo_esme *esme, uint32_t seq, uint32_t status)
{ {
struct generic_nack_t nack; struct generic_nack_t nack;
@@ -99,19 +127,21 @@ static int smpp_tx_gen_nack(struct osmo_esme *esme, uint32_t seq, uint32_t statu
return PACK_AND_SEND(esme, &nack); return PACK_AND_SEND(esme, &nack);
} }
/*! \brief retrieve SMPP command ID from a msgb */
static inline uint32_t smpp_msgb_cmdid(struct msgb *msg) static inline uint32_t smpp_msgb_cmdid(struct msgb *msg)
{ {
uint8_t *tmp = msgb_data(msg) + 4; uint8_t *tmp = msgb_data(msg) + 4;
return ntohl(*(uint32_t *)tmp); return ntohl(*(uint32_t *)tmp);
} }
/*! \brief retrieve SMPP sequence number from a msgb */
static inline uint32_t smpp_msgb_seq(struct msgb *msg) static inline uint32_t smpp_msgb_seq(struct msgb *msg)
{ {
uint8_t *tmp = msgb_data(msg); uint8_t *tmp = msgb_data(msg);
return ntohl(*(uint32_t *)tmp); return ntohl(*(uint32_t *)tmp);
} }
/*! \brief handle an incoming SMPP generic NACK */
static int smpp_handle_gen_nack(struct osmo_esme *esme, struct msgb *msg) static int smpp_handle_gen_nack(struct osmo_esme *esme, struct msgb *msg)
{ {
struct generic_nack_t nack; struct generic_nack_t nack;
@@ -129,6 +159,7 @@ static int smpp_handle_gen_nack(struct osmo_esme *esme, struct msgb *msg)
return 0; return 0;
} }
/*! \brief handle an incoming SMPP BIND RECEIVER */
static int smpp_handle_bind_rx(struct osmo_esme *esme, struct msgb *msg) static int smpp_handle_bind_rx(struct osmo_esme *esme, struct msgb *msg)
{ {
struct bind_receiver_t bind; struct bind_receiver_t bind;
@@ -165,6 +196,7 @@ err:
return 0; return 0;
} }
/*! \brief handle an incoming SMPP BIND TRANSMITTER */
static int smpp_handle_bind_tx(struct osmo_esme *esme, struct msgb *msg) static int smpp_handle_bind_tx(struct osmo_esme *esme, struct msgb *msg)
{ {
struct bind_transmitter_t bind; struct bind_transmitter_t bind;
@@ -212,6 +244,7 @@ err:
return PACK_AND_SEND(esme, &bind_r); return PACK_AND_SEND(esme, &bind_r);
} }
/*! \brief handle an incoming SMPP BIND TRANSCEIVER */
static int smpp_handle_bind_trx(struct osmo_esme *esme, struct msgb *msg) static int smpp_handle_bind_trx(struct osmo_esme *esme, struct msgb *msg)
{ {
struct bind_transceiver_t bind; struct bind_transceiver_t bind;
@@ -247,6 +280,7 @@ err:
return 0; return 0;
} }
/*! \brief handle an incoming SMPP UNBIND */
static int smpp_handle_unbind(struct osmo_esme *esme, struct msgb *msg) static int smpp_handle_unbind(struct osmo_esme *esme, struct msgb *msg)
{ {
struct unbind_t unbind; struct unbind_t unbind;
@@ -272,7 +306,7 @@ err:
return PACK_AND_SEND(esme, &unbind_r); return PACK_AND_SEND(esme, &unbind_r);
} }
/*! \brief handle an incoming SMPP ENQUIRE LINK */
static int smpp_handle_enq_link(struct osmo_esme *esme, struct msgb *msg) static int smpp_handle_enq_link(struct osmo_esme *esme, struct msgb *msg)
{ {
struct enquire_link_t enq; struct enquire_link_t enq;
@@ -291,6 +325,7 @@ static int smpp_handle_enq_link(struct osmo_esme *esme, struct msgb *msg)
return PACK_AND_SEND(esme, &enq_r); return PACK_AND_SEND(esme, &enq_r);
} }
/*! \brief send a SUBMIT-SM RESPONSE to a remote ESME */
int smpp_tx_submit_r(struct osmo_esme *esme, uint32_t sequence_nr, int smpp_tx_submit_r(struct osmo_esme *esme, uint32_t sequence_nr,
uint32_t command_status, char *msg_id) uint32_t command_status, char *msg_id)
{ {
@@ -306,6 +341,7 @@ int smpp_tx_submit_r(struct osmo_esme *esme, uint32_t sequence_nr,
return PACK_AND_SEND(esme, &submit_r); return PACK_AND_SEND(esme, &submit_r);
} }
/*! \brief handle an incoming SMPP SUBMIT-SM */
static int smpp_handle_submit(struct osmo_esme *esme, struct msgb *msg) static int smpp_handle_submit(struct osmo_esme *esme, struct msgb *msg)
{ {
struct submit_sm_t submit; struct submit_sm_t submit;
@@ -336,7 +372,7 @@ static int smpp_handle_submit(struct osmo_esme *esme, struct msgb *msg)
return rc; return rc;
} }
/* one complete SMPP PDU from the ESME has been received */ /*! \brief one complete SMPP PDU from the ESME has been received */
static int smpp_pdu_rx(struct osmo_esme *esme, struct msgb *msg) static int smpp_pdu_rx(struct osmo_esme *esme, struct msgb *msg)
{ {
uint32_t cmd_id = smpp_msgb_cmdid(msg); uint32_t cmd_id = smpp_msgb_cmdid(msg);
@@ -388,16 +424,7 @@ static int smpp_pdu_rx(struct osmo_esme *esme, struct msgb *msg)
return rc; return rc;
} }
static void esme_destroy(struct osmo_esme *esme) /* !\brief call-back when per-ESME TCP socket has some data to be read */
{
osmo_wqueue_clear(&esme->wqueue);
osmo_fd_unregister(&esme->wqueue.bfd);
close(esme->wqueue.bfd.fd);
llist_del(&esme->list);
talloc_free(esme);
}
/* call-back when per-ESME TCP socket has some data to be read */
static int esme_link_read_cb(struct osmo_fd *ofd) static int esme_link_read_cb(struct osmo_fd *ofd)
{ {
struct osmo_esme *esme = ofd->data; struct osmo_esme *esme = ofd->data;
@@ -456,7 +483,10 @@ static int esme_link_read_cb(struct osmo_fd *ofd)
return 0; return 0;
dead_socket: dead_socket:
msgb_free(esme->read_msg); msgb_free(esme->read_msg);
esme_destroy(esme); osmo_fd_unregister(&esme->wqueue.bfd);
close(esme->wqueue.bfd.fd);
esme->wqueue.bfd.fd = -1;
smpp_esme_put(esme);
return 0; return 0;
} }
@@ -469,7 +499,10 @@ static void esme_link_write_cb(struct osmo_fd *ofd, struct msgb *msg)
rc = write(ofd->fd, msgb_data(msg), msgb_length(msg)); rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
if (rc == 0) { if (rc == 0) {
esme_destroy(esme); osmo_fd_unregister(&esme->wqueue.bfd);
close(esme->wqueue.bfd.fd);
esme->wqueue.bfd.fd = -1;
smpp_esme_put(esme);
} else if (rc < msgb_length(msg)) { } else if (rc < msgb_length(msg)) {
LOGP(DSMPP, LOGL_ERROR, "%s: Short write\n", esme->system_id); LOGP(DSMPP, LOGL_ERROR, "%s: Short write\n", esme->system_id);
return; return;
@@ -484,6 +517,7 @@ static int link_accept_cb(struct smsc *smsc, int fd,
if (!esme) if (!esme)
return -ENOMEM; return -ENOMEM;
smpp_esme_get(esme);
esme->smsc = smsc; esme->smsc = smsc;
osmo_wqueue_init(&esme->wqueue, 10); osmo_wqueue_init(&esme->wqueue, 10);
esme->wqueue.bfd.fd = fd; esme->wqueue.bfd.fd = fd;
@@ -518,6 +552,7 @@ static int smsc_fd_cb(struct osmo_fd *ofd, unsigned int what)
return link_accept_cb(ofd->data, rc, &sa, sa_len); return link_accept_cb(ofd->data, rc, &sa, sa_len);
} }
/*! \brief Initialize the SMSC-side SMPP implementation */
int smpp_smsc_init(struct smsc *smsc, uint16_t port) int smpp_smsc_init(struct smsc *smsc, uint16_t port)
{ {
int rc; int rc;

View File

@@ -21,6 +21,8 @@ struct osmo_esme {
struct llist_head list; struct llist_head list;
struct smsc *smsc; struct smsc *smsc;
int use;
struct osmo_wqueue wqueue; struct osmo_wqueue wqueue;
struct sockaddr_storage sa; struct sockaddr_storage sa;
socklen_t sa_len; socklen_t sa_len;
@@ -46,6 +48,9 @@ struct smsc {
int smpp_smsc_init(struct smsc *smsc, uint16_t port); int smpp_smsc_init(struct smsc *smsc, uint16_t port);
void smpp_esme_get(struct osmo_esme *esme);
void smpp_esme_put(struct osmo_esme *esme);
int smpp_tx_submit_r(struct osmo_esme *esme, uint32_t sequence_nr, int smpp_tx_submit_r(struct osmo_esme *esme, uint32_t sequence_nr,
uint32_t command_status, char *msg_id); uint32_t command_status, char *msg_id);