[PATCH] Smppbox acks

"Rene Kluwen" <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Here is a more advanced patch. Messages to bearerbox are acked, once the deliver_sm_resp pdu is in.
Also submit_sm pdu's get their responses, after bearerbox has acked the message. And if not, a failure notice is returned.
Before, message acks were given right away, without checking for failure or rejection.

Tomasz: Would it be possible for you to test this patch in your environment?

Victor: Would you review for stupidities?

Comments are welcome.

== Rene
acks_patch.patch (application/octet-stream, 5 KB)
Index: gw/smppbox.c
===================================================================
--- gw/smppbox.c	(revision 35)
+++ gw/smppbox.c	(working copy)
@@ -139,6 +139,8 @@
     Octstr	*boxc_id; /* identifies the connected smppbox instance */
     Octstr	*account;
     Octstr	*route_to_smsc;
+    Dict	*msg_acks;
+    Dict	*deliver_acks;
     /* used to mark connection usable or still waiting for ident. msg */
     volatile int routable;
 
@@ -157,6 +159,12 @@
 
 } Boxc;
 
+
+void smpp_pdu_destroy_item(void *pdu)
+{
+	smpp_pdu_destroy(pdu);
+}
+
 /* check if login exists in database */
 int check_login(Boxc *boxc, Octstr *system_id, Octstr *password, Octstr *system_type, smpp_login login_type) {
 	int box;
@@ -1235,11 +1243,12 @@
 
 static void handle_pdu(Connection *conn, Boxc *box, SMPP_PDU *pdu) {
 	SMPP_PDU *resp = NULL;
-	Msg *msg, *msg2;
+	Msg *msg, *msg2, *mack;
 	long reason;
 	Octstr *msgid = NULL;
 	int msg_to_send = 1;
 	List *parts_list = NULL;
+	char id[UUID_STR_LEN + 1];
 
 	dump_pdu("Got PDU:", box->boxc_id, pdu);
 	switch (pdu->type) {
@@ -1339,6 +1348,10 @@
 					dlr_add(box->boxc_id, msgid, msg2);
 					octstr_destroy(msgid);
 				}
+				uuid_unparse(msg2->sms.id, id);
+				msgid = octstr_create(id);
+				dict_put(box->msg_acks, msgid, resp);
+				resp = NULL;
 				send_msg(box->bearerbox_connection, box, msg2);
 				if (parts_list) {
 					/* destroy values */
@@ -1373,6 +1386,10 @@
 					dlr_add(box->boxc_id, msgid, msg2);
 					octstr_destroy(msgid);
 				}
+				uuid_unparse(msg2->sms.id, id);
+				msgid = octstr_create(id);
+				dict_put(box->msg_acks, msgid, resp);
+				resp = NULL;
 				send_msg(box->bearerbox_connection, box, msg2);
 				if (parts_list) {
 					/* destroy values */
@@ -1382,7 +1399,18 @@
 		}
 		break;
 	case deliver_sm_resp:
-		/* thank you */
+		msgid = octstr_format("%ld", pdu->u.deliver_sm_resp.sequence_number);
+		mack = dict_get(box->deliver_acks, msgid);
+		if (mack) {
+			msg = msg_duplicate(mack);
+			/* TODO: ack_failed_tmp */
+			if (pdu->u.deliver_sm_resp.command_status != 0) {
+				msg->ack.nack = ack_failed;
+			}
+			send_msg(box->bearerbox_connection, box, msg);
+			dict_put(box->deliver_acks, msgid, NULL);
+		}
+		octstr_destroy(msgid);
 		break;
 	case unbind_resp:
 		box->logged_in = 0;
@@ -1433,6 +1461,8 @@
     boxc->alt_charset = NULL; /* todo: get from config */
     boxc->version = 0x33; /* default value, set upon receiving a bind */
     boxc->route_to_smsc = route_to_smsc ? octstr_duplicate(route_to_smsc) : NULL;
+    boxc->msg_acks = dict_create(10, smpp_pdu_destroy_item);
+    boxc->deliver_acks = dict_create(10, msg_destroy_item);
 
     boxc->service_type = NULL;
 
@@ -1471,6 +1501,8 @@
     }
     if (boxc->client_ip)
 	    octstr_destroy(boxc->client_ip);
+    dict_destroy(boxc->msg_acks);
+    dict_destroy(boxc->deliver_acks);
     gw_free(boxc);
 }
 
@@ -1570,6 +1602,8 @@
     List *pdulist;
     int dreport;
     Connection *receiver_connection;
+    char id[UUID_STR_LEN + 1];
+    Octstr *msgid;
 
     while (smppbox_status == SMPP_RUNNING && box->alive) {
 
@@ -1599,7 +1633,40 @@
             continue;
         }
 	if (msg_type(msg) == ack) {
-		// todo: what do we do here?
+	    uuid_unparse(msg->ack.id, id);
+	    msgid = octstr_create(id);
+	    pdu = dict_get(box->msg_acks, msgid);
+	    if (pdu) {
+		switch (msg->ack.nack) {
+		case ack_buffered:
+		case ack_success:
+			/* we can send the submit_sm_resp as-is */
+			break;
+		case ack_failed:
+		case ack_failed_tmp:
+			switch (pdu->type) {
+			case submit_sm_resp:
+				octstr_destroy(pdu->u.submit_sm_resp.message_id);
+				pdu->u.submit_sm_resp.message_id = NULL;
+				pdu->u.submit_sm_resp.command_status = SMPP_ESME_RSUBMITFAIL;
+				break;
+			case data_sm_resp:
+				octstr_destroy(pdu->u.data_sm_resp.message_id);
+				pdu->u.data_sm_resp.message_id = NULL;
+				pdu->u.data_sm_resp.command_status = SMPP_ESME_RSUBMITFAIL;
+				break;
+			}
+		default:
+			debug("smppbox", 0, "Unknown ack.nack type: %i.", msg->ack.nack);
+			break;
+		}
+		send_pdu(box->smpp_connection, box->boxc_id, pdu);
+		dict_put(box->msg_acks, msgid, NULL); /* also destroys item */
+	    }
+	    else {
+		debug("smppbox", 0, "Ack to unknown message: %s.", id);
+	    }
+	    octstr_destroy(msgid);
 	}
         if (!box->alive) {
 		msg_destroy(msg);
@@ -1677,16 +1744,23 @@
 		mack->ack.time = msg->sms.time;
 		uuid_copy(mack->ack.id, msg->sms.id);
 
+		msgid = NULL;
 		pdulist = msg_to_pdu(box, msg);
 		if (pdulist != NULL) {
 			receiver_connection = find_receiver_connection(box);
 			while ((pdu = gwlist_extract_first(pdulist)) != NULL) {
+				if (NULL == msgid) {
+					/* Put ack in dict. We will send it as soon as we received a deliver_sm_resp */
+					msgid = octstr_format("%ld", pdu->u.deliver_sm.sequence_number);
+					dict_put(box->deliver_acks, msgid, mack);
+				}
 				send_pdu(receiver_connection, box->boxc_id, pdu);
 				smpp_pdu_destroy(pdu);
 			}
+			if (msgid)
+				octstr_destroy(msgid);
 			gwlist_destroy(pdulist, NULL);
 		}
-		send_msg(box->bearerbox_connection, box, mack);
 	}
         msg_destroy(msg);
     }
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.