[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