[svn-commits] may: branch may/smpp r400905 - /team/may/smpp/branches/10/addons/
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Mon Oct 14 15:33:16 CDT 2013
Author: may
Date: Mon Oct 14 15:33:13 2013
New Revision: 400905
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=400905
Log:
first work version
bind_transceiver/bin_tr_resp, deliver_sm/deliver_sm_resp, submit_sm/submit_sm_resp, enquire_link/enquire_link_resp
supported only
Added:
team/may/smpp/branches/10/addons/res_smpp.c (with props)
Modified:
team/may/smpp/branches/10/addons/Makefile
Modified: team/may/smpp/branches/10/addons/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/Makefile?view=diff&rev=400905&r1=400904&r2=400905
==============================================================================
--- team/may/smpp/branches/10/addons/Makefile (original)
+++ team/may/smpp/branches/10/addons/Makefile Mon Oct 14 15:33:13 2013
@@ -32,7 +32,8 @@
chan_mobile \
chan_ooh323 \
format_mp3 \
- res_config_mysql
+ res_config_mysql \
+ res_smpp
all: check_mp3 _all
@@ -65,6 +66,8 @@
$(if $(filter format_mp3,$(EMBEDDED_MODS)),modules.link,format_mp3.so): mp3/common.o mp3/dct64_i386.o mp3/decode_ntom.o mp3/layer3.o mp3/tabinit.o mp3/interface.o
chan_ooh323.o: _ASTCFLAGS+=$(H323CFLAGS)
+res_smpp.o: _ASTCFLAGS+=-I/usr/local/include
+res_smpp.so: LIBS+=-L/usr/local/lib -lsmpp34
$(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): _ASTCFLAGS+=$(H323CFLAGS)
$(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): $(addprefix ooh323c/src/,$(H323OBJS)) chan_ooh323.o ooh323cDriver.o
Added: team/may/smpp/branches/10/addons/res_smpp.c
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/res_smpp.c?view=auto&rev=400905
==============================================================================
--- team/may/smpp/branches/10/addons/res_smpp.c (added)
+++ team/may/smpp/branches/10/addons/res_smpp.c Mon Oct 14 15:33:13 2013
@@ -1,0 +1,1575 @@
+/*
+ */
+
+/*! \file
+ *
+ * \brief SMPP messaging module
+ *
+ */
+
+/*** MODULEINFO
+ <defaultenabled>no</defaultenabled>
+ <support_level>extended</support_level>
+ ***/
+
+// todo
+// data coding scheme +
+// message-id +
+// bind_resp failed
+// locking +
+// memory leaks & valgrind testing +
+// many other things ;)
+
+#include "asterisk.h"
+#include <pthread.h>
+#include <signal.h>
+#include <sys/signal.h>
+
+
+
+#include "asterisk/channel.h"
+#include "asterisk/module.h"
+#include "asterisk/cli.h"
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/pbx.h"
+#include "asterisk/sched.h"
+#include "asterisk/io.h"
+#include "asterisk/acl.h"
+#include "asterisk/callerid.h"
+#include "asterisk/file.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/rtp_engine.h"
+#include "asterisk/causes.h"
+#include "asterisk/message.h"
+
+
+#define MODULE_DESCRIPTION "SMPP messaging resource module"
+
+#include "smpp34.h"
+#include "smpp34_structs.h"
+#include "smpp34_params.h"
+
+#define TRUE 1
+#define FALSE 0
+
+
+static char config[] = "smpp.conf";
+
+static int smppDebug = 1;
+static struct ast_sockaddr bindaddr;
+static int bindport = 2775;
+static int smppSocket = 0;
+static int smpplistener_stop = 0;
+static pthread_t listener = AST_PTHREADT_NULL;
+static char system_id[16] = "asterisk";
+AST_MUTEX_DEFINE_STATIC(smpp_lock);
+//
+
+struct smpp_smsc;
+
+struct smpp_buff {
+ uint8_t *pdubuf;
+ uint32_t pdulen;
+ AST_LIST_ENTRY(smpp_buff) next;
+};
+
+struct respwait {
+ ast_cond_t cond;
+ ast_mutex_t lock;
+ int delivered;
+ uint32_t sequence_number;
+ unsigned char message_id[66];
+ AST_LIST_ENTRY(respwait) next;
+};
+
+struct newsocket {
+ struct ast_sockaddr addr;
+ int socket;
+};
+
+struct smpp_smsc {
+ char name[256];
+ char system_id[16];
+ char password[9];
+ char system_type[13];
+ int seq;
+ int enquire;
+ time_t lastenq;
+ char host[MAXHOSTNAMELEN];
+ int port;
+ struct ast_sockaddr addr;
+ int socket;
+ pthread_t monitor;
+ ast_mutex_t lock;
+ unsigned int stop :1;
+ unsigned int esme :1;
+ char context[AST_MAX_EXTENSION];
+ AST_LIST_HEAD(smsc_outq, smpp_buff) outq;
+ AST_LIST_HEAD(smsc_respq, respwait) respq;
+
+ struct smpp_smsc *next;
+} *smsc_list = NULL;
+
+static struct smpp_buff* queue_pdu(struct smpp_smsc *smsc, uint32_t cmd, void *unpack);
+
+//
+// return conference parameters to channel driver
+//
+
+static char* generate_msgid(char *msgid)
+{
+ unsigned short val[4];
+ int x;
+
+ for (x = 0; x < 4; x++) {
+ val[x] = ast_random();
+ }
+ sprintf(msgid, "%04x%04x%04x%04x", val[0], val[1], val[2], val[3]);
+ return msgid;
+}
+
+// SMPP processing
+
+static int smsc_connect(struct smpp_smsc *smsc)
+{
+ int sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (!sock) {
+ return 0;
+ }
+
+ ast_sockaddr_set_port(&smsc->addr, smsc->port);
+ if (smppDebug) {
+ ast_verb(3,"SMPP try to connect to %s:%d for smsc %s\n",
+ ast_sockaddr_stringify_addr(&smsc->addr), ast_sockaddr_port(&smsc->addr),
+ smsc->name);
+ }
+ if (ast_connect(sock, &smsc->addr)) {
+ close(sock);
+ ast_log(LOG_WARNING, "Can't connect to %s:%d for smsc %s (%s)\n",
+ ast_sockaddr_stringify_addr(&smsc->addr), ast_sockaddr_port(&smsc->addr),
+ smsc->name, strerror(errno));
+ return 0;
+ }
+ smsc->seq = 1;
+ return sock;
+}
+
+static void* read_smpp(struct smpp_smsc *smsc, void *unpack)
+{
+ unsigned char pdu[2048];
+ unsigned char bPrint[2048];
+ uint32_t pdulen;
+
+ memset(&pdu, 0, sizeof(pdu));
+
+ if ((recv(smsc->socket, &pdulen, 4, MSG_PEEK) != 4) ||
+ (recv(smsc->socket, pdu, ntohl(pdulen), 0) != ntohl(pdulen))) {
+ ast_log(LOG_WARNING, "smpp read error %s to smsc %s\n", strerror(errno), smsc->name);
+ return NULL;
+ } else {
+ pdulen = ntohl(pdulen);
+ if (smppDebug) {
+ ast_verb(3,"SMSC %s, read pdu %d\n", smsc->name, pdulen);
+ }
+ }
+ if (smpp34_unpack2((void*)unpack, pdu, pdulen)) {
+ ast_log(LOG_WARNING, "Error in smpp34_unpack2():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ return NULL;
+ }
+ if (smppDebug) {
+ if (smpp34_dumpPdu2(bPrint, sizeof(bPrint), (void*)unpack)) {
+ ast_log(LOG_WARNING, "Error in smpp34_dumppdu():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ return NULL;
+ } else {
+ ast_verb(3, "PDU Dump:\n%s\n", bPrint);
+ }
+ }
+ return unpack;
+}
+
+static void process_pdu(struct smpp_smsc *smsc, void *unpack)
+{
+ submit_sm_t *submit;
+ submit_sm_resp_t *submit_sm_resp;
+ deliver_sm_t *deliver;
+ deliver_sm_resp_t *deliver_sm_resp;
+ enquire_link_t *enq;
+ enquire_link_resp_t *enq_resp;
+
+ struct respwait *resp;
+ uint32_t sequence_number;
+
+ submit = unpack;
+ submit_sm_resp = unpack;
+ deliver = unpack;
+ deliver_sm_resp = unpack;
+ enq = unpack;
+ enq_resp = unpack;
+
+ if ((uint32_t)submit_sm_resp->command_id == (uint32_t) SUBMIT_SM_RESP && submit_sm_resp->command_status == ESME_ROK) {
+ sequence_number = submit_sm_resp->sequence_number;
+ AST_LIST_LOCK(&smsc->respq);
+ AST_LIST_TRAVERSE(&smsc->respq, resp, next) {
+ ast_mutex_lock(&resp->lock);
+ if (resp->sequence_number == sequence_number) {
+ resp->delivered = 1;
+ snprintf((char *)resp->message_id, sizeof(resp->message_id), "%s", submit_sm_resp->message_id);
+ ast_mutex_unlock(&resp->lock);
+ break;
+ }
+ ast_mutex_unlock(&resp->lock);
+ }
+ if (resp) {
+ AST_LIST_REMOVE(&smsc->respq, resp, next);
+ ast_cond_signal(&resp->cond);
+ }
+ AST_LIST_UNLOCK(&smsc->respq);
+
+ } else if ((uint32_t)deliver_sm_resp->command_id == (uint32_t) DELIVER_SM_RESP && deliver_sm_resp->command_status == ESME_ROK) {
+ sequence_number = deliver_sm_resp->sequence_number;
+ AST_LIST_LOCK(&smsc->respq);
+ AST_LIST_TRAVERSE(&smsc->respq, resp, next) {
+ ast_mutex_lock(&resp->lock);
+ if (resp->sequence_number == sequence_number) {
+ resp->delivered = 1;
+ ast_mutex_unlock(&resp->lock);
+ break;
+ }
+ ast_mutex_unlock(&resp->lock);
+ }
+ if (resp) {
+ AST_LIST_REMOVE(&smsc->respq, resp, next);
+ ast_cond_signal(&resp->cond);
+ }
+ AST_LIST_UNLOCK(&smsc->respq);
+
+ } else if ((uint32_t)deliver->command_id == (uint32_t) DELIVER_SM && deliver->command_status == ESME_ROK) {
+ struct ast_msg *msg = ast_msg_alloc();
+ char body[1024];
+ char tmp[1024];
+ int res;
+ deliver_sm_resp_t sm_resp;
+
+ if (!msg) {
+ return;
+ }
+ sequence_number = deliver->sequence_number;
+ res = ast_msg_set_to(msg, "%s", deliver->destination_addr);
+ res |= ast_msg_set_from(msg, "%s", deliver->source_addr);
+ memcpy(body, deliver->short_message, deliver->sm_length);
+ body[deliver->sm_length] = 0;
+ res |= ast_msg_set_body(msg, "%s", body);
+ res |= ast_msg_set_context(msg, "%s", smsc->context);
+ res |= ast_msg_set_exten(msg, "%s", deliver->destination_addr);
+
+ if (res) {
+ ast_msg_destroy(msg);
+ return;
+ }
+
+#define FILL_MSG_HEADERS(msg, deliver, tmp) \
+ snprintf(tmp, sizeof(tmp), "%d", deliver->data_coding); \
+ ast_msg_set_var(msg, "dcs", tmp); \
+ snprintf(tmp, sizeof(tmp), "%s", deliver->service_type); \
+ ast_msg_set_var(msg, "service_type", tmp); \
+ snprintf(tmp, sizeof(tmp), "%d", deliver->esm_class); \
+ ast_msg_set_var(msg, "esm_class", tmp);
+
+ FILL_MSG_HEADERS(msg, deliver, tmp);
+ ast_msg_set_var(msg, "smpp_type", "MO");
+
+ ast_msg_set_var(msg, "smpp_source", smsc->name);
+
+ ast_msg_queue(msg);
+
+ memset(&sm_resp, 0, sizeof(sm_resp));
+ sm_resp.command_length = 0;
+ sm_resp.command_id = DELIVER_SM_RESP;
+ sm_resp.command_status = ESME_ROK;
+ sm_resp.sequence_number = sequence_number;
+ snprintf((char*)sm_resp.message_id, sizeof(sm_resp.message_id), "%s", "");
+
+ queue_pdu(smsc, DELIVER_SM_RESP, (void *)&sm_resp);
+
+ } else if ((uint32_t)submit->command_id == (uint32_t) SUBMIT_SM && submit->command_status == ESME_ROK) {
+ struct ast_msg *msg = ast_msg_alloc();
+ char body[1024];
+ char tmp[1024];
+ char messageid[66];
+ int res;
+ submit_sm_resp_t sm_resp;
+
+ if (!msg) {
+ return;
+ }
+ sequence_number = submit->sequence_number;
+ res = ast_msg_set_to(msg, "%s", submit->destination_addr);
+ res |= ast_msg_set_from(msg, "%s", submit->source_addr);
+ memcpy(body, submit->short_message, submit->sm_length);
+ body[submit->sm_length] = 0;
+ res |= ast_msg_set_body(msg, "%s", body);
+ res |= ast_msg_set_context(msg, "%s", smsc->context);
+ res |= ast_msg_set_exten(msg, "%s", submit->destination_addr);
+ if (res) {
+ ast_msg_destroy(msg);
+ return;
+ }
+
+ FILL_MSG_HEADERS(msg, submit, tmp);
+ ast_msg_set_var(msg, "smpp_type", "MT");
+ ast_msg_set_var(msg, "smpp_message_id", generate_msgid(messageid));
+
+ ast_msg_set_var(msg, "smpp_source", smsc->name);
+
+ ast_msg_queue(msg);
+
+ memset(&sm_resp, 0, sizeof(sm_resp));
+ sm_resp.command_length = 0;
+ sm_resp.command_id = SUBMIT_SM_RESP;
+ sm_resp.command_status = ESME_ROK;
+ sm_resp.sequence_number = sequence_number;
+ snprintf((char*)sm_resp.message_id, sizeof(sm_resp.message_id), "%s", messageid);
+
+ queue_pdu(smsc, SUBMIT_SM_RESP, (void *)&sm_resp);
+ } else if ((uint32_t)enq->command_id == (uint32_t) ENQUIRE_LINK && enq->command_status == ESME_ROK) {
+ enquire_link_resp_t enq_resp;
+
+ sequence_number = enq->sequence_number;
+ memset(&enq_resp, 0, sizeof(enq_resp));
+ enq_resp.command_length = 0;
+ enq_resp.command_id = ENQUIRE_LINK_RESP;
+ enq_resp.command_status = ESME_ROK;
+ enq_resp.sequence_number = sequence_number;
+ queue_pdu(smsc, ENQUIRE_LINK_RESP, (void *)&enq_resp);
+ } else if ((uint32_t)enq_resp->command_id == (uint32_t) ENQUIRE_LINK_RESP && enq_resp->command_status == ESME_ROK) {
+ } else {
+ generic_nack_t nack;
+
+ sequence_number = enq->sequence_number;
+ memset(&nack, 0, sizeof(nack));
+ nack.command_length = 0;
+ nack.command_id = GENERIC_NACK;
+ nack.command_status = ESME_ROK;
+ nack.sequence_number = sequence_number;
+ queue_pdu(smsc, GENERIC_NACK, (void *)&nack);
+ }
+}
+
+static int receive_bind_resp(struct smpp_smsc *smsc)
+{
+ bind_transceiver_resp_t bind_resp;
+
+ memset(&bind_resp, 0, sizeof(bind_resp));
+
+ if (!read_smpp(smsc, &bind_resp)) {
+ ast_log(LOG_WARNING, "Can't get bind response from %s\n", smsc->name);
+ return 1;
+ }
+
+ if((uint32_t)bind_resp.command_id != (uint32_t) BIND_TRANSCEIVER_RESP || bind_resp.command_status != ESME_ROK) {
+ ast_log(LOG_WARNING, "Got incorrect reply to bind req from smsc %s\n", smsc->name);
+ return 1;
+ }
+ return 0;
+}
+
+static struct smpp_smsc* receive_bind(struct newsocket* newsock)
+{
+ struct smpp_smsc *smsc = NULL;
+ unsigned char pdu[2048];
+ unsigned char bPrint[2048];
+ uint32_t pdulen;
+ char *host;
+ int port;
+ int socket;
+ bind_transceiver_t bind;
+ void *unpack = &bind;
+
+ memset(&pdu, 0, sizeof(pdu));
+ host = ast_sockaddr_stringify_addr(&newsock->addr);
+ port = ast_sockaddr_port(&newsock->addr);
+ socket = newsock->socket;
+
+ if ((recv(socket, &pdulen, 4, MSG_PEEK) != 4) ||
+ (recv(socket, pdu, ntohl(pdulen), 0) != ntohl(pdulen))) {
+ ast_log(LOG_WARNING, "smpp read error on new connection %s\n", strerror(errno));
+ return NULL;
+ } else {
+ pdulen = ntohl(pdulen);
+ if (smppDebug) {
+ ast_verb(3,"read bind pdu %d from %s:%d\n", pdulen, host, port);
+ }
+ }
+ if (smpp34_unpack2((void*)unpack, pdu, pdulen)) {
+ ast_log(LOG_WARNING, "Error in smpp34_unpack2():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ return NULL;
+ }
+ if (smppDebug) {
+ if (smpp34_dumpPdu2(bPrint, sizeof(bPrint), (void*)unpack)) {
+ ast_log(LOG_WARNING, "Error in smpp34_dumppdu():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ return NULL;
+ } else {
+ ast_verb(3, "PDU Dump:\n%s\n", bPrint);
+ }
+ }
+
+ if((uint32_t)bind.command_id != (uint32_t) BIND_TRANSCEIVER || bind.command_status != ESME_ROK) {
+ ast_log(LOG_WARNING, "Got incorrect bind req from %s:%d\n", host, port);
+ return NULL;
+ }
+
+ smsc = smsc_list;
+ while(smsc) {
+ if (smsc->esme &&
+ !strcmp((char *)bind.system_id, smsc->system_id) && !strcmp((char *)bind.password, smsc->password) &&
+ !strcmp((char *)bind.system_type, smsc->system_type) &&
+ ((smsc->host[0] == 0) || !strcmp(smsc->host, "0.0.0.0") || !strcmp(smsc->host, "dynamic") ||
+ !strcmp(smsc->host, host))) {
+
+ if (smsc->socket) {
+ ast_log(LOG_WARNING, "ESME %s already connected\n", smsc->name);
+ return NULL;
+ }
+ smsc->socket = socket;
+ smsc->seq = 1;
+ return smsc;
+ }
+ smsc = smsc->next;
+ }
+
+ ast_verb(2, "Can't bind %s/%s/%s from %s:%d\n", bind.system_id, bind.password, bind.system_type, host, port);
+
+ return NULL;
+}
+
+static struct smpp_buff* queue_pdu(struct smpp_smsc *smsc, uint32_t cmd, void *unpack)
+{
+ unsigned char pdu[2048];
+ unsigned char bPrint[2048];
+ int pdulen;
+ struct smpp_buff* smpp_buf;
+
+ int ret;
+
+ ret = smpp34_pack(cmd, pdu, sizeof(pdu), &pdulen, unpack);
+ if (ret) {
+ ast_log(LOG_WARNING, "Error in smpp34_pack():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ return NULL;
+ }
+ if (!(smpp_buf = ast_calloc(1,sizeof(struct smpp_buff)))) {
+ ast_log(LOG_ERROR, "can't alloc smpp queue buffer for smsc %s\n", smsc->name);
+ return NULL;
+ }
+ if (!(smpp_buf->pdubuf = ast_calloc(1,pdulen))) {
+ free(smpp_buf);
+ ast_log(LOG_ERROR, "can't alloc smpp queue buffer for smsc %s\n", smsc->name);
+ return NULL;
+ }
+
+ smpp_buf->pdulen = pdulen;
+ memcpy(smpp_buf->pdubuf, pdu, pdulen);
+
+ if (smppDebug) {
+ if (smpp34_dumpPdu2(bPrint, sizeof(bPrint), (void*)unpack)) {
+ ast_log(LOG_WARNING, "Error in smpp34_dumpbuf():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ } else {
+ ast_verb(3, "Queue PDU to %s:\n%s\n", smsc->name, bPrint);
+ }
+ }
+ AST_LIST_LOCK(&smsc->outq);
+ AST_LIST_INSERT_TAIL(&smsc->outq, smpp_buf, next);
+ AST_LIST_UNLOCK(&smsc->outq);
+ return smpp_buf;
+}
+
+static int write_smpp(struct smpp_smsc *smsc, struct smpp_buff *smpp_buf)
+{
+ unsigned char bPrint[2048];
+
+ if (smppDebug) {
+ if (smpp34_dumpBuf(bPrint, sizeof(bPrint), smpp_buf->pdubuf, smpp_buf->pdulen)) {
+ ast_log(LOG_WARNING, "Error in smpp34_dumpbuf():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ } else {
+ ast_verb(3, "Sending to %s pdu :\n%s\n", smsc->name, bPrint);
+ }
+ }
+ if (write(smsc->socket, smpp_buf->pdubuf, smpp_buf->pdulen) < 0) {
+ ast_log(LOG_WARNING, "smpp write error %s to smsc %s\n", strerror(errno),
+ smsc->name);
+ return 1;
+ }
+ return 0;
+}
+
+static struct smpp_buff* send_enquire_link(struct smpp_smsc *smsc)
+{
+ enquire_link_t enq;
+
+ memset(&enq, 0, sizeof(enq));
+ enq.command_length = 0;
+ enq.command_id = ENQUIRE_LINK;
+ enq.command_status = ESME_ROK;
+ enq.sequence_number = smsc->seq++;
+
+ return queue_pdu(smsc, ENQUIRE_LINK, (void *)&enq);
+}
+
+static struct smpp_buff* send_bind_resp(struct smpp_smsc *smsc)
+{
+ bind_transceiver_resp_t bind_resp;
+
+ memset(&bind_resp, 0, sizeof(bind_resp));
+ bind_resp.command_length = 0;
+ bind_resp.command_id = BIND_TRANSCEIVER_RESP;
+ bind_resp.command_status = ESME_ROK;
+ bind_resp.sequence_number = smsc->seq++;
+ snprintf((char*)bind_resp.system_id, sizeof(bind_resp.system_id), "%s", system_id);
+
+ return queue_pdu(smsc, BIND_TRANSCEIVER_RESP, (void *)&bind_resp);
+}
+
+static int send_bind(struct smpp_smsc *smsc)
+{
+ bind_transceiver_t bind;
+ unsigned char pdu[2048];
+ unsigned char bPrint[2048];
+ int pdulen;
+ int ret;
+
+ memset(&bind, 0, sizeof(bind));
+ memset(&pdu, 0, sizeof(pdu));
+
+ bind.command_length = 0;
+ bind.command_id = BIND_TRANSCEIVER;
+ bind.command_status = ESME_ROK;
+ bind.sequence_number = smsc->seq++;
+
+ snprintf((char*)bind.system_id, sizeof(bind.system_id), "%s", smsc->system_id);
+ snprintf((char*)bind.password, sizeof(bind.password), "%s", smsc->password);
+ snprintf((char*)bind.system_type, sizeof(bind.system_type), "%s", smsc->system_type);
+ bind.interface_version = 0x34;
+ bind.addr_ton = 2;
+ bind.addr_npi = 1;
+ snprintf((char*)bind.address_range, sizeof(bind.address_range), "%s", "");
+
+ ret = smpp34_pack(BIND_TRANSCEIVER, pdu, sizeof(pdu), &pdulen, (void *)&bind);
+ if (ret) {
+ ast_log(LOG_WARNING, "Error in smpp34_pack():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ return 1;
+ }
+ if (smppDebug) {
+ if (smpp34_dumpBuf(bPrint, sizeof(bPrint), pdu, pdulen)) {
+ ast_log(LOG_WARNING, "Error in smpp34_dumpbuf():%d:\n%s\n",
+ smpp34_errno, smpp34_strerror);
+ } else {
+ ast_verb(3, "PDU Dump:\n%s\n", bPrint);
+ }
+ }
+ if (write(smsc->socket, pdu, pdulen) < 0) {
+ ast_log(LOG_WARNING, "smpp write error %s to smsc %s\n", strerror(errno),
+ smsc->name);
+ return 1;
+ }
+ return 0;
+}
+
+// Internal struct processing
+
+static void* smsc_thread(void *dummy)
+{
+ struct smpp_smsc* smsc = (struct smpp_smsc *) dummy;
+ struct ast_sched_context *sched;
+
+ struct pollfd pfds;
+ int to;
+ int nfds;
+
+ struct smpp_buff *freedbuf, *smpp_buf;
+
+ unsigned char unpack[2048];
+
+ if (!(sched = ast_sched_context_create())) {
+ ast_log(LOG_ERROR, "Unable to create schedule context on smsc %s\n", smsc->name);
+ return NULL;
+ }
+
+ while (!smsc->stop) {
+ if (!smsc->socket) {
+ smsc->socket = smsc_connect(smsc);
+
+ if (!smsc->socket) {
+ sleep(12); // wait to reconnect to smsc
+ pthread_testcancel();
+ continue;
+ }
+ if (send_bind(smsc) || receive_bind_resp(smsc)) {
+ close(smsc->socket);
+ smsc->socket = 0;
+ sleep(12);
+ pthread_testcancel();
+ continue; // reconnect if bind was unsuccessfull
+ }
+ }
+
+
+
+ nfds = 0;
+ if (smsc->socket) {
+ pfds.fd = smsc->socket;
+ pfds.events = POLLIN;
+ nfds += 1;
+ if (!AST_LIST_EMPTY(&smsc->outq)) {
+ pfds.events |= POLLOUT;
+ }
+ }
+ // to = (smsc->enquire > 0) ? smsc->enquire * 1000 : 12000;
+ to = 300;
+
+ if (ast_poll(&pfds, nfds, to) == -1) {
+ if (smsc->socket) {
+ ast_log(LOG_WARNING, "smsc %s poll error, closing connection\n", smsc->name);
+ close(smsc->socket);
+ smsc->socket = 0;
+ continue;
+ }
+ }
+
+ if (pfds.revents & POLLIN) {
+ memset(unpack, 0, sizeof(unpack));
+ if (!read_smpp(smsc, unpack)) {
+ ast_log(LOG_WARNING, "failed to read pdu from smsc %s\n", smsc->name);
+ close(smsc->socket);
+ pthread_testcancel();
+ smsc->socket = 0;
+ continue; // reconnect if receive was unsuccessfull
+ } else {
+ process_pdu(smsc, unpack);
+ }
+ } else {
+ if (smsc->enquire && time(NULL) - smsc->lastenq >= smsc->enquire) {
+ if (!(smpp_buf = send_enquire_link(smsc))) {
+ close(smsc->socket);
+ smsc->socket = 0;
+ pthread_testcancel();
+ sleep(12);
+ continue;
+ }
+ smsc->lastenq = time(NULL);
+ }
+ }
+
+ if ((pfds.revents & POLLOUT)) {
+ AST_LIST_LOCK(&smsc->outq);
+ if (!AST_LIST_EMPTY(&smsc->outq)) {
+ if (write_smpp(smsc, AST_LIST_FIRST(&smsc->outq))) {
+ close(smsc->socket);
+ pthread_testcancel();
+ smsc->socket = 0;
+ AST_LIST_UNLOCK(&smsc->outq);
+ continue;
+ } else {
+ freedbuf = AST_LIST_REMOVE_HEAD(&smsc->outq, next);
+ if (freedbuf->pdubuf) {
+ free(freedbuf->pdubuf);
+ }
+ free(freedbuf);
+ }
+ }
+ AST_LIST_UNLOCK(&smsc->outq);
+ }
+ if ((pfds.revents & POLLERR)) {
+ close(smsc->socket);
+ pthread_testcancel();
+ smsc->socket = 0;
+ }
+ pthread_testcancel();
+ }
+
+ if (smsc->socket) {
+ close(smsc->socket);
+ }
+ ast_sched_context_destroy(sched);
+ if (smppDebug) {
+ ast_verbose("smsc thread stop for %s\n", smsc->name);
+ }
+ smsc->stop = 0;
+ return NULL;
+}
+
+
+static void* esme_thread(void *dummy)
+{
+ struct smpp_smsc* smsc;
+ struct ast_sched_context *sched;
+
+ struct pollfd pfds;
+ int to;
+ int nfds;
+
+ struct smpp_buff *freedbuf;
+
+ unsigned char unpack[2048];
+
+ struct newsocket newsock = *(struct newsocket *)dummy;
+ free(dummy);
+
+ if (smppDebug) {
+ ast_verb(2, "Start esme thread on socket %d\n", newsock.socket);
+ }
+
+ if (!(smsc = receive_bind(&newsock))) {
+ close(newsock.socket);
+ return NULL;
+ }
+
+ if (!send_bind_resp(smsc)) {
+ ast_log(LOG_WARNING, "Can't send bind response to esme %s\n", smsc->name);
+ close(smsc->socket);
+ return NULL;
+ }
+
+ if (smppDebug) {
+ ast_verb(2,"Esme thread for %s started\n", smsc->name);
+ }
+
+ if (!(sched = ast_sched_context_create())) {
+ ast_log(LOG_ERROR, "Unable to create schedule context on smsc %s\n", smsc->name);
+ close(smsc->socket);
+ return NULL;
+ }
+
+ smsc->monitor = pthread_self();
+
+ while (!smsc->stop) {
+ nfds = 0;
+ pfds.fd = smsc->socket;
+ pfds.events = POLLIN;
+ nfds += 1;
+ if (!AST_LIST_EMPTY(&smsc->outq)) {
+ pfds.events |= POLLOUT;
+ }
+ to = 300;
+
+ if (ast_poll(&pfds, nfds, to) == -1) {
+ if (smsc->socket) {
+ ast_log(LOG_WARNING, "smsc %s poll error, closing connection\n", smsc->name);
+ close(smsc->socket);
+ smsc->socket = 0;
+ continue;
+ }
+ }
+
+ if (pfds.revents & POLLIN) {
+ memset(unpack, 0, sizeof(unpack));
+ if (!read_smpp(smsc, unpack)) {
+ ast_log(LOG_WARNING, "failed to read pdu from smsc %s\n", smsc->name);
+ close(smsc->socket);
+ pthread_testcancel();
+ smsc->socket = 0;
+ continue; // reconnect if receive was unsuccessfull
+ } else {
+ process_pdu(smsc, unpack);
+ }
+ }
+
+ if ((pfds.revents & POLLOUT)) {
+ AST_LIST_LOCK(&smsc->outq);
+ if (!AST_LIST_EMPTY(&smsc->outq)) {
+ if (write_smpp(smsc, AST_LIST_FIRST(&smsc->outq))) {
+ close(smsc->socket);
+ pthread_testcancel();
+ smsc->socket = 0;
+ AST_LIST_UNLOCK(&smsc->outq);
+ continue;
+ } else {
+ freedbuf = AST_LIST_REMOVE_HEAD(&smsc->outq, next);
+ if (freedbuf->pdubuf) {
+ free(freedbuf->pdubuf);
+ }
+ free(freedbuf);
+ }
+ }
+ AST_LIST_UNLOCK(&smsc->outq);
+ }
+ if ((pfds.revents & POLLERR)) {
+ close(smsc->socket);
+ pthread_testcancel();
+ smsc->socket = 0;
+ }
+ pthread_testcancel();
+ }
+
+ if (smsc->socket) {
+ close(smsc->socket);
+ }
+ ast_sched_context_destroy(sched);
+ if (smppDebug) {
+ ast_verbose("esme thread stop for %s\n", smsc->name);
+ }
+ smsc->stop = 0;
+ return NULL;
+}
+
+static void* smpp_listener(void *dummy)
+{
+ pthread_attr_t attr;
+ pthread_t monitor;
+ struct ast_sockaddr addr;
+ struct newsocket *newsock;
+ struct pollfd pfds;
+ int to;
+ int nfds;
+ int on;
+
+
+ smppSocket = socket(AF_INET, SOCK_STREAM, 0);
+ smpplistener_stop = 0;
+ if (smppSocket < 0) {
+ ast_log(LOG_WARNING, "Can't create SMPP listener socket\n");
+ return NULL;
+ }
+ on = 1;
+ setsockopt(smppSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
+ ast_sockaddr_set_port(&bindaddr, bindport);
+ if (ast_bind(smppSocket, &bindaddr) < 0) {
+ ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n", ast_sockaddr_stringify_addr(&bindaddr), ast_sockaddr_port(&bindaddr),
+ strerror(errno));
+ listener = AST_PTHREADT_NULL;
+ return NULL;
+ }
+ if (listen(smppSocket, 1024)) {
+ ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n", ast_sockaddr_stringify_addr(&bindaddr), ast_sockaddr_port(&bindaddr),
+ strerror(errno));
+ listener = AST_PTHREADT_NULL;
+ return NULL;
+ }
+
+ if (smppDebug) {
+ ast_verb(2, "SMPP listening on %s:%d\n",
+ ast_sockaddr_stringify_addr(&bindaddr), ast_sockaddr_port(&bindaddr));
+
+ }
+
+ while (!smpplistener_stop) {
+ nfds = 0;
+ pfds.fd = smppSocket;
+ pfds.events = POLLIN;
+ nfds += 1;
+ to = 30000;
+ if (ast_poll(&pfds, nfds, to) == -1) {
+ ast_log(LOG_WARNING, "Listener error on %s:%d: %s\n", ast_sockaddr_stringify_addr(&bindaddr),
+ ast_sockaddr_port(&bindaddr), strerror(errno));
+ break;
+ }
+
+ if (!(pfds.revents & POLLIN)) {
+ continue;
+ }
+ newsock = ast_calloc(1, sizeof(struct newsocket));
+ if (!(newsock->socket = ast_accept (smppSocket, &newsock->addr))) {
+ ast_log(LOG_WARNING, "Accept error on %s:%d: %s\n", ast_sockaddr_stringify_addr(&addr),
+ ast_sockaddr_port(&addr), strerror(errno));
+ free(newsock);
+ continue;
+ }
+
+ pthread_attr_init(&attr);
+ if ((errno = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE))) {
+ ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
+ }
+
+ if(ast_pthread_create_detached_background(&monitor, &attr, esme_thread, newsock) < 0) {
+ ast_log(LOG_ERROR, "Unable to start monitor thread for new connection from %s\n",
+ ast_sockaddr_stringify_addr(&addr));
+ }
+
+ pthread_testcancel();
+ }
+ if (smppDebug) {
+ ast_verb(2, "SMPP listener stop\n");
+ }
+ smpplistener_stop = 0;
+ close(smppSocket);
+ return NULL;
+}
+
+
+static void start_monitor_threads(void)
+{
+ struct smpp_smsc* smsc;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ if ((errno = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE))) {
+ ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
+ }
+ ast_mutex_lock(&smpp_lock);
+ smsc = smsc_list;
+ while (smsc) {
+ if (!smsc->esme) {
+ if(ast_pthread_create_detached_background(&smsc->monitor, &attr, smsc_thread, smsc) < 0) {
+ ast_log(LOG_ERROR, "Unable to start monitor thread for smsc %s\n", smsc->name);
+ }
+ }
+ smsc = smsc->next;
+ }
+
+ pthread_attr_init(&attr);
+ if ((errno = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE))) {
+ ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
+ }
+ if (ast_pthread_create_detached_background(&listener, &attr, smpp_listener, NULL) < 0) {
+ ast_log(LOG_ERROR, "Can't start smpp listener thread\n");
+ }
+ ast_mutex_unlock(&smpp_lock);
+}
+
+static void stop_monitor_threads(void)
+{
+ struct smpp_smsc *smsc;
+ ast_mutex_lock(&smpp_lock);
+ smsc = smsc_list;
+ while (smsc) {
+ if (smsc->monitor != AST_PTHREADT_NULL) {
+ if (smsc->monitor != AST_PTHREADT_STOP) {
+ smsc->stop = 1;
+ if (smppDebug) {
+ ast_verbose("stopping monitor on %s %s\n", (smsc->esme) ? "esme" : "smsc",
+ smsc->name);
+ }
+ pthread_kill(smsc->monitor, SIGURG);
+ while (smsc->stop) {
+ sleep(1);
+ }
+ smsc->monitor = AST_PTHREADT_NULL;
+ }
+ }
+ smsc = smsc->next;
+ }
+
+ if (listener != AST_PTHREADT_NULL) {
+ if (listener != AST_PTHREADT_STOP) {
+ smpplistener_stop = 1;
+ if (smppDebug) {
+ ast_verbose("stopping smpp listener thread\n");
+ }
+ pthread_kill(listener, SIGURG);
+ while (smpplistener_stop) {
+ sleep(1);
+ }
+ listener = AST_PTHREADT_NULL;
+ ast_verbose("listener terminated\n");
+ }
+ }
+
+ ast_mutex_unlock(&smpp_lock);
+}
+
+static struct smpp_smsc* build_smsc(const char *name, struct ast_variable *v, unsigned int esme)
+{
+ struct smpp_smsc *smsc = NULL;
+ if (smppDebug) {
+ ast_verbose("--- build_smsc %s\n", name);
+ }
+
+ smsc = ast_calloc(1,sizeof(struct smpp_smsc));
+ smsc->port = 2775;
+ if (smsc) {
+ ast_copy_string(smsc->name, name, sizeof(smsc->name) - 1);
+ ast_copy_string(smsc->system_id, name, sizeof(smsc->system_id) - 1);
+ while (v) {
+ if (!strcasecmp(v->name, "system_id")) {
+ ast_copy_string(smsc->system_id, v->value, sizeof(smsc->system_id) - 1);
+ } else if (!strcasecmp(v->name, "password")) {
+ ast_copy_string(smsc->password, v->value, sizeof(smsc->password) - 1);
+ } else if (!strcasecmp(v->name, "system_type")) {
+ ast_copy_string(smsc->system_type, v->value, sizeof(smsc->system_type) - 1);
+ } if (!strcasecmp(v->name, "host") || (!strcasecmp(v->name, "ip"))) {
+ if (ast_parse_arg(v->value, PARSE_ADDR, &smsc->addr)) {
+ ast_log(LOG_WARNING, "Invalid smsc address: %s\n", v->value);
+ free(smsc);
+ smsc = NULL;
+ break;
+ } else {
+ ast_copy_string(smsc->host, v->value, sizeof(smsc->host) - 1);
+ }
+ } else if (!strcasecmp(v->name, "port")) {
+ if ((smsc->port = atoi(v->value)) < 0) {
+ ast_log(LOG_ERROR, "Invalid smsc port: %s\n", v->value);
+ smsc = NULL;
+ break;
+ }
+ } else if (!strcasecmp(v->name, "enquire-link-interval")) {
+ smsc->enquire = atoi(v->value);
+ if (smsc->enquire <= 0) {
+ smsc->enquire = 0;
+ }
+ } else if (!strcasecmp(v->name, "context")) {
+ ast_copy_string(smsc->context, v->value, sizeof(smsc->context));
+ }
+ v = v->next;
+ }
+ }
+
+ if (smsc) {
+ if (esme) {
+ smsc->esme = 1;
+ }
+ smsc->monitor = AST_PTHREADT_NULL;
+ } else {
+ ast_verbose("%s %s isn't configured\n", (esme) ? "esme" : "smsc", name);
+ return NULL;
+ }
+
+ AST_LIST_HEAD_INIT(&smsc->outq);
+ AST_LIST_HEAD_INIT(&smsc->respq);
+ ast_mutex_init(&smsc->lock);
+ if (smppDebug) {
+ ast_verbose("+++ build_smsc %s %s\n", (esme) ? "esme" : "smsc", name);
+ }
+ return smsc;
+}
+
+static struct smpp_smsc* find_smsc(char *name)
+{
+ struct smpp_smsc* smsc = smsc_list;
+ ast_mutex_lock(&smpp_lock);
+ while(smsc) {
+ if (!strcasecmp(smsc->name, name)) {
+ ast_mutex_unlock(&smpp_lock);
+ return smsc;
+ }
+ smsc = smsc->next;
+ }
+ ast_mutex_unlock(&smpp_lock);
+ return NULL;
+}
+
+static void destroy_smscs(void)
+{
+ struct smpp_smsc* smsc = smsc_list, *prev = NULL;
+ struct respwait *resp;
+ struct smpp_buff* freedbuf;
+ ast_mutex_lock(&smpp_lock);
+ while(smsc) {
+ prev = smsc;
+ smsc = smsc->next;
+ if (smppDebug) {
+ ast_verbose("destroying smsc %s\n", prev->name);
+ }
+ ast_mutex_lock(&prev->lock);
+
+ AST_LIST_LOCK(&prev->outq);
+ while (!AST_LIST_EMPTY(&prev->outq)) {
+ freedbuf = AST_LIST_REMOVE_HEAD(&prev->outq, next);
+ if (freedbuf->pdubuf) {
+ free(freedbuf->pdubuf);
+ }
+ free(freedbuf);
+ }
+ AST_LIST_UNLOCK(&prev->outq);
+ AST_LIST_HEAD_DESTROY(&prev->outq);
+
+ AST_LIST_LOCK(&prev->respq);
+ while (!AST_LIST_EMPTY(&prev->respq)) { // unitl all msg_send threads aren't finished
+ resp = AST_LIST_REMOVE_HEAD(&prev->respq, next);
+ ast_mutex_lock(&resp->lock);
+ resp->delivered = 0;
+ ast_mutex_unlock(&resp->lock);
+ ast_cond_signal(&resp->cond);
+ ast_mutex_lock(&resp->lock);
+ }
+ AST_LIST_UNLOCK(&prev->respq);
+ AST_LIST_HEAD_DESTROY(&prev->respq);
+
+ ast_mutex_unlock(&prev->lock);
+ ast_mutex_destroy(&prev->lock);
+ free(prev);
+ }
+ smsc_list = NULL;
+ ast_mutex_unlock(&smpp_lock);
+}
+
+
+// Asterisk msg and config processling
+
+static int smpp_msg_send(const struct ast_msg *msg, const char *to, const char *from)
+{
+ char *tosme, *tonum;
+ char tmp[1024];
+ struct smpp_smsc* smsc;
+ struct ast_msg *message;
+ const char *body;
+ struct respwait *resp;
+ struct timespec ts;
+ struct timeval tv;
+ int ret;
+ uint32_t sequence_number;
+
+ void *unpack;
+
+ const char *var, *val;
+ struct ast_msg_var_iterator *iter;
+
+ message = (struct ast_msg *)msg;
+ body = ast_msg_get_body(msg);
+
+ if (!strncasecmp(to, "smpp:", strlen("smpp:"))) {
+ to += strlen("smpp:");
+ }
+
+ strncpy(tmp, to, strlen(to));
+ if (strchr(tmp, '@')) {
+ tosme = strchr(tmp, '@');
+ *tosme = 0;
+ tosme++;
+ tonum = tmp;
+
+ } else if (strchr(tmp, '/')) {
+ tonum = strchr(tmp, '/');
+ *tonum = 0;
+ tonum++;
+ tosme = tmp;
+ } else {
+ ast_log(LOG_ERROR, "Invalid SMPP uri to send msg %s\n", to);
+ return -1;
+ }
+ if (!(smsc = find_smsc(tosme))) {
+ ast_log(LOG_ERROR, "Can't find SME %s\n", to);
+ return -1;
+ }
+
+ ast_mutex_lock(&smsc->lock);
+ if (smsc->socket == 0) {
+ ast_log(LOG_ERROR, "Can't send msg to %s because not connected\n", to);
+ ast_mutex_unlock(&smsc->lock);
+ return -1;
+ }
+
+// get message custom variables
+
+ for (iter = ast_msg_var_iterator_init(msg); ast_msg_var_iterator_next(msg, iter, &var, &val);
+ ast_msg_var_unref_current(iter)) {
+ }
+ ast_msg_var_iterator_destroy(iter);
+
+ if (!smsc->esme) {
+ submit_sm_t submit;
+ memset(&submit, 0, sizeof(submit));
+ submit.command_length = 0;
+ submit.command_id = SUBMIT_SM;
+ submit.command_status = ESME_ROK;
+ submit.sequence_number = sequence_number = smsc->seq++;
+
+#define FILL_SMPP_HEADERS(message, submit) \
+ snprintf((char*)submit.service_type, sizeof(submit.service_type), "%s", \
+ (ast_msg_get_var(message, "service_type")) ? ast_msg_get_var(message, "service_type") : ""); \
+ if(ast_msg_get_var(message, "dcs")) { \
+ submit.data_coding = atoi(ast_msg_get_var(message, "dcs")); \
+ } \
+ if(ast_msg_get_var(message, "esm_class")) { \
+ submit.esm_class = atoi(ast_msg_get_var(message, "esm_class")); \
+ }
+
+ FILL_SMPP_HEADERS(message, submit);
+
+ submit.source_addr_ton = 0;
+ submit.source_addr_npi = 0;
+ submit.dest_addr_ton = 0;
+ submit.dest_addr_npi = 0;
+
+ snprintf((char*)submit.source_addr, sizeof(submit.source_addr), "%s", /* (from) ? */ from /*: msg->from */);
+ snprintf((char*)submit.destination_addr, sizeof(submit.destination_addr), "%s", /* (to) ? */ tonum /* : msg->to */);
+
+ submit.esm_class = 0;
+ submit.protocol_id = 0;
+ submit.priority_flag = 0;
+ memset(submit.schedule_delivery_time,0,sizeof(submit.schedule_delivery_time));
+ memset(submit.validity_period,0,sizeof(submit.validity_period));
+ submit.registered_delivery = 0;
+ submit.replace_if_present_flag = 0;
+
+ submit.data_coding = 0;
+ submit.sm_default_msg_id = 0;
+ submit.sm_length = strlen(body);
+ memcpy(submit.short_message, body, (strlen(body) < 254) ? strlen(body) : 254);
+ unpack = &submit;
+ } else {
+ deliver_sm_t deliver;
+ memset(&deliver, 0, sizeof(deliver));
+ deliver.command_length = 0;
+ deliver.command_id = DELIVER_SM;
+ deliver.command_status = ESME_ROK;
+ deliver.sequence_number = sequence_number = smsc->seq++;
+
+ FILL_SMPP_HEADERS(message, deliver);
+
+ deliver.source_addr_ton = 0;
+ deliver.source_addr_npi = 0;
+ deliver.dest_addr_ton = 0;
+ deliver.dest_addr_npi = 0;
+
+ snprintf((char*)deliver.source_addr, sizeof(deliver.source_addr), "%s", /* (from) ? */ from /*: msg->from */);
+ snprintf((char*)deliver.destination_addr, sizeof(deliver.destination_addr), "%s", /* (to) ? */ tonum /* : msg->to */);
+
+ deliver.esm_class = 0;
+ deliver.protocol_id = 0;
+ deliver.priority_flag = 0;
+ memset(deliver.schedule_delivery_time,0,sizeof(deliver.schedule_delivery_time));
+ memset(deliver.validity_period,0,sizeof(deliver.validity_period));
+ deliver.registered_delivery = 0;
+ deliver.replace_if_present_flag = 0;
+
+ deliver.data_coding = 0;
+ deliver.sm_default_msg_id = 0;
+ deliver.sm_length = strlen(body);
+ memcpy(deliver.short_message, body, (strlen(body) < 254) ? strlen(body) : 254);
+ unpack = &deliver;
+ }
+
+ if (!(resp = ast_calloc(1, sizeof(struct respwait))) ) {
+ ast_log(LOG_WARNING, "Can't alloc response wait data\n");
+ ast_mutex_unlock(&smsc->lock);
+ return -1;
+ }
+ ast_mutex_init(&resp->lock);
+ ast_cond_init(&resp->cond, NULL);
+ ast_mutex_lock(&resp->lock);
+ resp->sequence_number = sequence_number;
+
+ AST_LIST_LOCK(&smsc->respq);
+ AST_LIST_INSERT_TAIL(&smsc->respq, resp, next);
+ AST_LIST_UNLOCK(&smsc->respq);
+
+ if (!queue_pdu(smsc, (smsc->esme) ? DELIVER_SM : SUBMIT_SM, unpack)) {
+ ast_log(LOG_WARNING, "Message queue failed %s (%s -> %s)\n", smsc->name, from, to);
+ AST_LIST_LOCK(&smsc->respq);
+ AST_LIST_REMOVE(&smsc->respq, resp, next);
+ AST_LIST_UNLOCK(&smsc->respq);
+ ast_cond_destroy(&resp->cond);
+ ast_mutex_destroy(&resp->lock);
+ free(resp);
+ ast_mutex_unlock(&smsc->lock);
+ return -1;
+ }
+
+ if (smppDebug) {
+ ast_verb(3, "Message queued to %s (%s -> %s)\n", smsc->name, from, to);
+ }
+
+ ret = -1;
+ tv = ast_tvadd(ast_tvnow(), ast_tv(30, 0));
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+
+ ast_mutex_unlock(&smsc->lock);
+
+ if (ast_cond_timedwait(&resp->cond, &resp->lock, &ts) == ETIMEDOUT) {
+ AST_LIST_LOCK(&smsc->respq);
+ AST_LIST_REMOVE(&smsc->respq, resp, next);
+ AST_LIST_UNLOCK(&smsc->respq);
+ } else {
+ if (resp->delivered) {
+ if (resp->message_id[0]) {
+ ast_msg_set_var((struct ast_msg *)msg, "smpp_message_id", (char *)resp->message_id);
+ }
+ ret = 0;
+ }
+ }
+
+ ast_cond_destroy(&resp->cond);
+ ast_mutex_unlock(&resp->lock);
+ ast_mutex_destroy(&resp->lock);
+ free(resp);
+ return ret;
+}
+
+/*!
+ * \brief Load config file
+ * \return 1 on load, 0 file does not exist
+*/
+static int load_config(int reload)
+{
+ struct ast_config *cfg;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+ struct ast_variable *v;
+ const char *cat, *stype;
+
+ struct smpp_smsc* esme;
+ struct smpp_smsc* smsc;
+
+ cfg = ast_config_load(config, config_flags);
+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
+ ast_log(LOG_WARNING, "Could not load smpp.conf\n");
+ return 0;
+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+ return 1;
+ }
+ if (reload) {
+ destroy_smscs();
+ }
+ cat = ast_category_browse(cfg, NULL);
+ while (cat) {
+ if (strcasecmp(cat, "general")) {
+ stype = ast_variable_retrieve(cfg, cat, "type");
+
+ if (!strcmp(stype, "esme")) {
+ esme = build_smsc(cat, ast_variable_browse(cfg, cat), 1);
+ if (esme) {
+ ast_mutex_lock(&smpp_lock);
+ esme->next = smsc_list;
+ smsc_list = esme;
+ ast_mutex_unlock(&smpp_lock);
+ }
+ }
+
+ if (!strcmp(stype, "smsc")) {
+ smsc = build_smsc(cat, ast_variable_browse(cfg, cat), 0);
+ if (smsc) {
+ ast_mutex_lock(&smpp_lock);
+ smsc->next = smsc_list;
+ smsc_list = smsc;
+ ast_mutex_unlock(&smpp_lock);
+ }
+ }
+
+ } else {
+ for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
+ if (!strcasecmp(v->name, "bindaddr")) {
+ if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
+ ast_log(LOG_WARNING, "Invalid bind address: %s\n", v->value);
+ ast_config_destroy(cfg);
+ return 0;
+ }
+ } else if (!strcasecmp(v->name, "port")) {
+ if ((bindport = atoi(v->value)) < 0) {
+ ast_log(LOG_ERROR, "Invalid bind port: %s\n", v->value);
+ ast_config_destroy(cfg);
+ return 0;
+ }
+ } else if (!strcasecmp(v->name, "system_id")) {
+ strncpy(system_id, v->value, sizeof(system_id));
+ }
+ }
+ }
+
+ cat = ast_category_browse(cfg, cat);
+ }
+ ast_config_destroy(cfg);
+ ast_verb(1,"smpp.conf parsed\n");
+ return 1;
+}
+
[... 212 lines stripped ...]
More information about the svn-commits
mailing list