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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.