opensmppbox patch
Aarno Syvänen <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi all, I did following changes in opensmppbox - debug functions dumping various structures - one connection to bearerbox, and data structure wrapping it. Opensmppbox identifies itself to bearerbox only once. - original client box i9d (system id) is stored when MT cames and restored when DLR cames - Messages would be added to storgae in all cases, not only when delivery report is asked. Thsi is needed to route acks. - MOs are routed to the client by smwsc id or shortcode, as Kannel does. If use-smppboxid flag is not set, opensmppbox reverts to the current usage. I must change Kannel, too, beacause opensmppbox uses Kannel as a library. Msg id must be stoed and one needs to fethc data by id. Id addtion general msg_add function is needed. These are patches: For opensmppbox: For Kannel Aarno
doc.dump
(application/octet-stream, 3.5 KB) - not displayed
box.diff
(application/octet-stream, 39.3 KB)
--- gw/opensmppbox.c 2011-11-09 09:42:46.000000000 +0100
+++ /Users/aarno/gateway-cvs-110811/gateway/addons/opensmppbox/gw/opensmppbox.c 2011-11-15 10:27:21.000000000 +0100
@@ -118,18 +118,24 @@
static Octstr *smppbox_id;
static Octstr *our_system_id;
-static Octstr *route_to_smsc;
+static Octstr *route_to_smsc = NULL;
static time_t smpp_timeout;
static int systemidisboxcid;
static int enablepam;
static Octstr *pamacl;
+static int usesmppboxid;
+static Dict *client_by_smsc;
+static Dict *client_by_receiver;
+static Dict *client_by_smsc_receiver;
#define TIMEOUT_SECONDS 300
typedef enum { SMPP_LOGIN_NOTLOGGEDIN, SMPP_LOGIN_TRANSMITTER, SMPP_LOGIN_RECEIVER, SMPP_LOGIN_TRANSCEIVER } smpp_login;
+enum {USE_UUID = 0, USE_SMPP_ID = 1};
+
typedef struct _boxc {
Connection *smpp_connection;
Connection *bearerbox_connection;
@@ -150,6 +156,7 @@
Semaphore *pending;
volatile sig_atomic_t alive;
Octstr *boxc_id; /* identifies the connected opensmppbox instance */
+ Octstr *our_id; /* pir own id*/
Octstr *sms_service;
Octstr *route_to_smsc;
Dict *msg_acks;
@@ -173,11 +180,95 @@
} Boxc;
+typedef struct _bbboxc {
+ Connection *bearerbox_connection;
+ volatile sig_atomic_t alive;
+ Dict *msg_acks;
+ Dict *deliver_acks;
+ int mo_recode;
+} BBBoxc;
+
+static BBBoxc *bbbox;
+
+
+static void box_dump_salient(Boxc *boxc)
+{
+ if (!boxc) {
+ debug("opensmppbox", 0, "client pointer points to NULL");
+ return;
+ }
+
+ debug("opensmppbox", 0, "client dump starts");
+ if (boxc->client_ip)
+ debug("opensmppbox", 0, "client ip address was <%s>", octstr_get_cstr(boxc->client_ip));
+ if (boxc->boxc_id)
+ debug("opensmppbox", 0, "client box id (username) was <%s>", octstr_get_cstr(boxc->boxc_id));
+ if (boxc->our_id)
+ debug("opensmppbox", 0, "client id was <%s>", octstr_get_cstr(boxc->our_id));
+ if (boxc->bearerbox_connection) {
+ debug("opensmppbox", 0, "bearerboz connection was");
+ conn_dump_salient(boxc->bearerbox_connection);
+ }
+ if (boxc->smpp_connection) {
+ debug("opensmppbox", 0, "client connection was");
+ conn_dump_salient(boxc->smpp_connection);
+ }
+
+ debug("opensmppbox", 0, "client dump ends");
+}
+
+static void box_list_dump_salient(List *boxes)
+{
+ long i, len;
+ Boxc *box;
+
+ i = 0;
+ len = gwlist_len(boxes);
+ while (i < len) {
+ box = gwlist_get(boxes, i);
+ box_dump_salient(box);
+ ++i;
+ }
+}
+
+void box_id_dict_dump(Dict *box_id_by_msg_id)
+{
+ long i, count;
+ List *ids;
+ Octstr *key;
+ Octstr *box_id;
+
+ gwlib_assert_init();
+
+ debug("opensmppbox", 0, "Dumping box_id dict:");
+ if (!box_id_by_msg_id) {
+ debug("opensmppbox", 0, "box id dict point NULL");
+ return;
+ }
+
+ ids = dict_keys(box_id_by_msg_id);
+ count = dict_key_count(box_id_by_msg_id);
+ for (i = 0; i < count; ++i) {
+ key = gwlist_get(ids, i);
+ box_id = dict_get(box_id_by_msg_id, key);
+ debug("opensmppbox", 0, "Msg id %ld was: ", i);
+ octstr_dump(key, 0);
+ debug("opensmppbox", 0, "Box id %ld was: ", i);
+ octstr_dump(box_id, 0);
+ }
+ debug("opensmppbox", 0, "End of dump.");
+}
+
void smpp_pdu_destroy_item(void *pdu)
{
smpp_pdu_destroy(pdu);
}
+static void shutdown_connection(Connection *conn)
+{
+ conn_destroy(conn);
+}
+
/*
* Use PAM (Pluggable Authentication Module) to check sendsms authentication.
*/
@@ -309,16 +401,20 @@
valid_login:
for (box = 0; box < gwlist_len(all_boxes); box++) {
thisbox = (Boxc *)gwlist_get(all_boxes, box);
- if (octstr_compare(system_type, thisbox->boxc_id) == 0 && (thisbox->login_type == SMPP_LOGIN_TRANSCEIVER || (thisbox->login_type == login_type))) {
- debug("bb.sms.smpp", 0, "opensmppbox[%s]: Multiple login: disconnect.",
+ if (octstr_compare(system_type, thisbox->boxc_id) == 0 && (thisbox->login_type == SMPP_LOGIN_TRANSCEIVER
+ || (thisbox->login_type == login_type))) {
+ debug("opensmppbox", 0, "opensmppbox[%s]: Multiple login: disconnect.",
octstr_get_cstr(thisbox->boxc_id));
thisbox->alive = 0;
#ifdef HAVE_SHUTDOWN_CONNECTION
+ if (!use_smppboxid)
shutdown_connection(thisbox->bearerbox_connection);
shutdown_connection(thisbox->smpp_connection);
#endif
}
}
+ debug("opensmppbox", 0, "Accepted client with box id (username ?) <%s>",
+ octstr_get_cstr(boxc->boxc_id));
return 1;
}
@@ -342,6 +438,12 @@
} while(0)
#endif
+static void dump_pdu_debug(char *msg, Octstr *id, SMPP_PDU *pdu)
+{
+ debug("opensmppbox", 0, "SMPP[%s]: %s", \
+ octstr_get_cstr(id), msg); \
+ smpp_pdu_dump(pdu);
+}
/*
* Converting SMPP timestamp to minutes relative
@@ -396,7 +498,7 @@
localdiff = difftime(gw_mktime(&local), gw_mktime(&tm));
valutc += localdiff;
- debug("sms.smpp",0, "diff between utc and localtime (%d)", localdiff);
+ debug("opensmppbox",0, "diff between utc and localtime (%d)", localdiff);
diff = diff*15*60;
switch(relation) {
case '+':
@@ -421,10 +523,10 @@
return -1;
}
tm = gw_gmtime(valutc);
- debug("sms.smpp",0,"Requested UTC timestamp: %02d-%02d-%02d %02d:%02d:%02d",
+ debug("opensmppbox",0,"Requested UTC timestamp: %02d-%02d-%02d %02d:%02d:%02d",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
- debug("sms.smpp", 0, "requested timestamp in min. (%ld)", (valutc - utc)/60);
+ debug("opensmppbox", 0, "requested timestamp in min. (%ld)", (valutc - utc)/60);
return ceil ( difftime (valutc, utc) / 60 );
}
@@ -440,7 +542,7 @@
/* send to bearerbox */
-static int send_msg(Connection *conn, Boxc *boxconn, Msg *pmsg)
+static int send_msg(Connection *conn, Msg *pmsg)
{
/* Caution: implicit msg_destroy */
write_to_bearerbox_real(conn, pmsg);
@@ -456,7 +558,7 @@
for (pos = 0; pos < gwlist_len(all_boxes); pos++) {
box = (Boxc *)gwlist_get(all_boxes, pos);
- send_msg(box->bearerbox_connection, box, msg);
+ send_msg(box->bearerbox_connection, msg);
}
}
*/
@@ -474,25 +576,25 @@
* Do this even while no opensmppbox-id is given to unlock the sender thread in
* bearerbox.
*/
-static void identify_to_bearerbox(Boxc *conn)
+static void identify_to_bearerbox(Connection *conn, Octstr *our_id)
{
Msg *msg;
msg = msg_create(admin);
msg->admin.command = cmd_identify;
- msg->admin.boxc_id = octstr_duplicate(conn->boxc_id);
- send_msg(conn->bearerbox_connection, conn, msg);
+ msg->admin.boxc_id = octstr_duplicate(our_id);
+ send_msg(conn, msg);
}
/* read from bearerbox */
-static Msg *read_from_box(Connection *conn, Boxc *boxconn)
+static Msg *read_from_box(Connection *conn, int alive)
{
Octstr *pack;
Msg *msg;
pack = NULL;
- while (boxconn->alive) {
+ while (alive) {
switch (read_from_bearerbox_real(conn, &msg, 1.0)) {
case -1:
/* connection to bearerbox lost */
@@ -626,7 +728,7 @@
/* generate 8 character ID, taken from msgid */
static Octstr *generate_smppid(Msg *msg)
{
- char uuidbuf[100];
+ char uuidbuf[UUID_STR_LEN + 1];
Octstr *result;
// gw_assert(msg->type == sms); // we segfault on this
@@ -673,7 +775,7 @@
if (*pdu == NULL) {
error(0, "opensmppbox[%s]: PDU unpacking failed.",
octstr_get_cstr(box->boxc_id));
- debug("bb.sms.smpp", 0, "opensmppbox[%s]: Failed PDU omitted.",
+ debug("opensmppbox", 0, "opensmppbox[%s]: Failed PDU omitted.",
octstr_get_cstr(box->boxc_id));
/* octstr_dump(os, 0); */
octstr_destroy(os);
@@ -684,6 +786,35 @@
return 1;
}
+ /* To route to the original client, we restore the original
+ * box id (i.e., essentially the username). */
+static void restore_box_id(Msg *msg, Octstr *msgid)
+{
+ if (msg->sms.sms_type == report_mo) {
+ List *parts = octstr_split(msg->sms.dlr_url, octstr_imm(";"));
+ Octstr *msgid = gwlist_extract_first(parts);
+ Msg *dlr = dlr_find_by_id(msgid, USE_SMPP_ID);
+ Octstr *boxid = NULL;
+ if (dlr && dlr->sms.boxc_id)
+ boxid = octstr_duplicate(dlr->sms.boxc_id);
+
+ if (boxid) {
+ octstr_destroy(msg->sms.boxc_id);
+ msg->sms.boxc_id = octstr_duplicate(boxid);
+ }
+
+ octstr_destroy(boxid);
+ msg_destroy(dlr);
+ }
+ /* MOs are routed separately, using smsc_id */
+}
+
+static void change_box_id(Msg *msg)
+{
+ octstr_destroy(msg->sms.boxc_id);
+ msg->sms.boxc_id = octstr_duplicate(smppbox_id);
+}
+
static List *msg_to_pdu(Boxc *box, Msg *msg)
{
SMPP_PDU *pdu, *pdu2;
@@ -717,7 +848,7 @@
if(box->source_addr_ton > -1 && box->source_addr_npi > -1) {
pdu->u.deliver_sm.source_addr_ton = box->source_addr_ton;
pdu->u.deliver_sm.source_addr_npi = box->source_addr_npi;
- debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced source addr ton = %ld, source add npi = %ld",
+ debug("opensmppbox", 0, "SMPP[%s]: Manually forced source addr ton = %ld, source add npi = %ld",
octstr_get_cstr(box->boxc_id), box->source_addr_ton,
box->source_addr_npi);
} else {
@@ -749,7 +880,7 @@
if (box->dest_addr_ton > -1 && box->dest_addr_npi > -1) {
pdu->u.deliver_sm.dest_addr_ton = box->dest_addr_ton;
pdu->u.deliver_sm.dest_addr_npi = box->dest_addr_npi;
- debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced dest addr ton = %ld, dest add npi = %ld",
+ debug("opensmppbox", 0, "SMPP[%s]: Manually forced dest addr ton = %ld, dest add npi = %ld",
octstr_get_cstr(box->boxc_id), box->dest_addr_ton,
box->dest_addr_npi);
} else {
@@ -771,6 +902,7 @@
octstr_len(pdu->u.deliver_sm.source_addr) > 20) {
smpp_pdu_destroy(pdu);
gwlist_destroy(pdulist, NULL);
+ warning(0, "opensmppbox: msg_to_pdu: address too long, not acceptable");
return NULL;
}
@@ -819,6 +952,7 @@
gwlist_destroy(pdulist, NULL);
octstr_destroy(msgid);
gwlist_destroy(parts, octstr_destroy_item);
+ warning(0, "opensmppbox: msg_to_pdu: no msg corresponding dlr, ignoring");
return NULL;
}
dlvrd = octstr_imm("000");
@@ -901,7 +1035,6 @@
if (box->version > 0x33) {
pdu2->u.deliver_sm.receipted_message_id = octstr_duplicate(msgid2);
pdu2->u.deliver_sm.message_state = dlr_state;
- dict_destroy(pdu2->u.deliver_sm.tlv);
pdu2->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
}
pdu2->u.deliver_sm.short_message = octstr_format("id:%S sub:001 dlvrd:%S submit date:%s done date:%s stat:%S err:%s text:%12s", msgid2, dlvrd, submit_date_c_str, done_date_c_str, dlr_status, err, text);
@@ -1028,7 +1161,7 @@
parts = NULL;
}
- debug("SMPP", 0, "message length %ld, sending %ld message%s",
+ debug("opensmppbox", 0, "message length %ld, sending %ld message%s",
octstr_len(msg->sms.msgdata), msg_count, msg_count == 1 ? "" : "s");
if (parts) {
@@ -1055,7 +1188,6 @@
}
if (box->version > 0x33) {
- dict_destroy(pdu2->u.deliver_sm.tlv);
pdu2->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
}
@@ -1067,7 +1199,6 @@
}
else {
if (box->version > 0x33) {
- dict_destroy(pdu->u.deliver_sm.tlv);
pdu->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
}
@@ -1162,7 +1292,7 @@
if (pdu->u.submit_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) {
int udhl;
udhl = octstr_get_char(msg->sms.msgdata, 0) + 1;
- debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d",
+ debug("opensmppbox",0,"SMPP[%s]: UDH length read as %d",
octstr_get_cstr(box->boxc_id), udhl);
if (udhl > octstr_len(msg->sms.msgdata)) {
error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length "
@@ -1348,7 +1477,7 @@
if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) {
int udhl;
udhl = octstr_get_char(msg->sms.msgdata, 0) + 1;
- debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d",
+ debug("opensmppbox",0,"SMPP[%s]: UDH length read as %d",
octstr_get_cstr(box->boxc_id), udhl);
if (udhl > octstr_len(msg->sms.msgdata)) {
error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length "
@@ -1500,6 +1629,12 @@
int msg_to_send = 1;
List *parts_list = NULL;
char id[UUID_STR_LEN + 1];
+ Connection *bearerbox_connection;
+
+ if (usesmppboxid)
+ bearerbox_connection = bbbox->bearerbox_connection;
+ else
+ bearerbox_connection = box->bearerbox_connection;
dump_pdu("Got PDU:", box->boxc_id, pdu);
switch (pdu->type) {
@@ -1524,7 +1659,8 @@
box->login_type = SMPP_LOGIN_TRANSMITTER;
box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
box->sms_service = octstr_duplicate(pdu->u.bind_transmitter.system_id);
- identify_to_bearerbox(box);
+ if (!usesmppboxid)
+ identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter.sequence_number);
resp->u.bind_transmitter_resp.system_id = octstr_duplicate(our_system_id);
}
@@ -1541,7 +1677,8 @@
box->login_type = SMPP_LOGIN_RECEIVER;
box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
box->sms_service = octstr_duplicate(pdu->u.bind_receiver.system_id);
- identify_to_bearerbox(box);
+ if (!usesmppboxid)
+ identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number);
resp->u.bind_receiver_resp.system_id = octstr_duplicate(our_system_id);
}
@@ -1558,7 +1695,8 @@
box->login_type = SMPP_LOGIN_TRANSCEIVER;
box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
box->sms_service = octstr_duplicate(pdu->u.bind_transceiver.system_id);
- identify_to_bearerbox(box);
+ if (!usesmppboxid)
+ identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
resp = smpp_pdu_create(bind_transceiver_resp, pdu->u.bind_transceiver.sequence_number);
resp->u.bind_transceiver_resp.system_id = octstr_duplicate(our_system_id);
}
@@ -1587,7 +1725,6 @@
check_multipart(box, msg, &msg_to_send, &msg2, &parts_list);
msg->sms.smsc_id = box->route_to_smsc ? octstr_duplicate(box->route_to_smsc) : NULL;
msg->sms.boxc_id = octstr_duplicate(box->boxc_id);
- msg_dump(msg, 0);
resp = smpp_pdu_create(data_sm_resp, pdu->u.data_sm.sequence_number);
msgid = generate_smppid(msg);
msg->sms.dlr_url = octstr_duplicate(msgid);
@@ -1601,15 +1738,23 @@
msg2->sms.dlr_url = concat_msgids(msgid, parts_list);
}
dlr_add(box->boxc_id, msgid, msg2);
+ if (usesmppboxid)
+ change_box_id(msg2);
octstr_destroy(msgid);
octstr_destroy(msg2->sms.service);
msg2->sms.service = hold_service;
}
uuid_unparse(msg2->sms.id, id);
msgid = octstr_create(id);
+ if (!usesmppboxid)
dict_put(box->msg_acks, msgid, resp);
+ else
+ dict_put(bbbox->msg_acks, msgid, resp);
resp = NULL;
- send_msg(box->bearerbox_connection, box, msg2);
+ if (usesmppboxid) {
+ send_msg(bearerbox_connection, msg2);
+ } else
+ send_msg(box->bearerbox_connection, msg2);
if (parts_list) {
/* destroy values */
gwlist_destroy(parts_list, msg_destroy_item);
@@ -1628,11 +1773,16 @@
check_multipart(box, msg, &msg_to_send, &msg2, &parts_list);
msg->sms.smsc_id = box->route_to_smsc ? octstr_duplicate(box->route_to_smsc) : NULL;
msg->sms.boxc_id = octstr_duplicate(box->boxc_id);
- msg_dump(msg, 0);
resp = smpp_pdu_create(submit_sm_resp, pdu->u.submit_sm.sequence_number);
msgid = generate_smppid(msg);
msg->sms.dlr_url = octstr_duplicate(msgid);
- resp->u.submit_sm_resp.message_id = msgid;
+ resp->u.submit_sm_resp.message_id = octstr_duplicate(msgid);
+ /* Note that we add msg to dlr tzble in all cases.
+ * In case of report_mo, need is obvious. In case
+ * of mo, it is needed to route resps. Report mo must be stored before
+ * we gahnge box id.*/
+ if (usesmppboxid)
+ msg_add(msg->sms.boxc_id, msgid, msg);
if (msg_to_send) {
if (DLR_IS_ENABLED(msg2->sms.dlr_mask)) {
hold_service = msg2->sms.service;
@@ -1641,17 +1791,26 @@
if (parts_list) {
msg2->sms.dlr_url = concat_msgids(msgid, parts_list);
}
- dlr_add(box->boxc_id, msgid, msg2);
+ //dlr_add(box->boxc_id, msgid, msg2);
+ if (usesmppboxid)
+ change_box_id(msg2);
octstr_destroy(msgid);
octstr_destroy(msg2->sms.service);
msg2->sms.service = hold_service;
}
uuid_unparse(msg2->sms.id, id);
msgid = octstr_create(id);
+ if (!usesmppboxid) {
dict_put(box->msg_acks, msgid, resp);
+ } else {
+ dict_put(bbbox->msg_acks, msgid, resp);
+ }
octstr_destroy(msgid);
resp = NULL;
- send_msg(box->bearerbox_connection, box, msg2);
+ if (usesmppboxid) {
+ send_msg(bearerbox_connection, msg2);
+ } else
+ send_msg(box->bearerbox_connection, msg2);
if (parts_list) {
/* destroy values */
gwlist_destroy(parts_list, msg_destroy_item);
@@ -1668,7 +1827,11 @@
if (pdu->u.deliver_sm_resp.command_status != 0) {
msg->ack.nack = ack_failed;
}
- send_msg(box->bearerbox_connection, box, msg);
+ if (usesmppboxid) {
+ send_msg(bearerbox_connection, msg);
+ } else {
+ send_msg(box->bearerbox_connection, msg);
+ }
dict_put(box->deliver_acks, msgid, NULL);
}
octstr_destroy(msgid);
@@ -1692,7 +1855,6 @@
smpp_pdu_destroy(pdu);
if (resp != NULL) {
send_pdu(conn, box->boxc_id, resp);
- smpp_pdu_destroy(resp);
}
}
@@ -1712,11 +1874,13 @@
boxc->is_wap = 0;
boxc->load = 0;
boxc->smpp_connection = conn_wrap_fd(fd, ssl);
+ boxc->bearerbox_connection = NULL;
boxc->id = counter_increase(boxid);
boxc->client_ip = octstr_duplicate(ip);
boxc->alive = 1;
boxc->connect_time = time(NULL);
- boxc->boxc_id = NULL;
+ boxc->boxc_id = octstr_duplicate(smppbox_id); /* Fix this one*/
+ boxc->our_id = octstr_duplicate(smppbox_id);
boxc->routable = 0;
boxc->smpp_pdu_counter = counter_create();
boxc->alt_charset = NULL; /* todo: get from config */
@@ -1754,6 +1918,8 @@
conn_destroy(boxc->bearerbox_connection);
if (boxc->boxc_id)
octstr_destroy(boxc->boxc_id);
+ if (boxc->our_id)
+ octstr_destroy(boxc->our_id);
if (boxc->alt_charset)
octstr_destroy(boxc->alt_charset);
counter_destroy(boxc->smpp_pdu_counter);
@@ -1767,6 +1933,31 @@
gw_free(boxc);
}
+static BBBoxc *bbboxc_create(void)
+{
+ BBBoxc *boxc;
+
+ boxc = gw_malloc(sizeof(BBBoxc));
+ boxc->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL);
+ boxc->alive = 1;
+ boxc->mo_recode = 0;
+ boxc->msg_acks = dict_create(1024, smpp_pdu_destroy_item);
+
+ return boxc;
+}
+
+static void bbboxc_destroy(BBBoxc *boxc)
+{
+ if (boxc == NULL)
+ return;
+
+ /* do not do anyhting to dict, it stpres only refrences*/
+ if (boxc->bearerbox_connection)
+ conn_destroy(boxc->bearerbox_connection);
+
+ gw_free(boxc);
+}
+
/* ------------------------------------------------------------------
* SMPP thingies
* ------------------------------------------------------------------
@@ -1816,7 +2007,9 @@
SMPP_PDU *pdu;
long len;
+ error(0, "opensmppbox: smpp_to_bearerbox: thread starts");
box->last_pdu_received = time(NULL);
+
while (smppbox_status == SMPP_RUNNING && box->alive) {
len = 0;
switch (read_pdu(box, conn, &len, &pdu)) {
@@ -1838,16 +2031,117 @@
}
}
#ifdef HAVE_SHUTDOWN_CONNECTION
+ if (!usesmppboxid)
shutdown_connection(box->bearerbox_connection);
#endif
+ error(0, "opensmppbox: smpp_to_bearerbox: thread terminates");
+}
+
+/*
+ * Check do we have a specific route to pass this msg to client-id?
+ */
+static Octstr *find_configured_box_id(Msg *msg)
+{
+ Octstr *boxc_id = NULL;
+ Octstr *r, *s, *rs;
+ /*
+ * Check if we have a "client-route" for this msg.
+ * Where the shortcode route has a higher priority then the smsc-id rule.
+ * Highest priority has the combined <shortcode>:<smsc-id> route.
+ */
+ Octstr *os = octstr_format("%s:%s", octstr_get_cstr(msg->sms.receiver),
+ octstr_get_cstr(msg->sms.smsc_id));
+ s = (msg->sms.smsc_id ? dict_get(client_by_smsc, msg->sms.smsc_id) : NULL);
+ r = (msg->sms.receiver ? dict_get(client_by_receiver, msg->sms.receiver) : NULL);
+ rs = (os ? dict_get(client_by_smsc_receiver, os) : NULL);
+ octstr_destroy(os);
+ if (rs)
+ boxc_id = rs;
+ else if (r)
+ boxc_id = r;
+ else if (s)
+ boxc_id = s;
+
+ return boxc_id;
}
-/* if this login was made as a transmitter, then find the corresponding receiver connection */
-static Boxc *find_receiver_box(Boxc *box)
+static Boxc *find_box_by_id(Octstr *boxc_id)
+{
+ Boxc *thisbox;
+ long retry = 0;
+ long i = 0;
+ long cnt = gwlist_len(all_boxes);
+ while (i < cnt) {
+ thisbox = gwlist_get(all_boxes, i);
+ if (!thisbox || !(thisbox->boxc_id)) {
+ ++i;
+ continue;
+ }
+
+ /* Reject connection that is just sending*/
+ if (thisbox->login_type == SMPP_LOGIN_TRANSMITTER){
+ ++i;
+ continue;
+ }
+
+ /* If the client was not logged in, wait some time*/
+ if (thisbox->login_type == SMPP_LOGIN_NOTLOGGEDIN && retry < 30){
+ ++retry;
+ if (retry < 30)
+ gwthread_sleep(0.1);
+ else
+ ++i;
+ continue;
+ }
+
+ if (boxc_id && octstr_compare(thisbox->boxc_id, boxc_id) == 0) {
+ return thisbox;
+ }
+ ++i;
+ }
+
+ return NULL;
+}
+
+/*
+ * This function is used to route msg acks. Ack's msg id maps ack to original
+ * message. The box id of the original message is used for routing.
+ */
+static Boxc *find_receiver_box_by_msg_id(Octstr *msgid, Msg *msg)
+{
+ Msg *sack;
+ Octstr *boxid = NULL;
+ Boxc *thisbox;
+
+ sack = dlr_find_by_id(msgid, USE_UUID);
+ if (sack)
+ boxid = sack->sms.boxc_id;
+ else
+ return NULL;
+
+ if (boxid)
+ thisbox = find_box_by_id(boxid);
+ else
+ return NULL;
+
+ return thisbox;
+}
+
+/* if this login was made as a transmitter or receiver, then find the corresponding
+ * receiver connection */
+static Boxc *find_receiver_box(Boxc *box, Msg *msg)
{
Boxc *thisbox;
int cnt;
+ Octstr *boxc_id = NULL;
+ int report_mo = 0;
+ int retry = 0;
+ if (usesmppboxid && octstr_len(msg->sms.boxc_id) > 0) {
+ boxc_id = msg->sms.boxc_id;
+ }
+
+ if (!usesmppboxid) {
if (box->login_type == SMPP_LOGIN_RECEIVER || box->login_type == SMPP_LOGIN_TRANSCEIVER) {
return box;
}
@@ -1858,37 +2152,93 @@
}
}
return box;
+ }
+
+ else {
+ /* If we had no clients, wait a little, bearerbox may resend when they be connecting*/
+ report_mo = 1;
+ while (gwlist_len(all_boxes) == 0 && retry < 3) {
+ gwthread_sleep(1);
+ ++retry;
+ }
+
+ if (gwlist_len(all_boxes) == 0 && retry == 3)
+ return NULL;
+
+ if (msg->sms.sms_type == mo) {
+ report_mo = 0;
+ boxc_id = find_configured_box_id(msg);
+ }
+
+ /*
+ * Report_mos will be routed simply by they boxc-id, defined by smsbox-route.
+ * If there is none, a random box is picked.
+ */
+ thisbox = find_box_by_id(boxc_id);
+
+ /* If no box was found and we have MO, pick a random box. In case
+ * of DLR, this is an error. */
+ if (!thisbox && report_mo) {
+ thisbox = gwlist_get(all_boxes, gw_rand() % gwlist_len(all_boxes));
+ return thisbox;
+ }
+
+ return thisbox;
+ }
}
static void bearerbox_to_smpp(void *arg)
{
Msg *msg, *mack;
- Boxc *box = arg;
+ Boxc *box;
+ BBBoxc *bbbox;
SMPP_PDU *pdu;
- List *pdulist;
+ List *pdulist = NULL;
int dreport, errcode;
- Boxc *receiver_box;
+ Boxc *receiver_box = NULL;
char id[UUID_STR_LEN + 1];
Octstr *msgid;
- while (smppbox_status == SMPP_RUNNING && box->alive) {
+ error(0, "opensmppbox: bearerbox_to_smpp: thread starts");
- msg = read_from_box(box->bearerbox_connection, box);
+ if (!usesmppboxid) {
+ box = arg;
+ } else {
+ bbbox = arg;
+ }
+
+ while (smppbox_status == SMPP_RUNNING && (usesmppboxid ? bbbox->alive : box->alive)) {
+
+ if (usesmppboxid)
+ msg = read_from_box(bbbox->bearerbox_connection, bbbox->alive);
+ else
+ msg = read_from_box(box->bearerbox_connection, box->alive);
if (msg == NULL) {
- if ((!box->alive) || conn_eof(box->bearerbox_connection)) {
/* tell opensmppbox to die */
/* the client closes the connection, after that die in receiver */
+ if (usesmppboxid)
+ if (conn_eof(bbbox->bearerbox_connection))
+ bbbox->alive = 0;
+ else
+ if (conn_eof(box->bearerbox_connection))
box->alive = 0;
- }
continue;
}
+ debug("", 0, "we have msg from bearerbox");
+ msg_dump(msg, 0);
if (msg_type(msg) == admin) {
if (msg->admin.command == cmd_shutdown) {
info(0, "Bearerbox told us to die");
+ if (usesmppboxid)
+ bbbox->alive = 0;
+ else
box->alive = 0;
} else if (msg->admin.command == cmd_restart) {
info(0, "Bearerbox told us to restart");
restart = 1;
+ if (usesmppboxid)
+ bbbox->alive = 0;
+ else
box->alive = 0;
}
}
@@ -1901,7 +2251,11 @@
if (msg_type(msg) == ack) {
uuid_unparse(msg->ack.id, id);
msgid = octstr_create(id);
+ if (!usesmppboxid)
pdu = dict_get(box->msg_acks, msgid);
+ else
+ pdu = dict_get(bbbox->msg_acks, msgid);
+
errcode = SMPP_ESME_RMSGQFUL; /* in case we get ack_failed_tmp */
if (pdu) {
switch (msg->ack.nack) {
@@ -1933,26 +2287,38 @@
debug("opensmppbox", 0, "Unknown ack.nack type: %ld.", msg->ack.nack);
break;
}
+ if (!usesmppboxid) {
send_pdu(box->smpp_connection, box->boxc_id, pdu);
dict_put(box->msg_acks, msgid, NULL); /* also destroys item */
+ } else {
+ Boxc *receiver_box = find_receiver_box_by_msg_id(msgid, msg);
+ if (receiver_box) {
+ send_pdu(receiver_box->smpp_connection, receiver_box->boxc_id, pdu);
+ dict_put(receiver_box->msg_acks, msgid, NULL);
+ }
+ //dlr_remove_by_id(msg);
+ }
}
else {
debug("opensmppbox", 0, "Ack to unknown message: %s.", id);
}
octstr_destroy(msgid);
}
- if (!box->alive) {
+ if (usesmppboxid ? !bbbox->alive : !box->alive) {
msg_destroy(msg);
break;
}
if (msg_type(msg) == sms) {
info(0, "We received an SMS message.");
- if (msg->sms.sms_type == report_mo)
+ uuid_unparse(msg->sms.id, id);
+ msgid = octstr_create(id);
+ if (msg->sms.sms_type == report_mo) {
dreport = 1;
- else
+ } else {
dreport = 0;
+ }
/* Recode to iso-8859-1 the MO message if possible */
- if (box->mo_recode && msg->sms.coding == DC_UCS2) {
+ if ((usesmppboxid ? bbbox->mo_recode : box->mo_recode) && msg->sms.coding == DC_UCS2) {
int converted = 0;
Octstr *text;
@@ -2006,7 +2372,10 @@
mack->ack.nack = ack_failed;
mack->ack.time = msg->sms.time;
uuid_copy(mack->ack.id, msg->sms.id);
- send_msg(box->bearerbox_connection, box, mack);
+ if (usesmppboxid) {
+ send_msg(bbbox->bearerbox_connection, mack);
+ } else
+ send_msg(box->bearerbox_connection, mack);
msg_destroy(msg);
continue;
@@ -2017,8 +2386,12 @@
mack->ack.time = msg->sms.time;
uuid_copy(mack->ack.id, msg->sms.id);
- msgid = NULL;
- receiver_box = find_receiver_box(box);
+ if (usesmppboxid) {
+ restore_box_id(msg, msgid);
+ receiver_box = find_receiver_box(NULL, msg);
+ } else
+ receiver_box = find_receiver_box(box, msg);
+ if (receiver_box != NULL)
pdulist = msg_to_pdu(receiver_box, msg);
if (pdulist != NULL) {
while ((pdu = gwlist_extract_first(pdulist)) != NULL) {
@@ -2027,7 +2400,7 @@
msgid = octstr_format("%ld", pdu->u.deliver_sm.sequence_number);
dict_put(receiver_box->deliver_acks, msgid, mack);
}
- send_pdu(receiver_box->smpp_connection, box->boxc_id, pdu);
+ send_pdu(receiver_box->smpp_connection, receiver_box->boxc_id, pdu);
smpp_pdu_destroy(pdu);
}
if (msgid)
@@ -2038,11 +2411,17 @@
/* Send NACK to bearerbox, otherwise message remains in store file. */
warning(0, "msg_to_pdu failed, sending negative ack");
mack->ack.nack = ack_failed;
- send_msg(box->bearerbox_connection, box, mack);
+ if (usesmppboxid) {
+ send_msg(bbbox->bearerbox_connection, mack);
+ } else
+ send_msg(box->bearerbox_connection, mack);
}
}
msg_destroy(msg);
}
+
+ error(0, "opensmppbox: bearerbox_to_smpp: thread terminates");
+ smppbox_status = SMPP_SHUTDOWN;
}
static void run_smppbox(void *arg)
@@ -2057,7 +2436,8 @@
panic(0, "Socket accept failed");
return;
}
- newconn->boxc_id = octstr_duplicate(smppbox_id);
+
+ if (!usesmppboxid) {
newconn->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL /* bb_our_host */);
/* XXX add our_host if required */
if (newconn->bearerbox_connection == NULL) {
@@ -2065,6 +2445,7 @@
boxc_destroy(newconn);
return;
}
+ }
gwlist_append(all_boxes, newconn);
@@ -2083,6 +2464,7 @@
boxc_destroy(newconn);
return;
}
+ if (!usesmppboxid)
bearerbox_to_smpp(newconn);
gwthread_join(sender);
gwlist_delete_equal(all_boxes, newconn);
@@ -2163,7 +2545,7 @@
switch (signum) {
case SIGINT:
-
+ case SIGTERM:
if (smppbox_status == SMPP_RUNNING) {
error(0, "SIGINT received, aborting program...");
smppbox_status = SMPP_SHUTDOWN;
@@ -2198,6 +2580,7 @@
sigaction(SIGQUIT, &act, NULL);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
}
@@ -2210,6 +2593,109 @@
{
}
+/*
+ * Populates the corresponding client_by_foobar dictionary hash tables
+ */
+static void init_client_routes(Cfg *cfg)
+{
+ CfgGroup *grp;
+ List *list, *items;
+ Octstr *client_id, *smsc_ids, *shortcuts;
+ int i, j;
+
+ client_id = smsc_ids = shortcuts = NULL;
+
+ list = cfg_get_multi_group(cfg, octstr_imm("client-route"));
+
+ /* loop multi-group "client-route" */
+ while (list && (grp = gwlist_extract_first(list)) != NULL) {
+ if ((client_id = cfg_get(grp, octstr_imm("client-id"))) == NULL) {
+ grp_dump(grp);
+ panic(0,"'client-route' group without valid 'client-id' directive!");
+ }
+
+ /*
+ * If smsc-id is given, then any message comming from the specified
+ * smsc-id in the list will be routed to this client.
+ * If shortcode is given, then any message with receiver number
+ * matching those will be routed to this client.
+ * If both are given, then only receiver within shortcode originating
+ * from smsc-id list will be routed to this cleint. So if both are
+ * present then this is a logical AND operation.
+ */
+ smsc_ids = cfg_get(grp, octstr_imm("smsc-id"));
+ shortcuts = cfg_get(grp, octstr_imm("shortcode"));
+
+ /* consider now the 3 possibilities: */
+ if (smsc_ids && !shortcuts) {
+ /* smsc-id only, so all MO traffic */
+ items = octstr_split(smsc_ids, octstr_imm(";"));
+ for (i = 0; i < gwlist_len(items); i++) {
+ Octstr *item = gwlist_get(items, i);
+ octstr_strip_blanks(item);
+
+ debug("opensmppbox",0,"Adding client routing to id <%s> for smsc id <%s>",
+ octstr_get_cstr(client_id), octstr_get_cstr(item));
+
+ if (!dict_put_once(client_by_smsc, item, octstr_duplicate(client_id)))
+ panic(0, "Routing for smsc-id <%s> already exists!",
+ octstr_get_cstr(item));
+ }
+ gwlist_destroy(items, octstr_destroy_item);
+ octstr_destroy(smsc_ids);
+ }
+ else if (!smsc_ids && shortcuts) {
+ /* shortcode only, so these MOs from all smscs */
+ items = octstr_split(shortcuts, octstr_imm(";"));
+ for (i = 0; i < gwlist_len(items); i++) {
+ Octstr *item = gwlist_get(items, i);
+ octstr_strip_blanks(item);
+
+ debug("opensmppbox",0,"Adding client routing to id <%s> for receiver no <%s>",
+ octstr_get_cstr(client_id), octstr_get_cstr(item));
+
+ if (!dict_put_once(client_by_receiver, item, octstr_duplicate(client_id)))
+ panic(0, "Routing for receiver no <%s> already exists!",
+ octstr_get_cstr(item));
+ }
+ gwlist_destroy(items, octstr_destroy_item);
+ octstr_destroy(shortcuts);
+ }
+ else if (smsc_ids && shortcuts) {
+ /* both, so only specified MOs from specified smscs */
+ items = octstr_split(shortcuts, octstr_imm(";"));
+ for (i = 0; i < gwlist_len(items); i++) {
+ List *subitems;
+ Octstr *item = gwlist_get(items, i);
+ octstr_strip_blanks(item);
+ subitems = octstr_split(smsc_ids, octstr_imm(";"));
+ for (j = 0; j < gwlist_len(subitems); j++) {
+ Octstr *subitem = gwlist_get(subitems, j);
+ octstr_strip_blanks(subitem);
+
+ debug("opensmppbox",0,"Adding client routing to id <%s> "
+ "for receiver no <%s> and smsc id <%s>",
+ octstr_get_cstr(client_id), octstr_get_cstr(item),
+ octstr_get_cstr(subitem));
+
+ /* construct the dict key '<shortcode>:<smsc-id>' */
+ octstr_insert(subitem, item, 0);
+ octstr_insert_char(subitem, octstr_len(item), ':');
+ if (!dict_put_once(client_by_smsc_receiver, subitem, octstr_duplicate(client_id)))
+ panic(0, "Routing for receiver:smsc <%s> already exists!",
+ octstr_get_cstr(subitem));
+ }
+ gwlist_destroy(subitems, octstr_destroy_item);
+ }
+ gwlist_destroy(items, octstr_destroy_item);
+ octstr_destroy(shortcuts);
+ }
+ octstr_destroy(client_id);
+ }
+
+ gwlist_destroy(list, NULL);
+}
+
static void init_smppbox(Cfg *cfg)
{
CfgGroup *grp;
@@ -2225,6 +2711,7 @@
lvl = 0;
systemidisboxcid = 0; /* default backward compatible */
enablepam = 0; /* also default false */
+ usesmppboxid = 0; /* Ditto */
/* init dlr storage */
dlr_init(cfg);
@@ -2298,6 +2784,7 @@
cfg_get_bool(&systemidisboxcid, grp, octstr_imm("use-systemid-as-smsboxid"));
cfg_get_bool(&enablepam, grp, octstr_imm("enable-pam"));
+ cfg_get_bool(&usesmppboxid, grp, octstr_imm("use-smppboxid"));
pamacl = cfg_get(grp, octstr_imm("pam-acl"));
if (NULL == pamacl) {
pamacl = octstr_create("kannel");
@@ -2318,6 +2805,12 @@
boxid = counter_create();
gw_smpp_enter(cfg);
+ /* the client routing specific inits */
+ client_by_smsc = dict_create(30, (void(*)(void *)) octstr_destroy);
+ client_by_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+ client_by_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+ init_client_routes(cfg);
+
smppbox_status = SMPP_RUNNING;
}
@@ -2414,15 +2907,30 @@
octstr_destroy(version);
init_smppbox(cfg);
-
+ if (usesmppboxid) {
+ bbbox = bbboxc_create();
+ identify_to_bearerbox(bbbox->bearerbox_connection, smppbox_id);
+ gwthread_create(bearerbox_to_smpp, bbbox);
+ }
smppboxc_run((void *)smppbox_port);
/* shutdown dlr storage */
heartbeat_stop(ALL_HEARTBEATS);
+ if (usesmppboxid) {
+ gwthread_join_every(bearerbox_to_smpp);
+ bbboxc_destroy(bbbox);
+ }
dlr_shutdown();
counter_destroy(catenated_sms_counter);
counter_destroy(boxid);
+ dict_destroy(client_by_smsc);
+ client_by_smsc = NULL;
+ dict_destroy(client_by_receiver);
+ client_by_receiver = NULL;
+ dict_destroy(client_by_smsc_receiver);
+ client_by_smsc_receiver = NULL;
+
if (restart_smppbox) {
gwthread_sleep(1.0);
}
doc.dump
(application/octet-stream, 2.9 KB) - not displayed
gw.dump
(application/octet-stream, 26 KB) - not displayed
gwlib.dump
(application/octet-stream, 2 KB) - not displayed