[PATCH] EMI part 2

Nisan Bloch <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Hi

This patch to the EMI module tries to address the problem of dealing with 
msgs that do not get acked by the SMSC after the wait-ack period. This 
should never happen but it does, even with wait-acks in the region of 
240-600secs.  Thanks to Andreas for his input.

It adds a new config var (wait-ack-expire) that defines what to do with 
such an error. After some discussion between Andreas and I, we decided that 
a disconnect/reconnect should be the default behavior. The various option 
for wait-ack-expire are
0x00 - disconnect/reconnect, (default)
0x01 - as is now, requeue, but this could potentially result in the msg 
arriving twice
0x02 - just carry on waiting (given that the wait-ack should never expire 
this is the mst accurate)

I have submitted this patch distinctly different from the patch to handle 
the window problem to make voting and testing easier. I have tested it a 
fair amount, but I think it needs some more.

Nisan
smsc_emi2.patch (application/octet-stream, 4.4 KB)
--- cvs/gateway/gw/smsc/smsc_emi2.c	Sun Dec  8 22:44:53 2002
+++ kannel-cvsup/gw/smsc/smsc_emi2.c	Sun Dec  8 22:29:08 2002
@@ -56,6 +56,7 @@
     int		keepalive; 	/* Seconds to send a Keepalive Command (OT=31) */
     int		flowcontrol;	/* 0=Windowing, 1=Stop-and-Wait */
     int		waitack;	/* Seconds to wait to ack */
+    int		waitack_expire;	/* What to do on waitack expire */
     int		throughput;	/* Messages per second */
     int		window;		/* In windowed flow-control, the window size */
     int         can_write;      /* write = 1, read = 0, for stop-and-wait flow control */
@@ -1107,7 +1108,7 @@
     return 0;
 }
 
-static void emi2_idleprocessing(SMSCConn *conn)
+static void emi2_idleprocessing(SMSCConn *conn, Connection **server)
 {
     time_t current_time;
     int i;
@@ -1121,21 +1122,42 @@
     
     if (PRIVDATA(conn)->unacked && (current_time > (PRIVDATA(conn)->check_time + 30))) {
 	PRIVDATA(conn)->check_time = current_time;
-	for (i = 0; i < EMI2_MAX_TRN; i++) {
+        for (i = 0; i < PRIVDATA(conn)->window; i++) {
 	    if (SLOTBUSY(conn,i)
 		&& PRIVDATA(conn)->slots[i].sendtime < (current_time - PRIVDATA(conn)->waitack)) {
+
+                if (PRIVDATA(conn)->slots[i].sendtype == 51) {
+                    if (PRIVDATA(conn)->waitack_expire == 0x00) {
+                        // 0x00 - disconnect/reconnect
+                        warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d "
+                            "in %d seconds, disconnecting and reconnection",
+                            octstr_get_cstr(privdata->name), i, PRIVDATA(conn)->waitack);
 		PRIVDATA(conn)->slots[i].sendtime = 0;
 		PRIVDATA(conn)->unacked--;
-		if (PRIVDATA(conn)->slots[i].sendtype == 51) {
+                        info(0, "EMI2[%s]: closing connection.",
+                                  octstr_get_cstr(privdata->name));
+                        conn_destroy(*server);
+                        *server = NULL;
+                        break;
+                    } else if (PRIVDATA(conn)->waitack_expire == 0x01) {
+                        // 0x01 - resend
 		    warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d " 
 			    "in %d seconds, resending message", octstr_get_cstr(privdata->name),
 			    i, PRIVDATA(conn)->waitack);
 		    list_produce(PRIVDATA(conn)->outgoing_queue,
 				 PRIVDATA(conn)->slots[i].sendmsg);
+                        PRIVDATA(conn)->slots[i].sendtime = 0;
+                        PRIVDATA(conn)->unacked--;
 		    if (PRIVDATA(conn)->flowcontrol) PRIVDATA(conn)->can_write=1;
 		    /* Wake up this same thread to send again
 		     * (simpler than avoiding sleep) */
 		    gwthread_wakeup(PRIVDATA(conn)->sender_thread);
+                    } else if (PRIVDATA(conn)->waitack_expire == 0x03) {
+                        // 0x02 - carry on waiting
+                           warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d "
+                                "in %d seconds, carrying on waiting", octstr_get_cstr(privdata->name),
+                                i, PRIVDATA(conn)->waitack);
+                    }
 		} else if (PRIVDATA(conn)->slots[i].sendtype == 31) {
 		    warning(0, "EMI2[%s]: Alert (operation 31) was not "
 			    "ACKed within %d seconds", octstr_get_cstr(privdata->name),
@@ -1231,7 +1253,7 @@
             return; /* reopen the connection */
         }
 	
-	emi2_idleprocessing (conn);
+	emi2_idleprocessing (conn, server);
 	emi2_idletimeout_handling (conn, server);
 
 	if (PRIVDATA(conn)->shutdown && (PRIVDATA(conn)->unacked == 0)) {
@@ -1510,7 +1532,7 @@
     PrivData *privdata;
     Octstr *allow_ip, *deny_ip, *host, *alt_host;
     long portno, our_port, keepalive, flowcontrol, waitack, throughput, 
-         idle_timeout, alt_portno, alt_charset; 
+         idle_timeout, alt_portno, alt_charset, waitack_expire;
     long window;
     	/* has to be long because of cfg_get_integer */
     int i;
@@ -1655,6 +1677,16 @@
 	goto error;
     }
 
+    if (cfg_get_integer(&waitack_expire, cfg, octstr_imm("wait-ack-expire")) < 0)
+	privdata->waitack_expire = 0;
+    else
+	privdata->waitack_expire = waitack_expire;
+    if (privdata->waitack_expire >3  ) {
+	error(0, "EMI2[%s]: 'wait-ack-expire' invalid in emi2 configuration.",
+	      octstr_get_cstr(privdata->name));
+	goto error;
+    }
+
     if (privdata->rport < 0 || privdata->rport > 65535) {
 	error(0, "EMI2[%s]: 'receive-port' missing/invalid in emi2 configuration.",
 	      octstr_get_cstr(privdata->name));
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.