Hi List,

attached you can find a patch that implements catenation of large sms inside
of bearerbox and does care of a sending of all message parts over one smsc
link. Now we have a problem with catenated large sms that bearerbox will
try to load balance those over diff. smsc links and such messages arrive as
junk (_all_ parts of catenated large sms _must_ go through the same smsc).
we avoid such a problems now with a config workarounds
(allowed/denied/etc.-smsc-id), but here is a clean solution attached;)

Please review/comment/ask/vote!

P.S. idea was stolen from netikos gateway, so I must say: thank you guys!

-- 
Thanks,
Alex
Index: gw/bb_smscconn.c
===================================================================
RCS file: /home/cvs/gateway/gw/bb_smscconn.c,v
retrieving revision 1.78
diff -a -u -p -r1.78 bb_smscconn.c
--- gw/bb_smscconn.c	8 Aug 2004 19:50:18 -0000	1.78
+++ gw/bb_smscconn.c	24 Aug 2004 21:56:11 -0000
@@ -117,6 +117,15 @@ static regex_t *black_list_regex;
 
 static long router_thread = -1;
 
+/*
+ * Counter for catenated SMS messages. The counter that can be put into
+ * the catenated SMS message's UDH headers is actually the lowest 8 bits.
+ */
+Counter *split_msg_counter;
+
+/*
+ * forward declaration
+ */
 static long route_incoming_to_smsc(SMSCConn *conn, Msg *msg);
 
 
@@ -150,22 +159,70 @@ void bb_smscconn_killed(void)
 }
 
 
-void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
+static void handle_split(SMSCConn *conn, Msg *msg, long reason)
 {
-    Msg *mack;
+    struct split_parts *split = msg->sms.split_parts;
+    
+    /* if temporarely failed, try again immediately */
+    if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_send(conn, msg) == 0)
+        return;
+    
+    /*
+     * if the reason is not a success and status is still success
+     * then set status of a split to the reason.
+     * Note: reason 'malformed','discarded' or 'rejected' has higher priority!
+     */
+    switch(reason) {
+    case SMSCCONN_FAILED_DISCARDED:
+    case SMSCCONN_FAILED_REJECTED:
+    case SMSCCONN_FAILED_MALFORMED:
+        debug("bb.sms.splits", 0, "Set split msg status to %ld", reason);
+        split->status = reason;
+        break;
+    case SMSCCONN_SUCCESS:
+        break; /* nothing todo */
+    default:
+        if (split->status == SMSCCONN_SUCCESS) {
+            debug("bb.sms.splits", 0, "Set split msg status to %ld", reason);
+            split->status = reason;
+        }
+        break;
+    }
+
+    /*
+     * now destroy this message, because we don't need it anymore.
+     * we will split it again in smscconn_send(...).
+     */
+    msg_destroy(msg);
+        
+    if (counter_decrease(split->parts_left) <= 1) {
+        /* all splited parts were processed */
+        counter_destroy(split->parts_left);
+        msg = split->orig;
+        msg->sms.split_parts = NULL;
+        if (split->status == SMSCCONN_SUCCESS)
+            bb_smscconn_sent(conn, msg, NULL);
+        else {
+            debug("bb.sms.splits", 0, "Parts of concatenated message failed.");
+            bb_smscconn_send_failed(conn, msg, split->status, NULL);
+        }
+        gw_free(split);
+    }
+}
 
+
+void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
+{
+    if (sms->sms.split_parts != NULL) {
+        handle_split(conn, sms, SMSCCONN_SUCCESS);
+        return;
+    }
+    
     counter_increase(outgoing_sms_counter);
     if (conn) counter_increase(conn->sent);
 
     /* write ACK to store file */
-
-    mack = msg_create(ack);
-    mack->ack.nack = ack_success;
-    mack->ack.time = sms->sms.time;
-    uuid_copy(mack->ack.id, sms->sms.id);
-
-    (void) store_save(mack);
-    msg_destroy(mack);
+    store_save_ack(sms, ack_success);
 
     bb_alog_sms(conn, sms, "Sent SMS");
 
@@ -191,6 +248,11 @@ void bb_smscconn_sent(SMSCConn *conn, Ms
 
 void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
 {
+    if (sms->sms.split_parts != NULL) {
+        handle_split(conn, sms, reason);
+        return;
+    }
+    
     switch (reason) {
 
     case SMSCCONN_FAILED_SHUTDOWN:
@@ -198,7 +260,6 @@ void bb_smscconn_send_failed(SMSCConn *c
 	list_produce(outgoing_sms, sms);
 	break;
     default:
-
 	/* write NACK to store file */
         store_save_ack(sms, ack_failed);
 
@@ -409,6 +470,9 @@ int smsc2_start(Cfg *cfg)
 
     if (smsc_running) return -1;
 
+    /* create split sms counter */
+    split_msg_counter = counter_create();
+    
     smsc_list = list_create();
     gw_rwlock_init_static(&smsc_list_lock);
 
@@ -662,6 +726,8 @@ void smsc2_cleanup(void)
         gw_regex_destroy(white_list_regex);
     if (black_list_regex != NULL)
         gw_regex_destroy(black_list_regex);
+    /* destroy msg split counter */
+    counter_destroy(split_msg_counter);
     gw_rwlock_destroy(&smsc_list_lock);
 }
 
@@ -849,7 +915,6 @@ int smsc2_rout(Msg *msg)
 	    bo_load = info.load;
 	}
     }
-    gw_rwlock_unlock(&smsc_list_lock);
 
     if (best_preferred)
 	ret = smscconn_send(best_preferred, msg);
@@ -858,15 +923,18 @@ int smsc2_rout(Msg *msg)
     else if (bad_found) {
 	if (bb_status != BB_SHUTDOWN)
 	    list_produce(outgoing_sms, msg);
+        gw_rwlock_unlock(&smsc_list_lock);
 	return 0;
     }
     else {
+        gw_rwlock_unlock(&smsc_list_lock);
 	if (bb_status == BB_SHUTDOWN)
 	    return 0;
 	warning(0, "Cannot find SMSCConn for message to <%s>, rejected.",
 		octstr_get_cstr(msg->sms.receiver));
 	return -1;
     }
+    gw_rwlock_unlock(&smsc_list_lock);
     /* check the status of sending operation */
     if (ret == -1)
 	return (smsc2_rout(msg));	/* re-try */
Index: gw/msg-decl.h
===================================================================
RCS file: /home/cvs/gateway/gw/msg-decl.h,v
retrieving revision 1.27
diff -a -u -p -r1.27 msg-decl.h
--- gw/msg-decl.h	21 Jun 2004 21:16:05 -0000	1.27
+++ gw/msg-decl.h	24 Aug 2004 21:56:11 -0000
@@ -104,6 +104,7 @@ MSG(sms,
 		OCTSTR(boxc_id);
 		OCTSTR(binfo);
 		INTEGER(msg_left);
+		VOID(split_parts);
 	})
 
 MSG(ack,
@@ -126,3 +127,4 @@ MSG(wdp_datagram,
 #undef INTEGER
 #undef OCTSTR
 #undef UUID
+#undef VOID
Index: gw/msg.c
===================================================================
RCS file: /home/cvs/gateway/gw/msg.c,v
retrieving revision 1.33
diff -a -u -p -r1.33 msg.c
--- gw/msg.c	22 Jan 2004 14:08:24 -0000	1.33
+++ gw/msg.c	24 Aug 2004 21:56:11 -0000
@@ -101,6 +101,7 @@ Msg *msg_create_real(enum msg_type type,
 #define INTEGER(name) p->name = MSG_PARAM_UNDEFINED
 #define OCTSTR(name) p->name = NULL
 #define UUID(name) uuid_generate(p->name)
+#define VOID(name) p->name = NULL
 #define MSG(type, stmt) { struct type *p = &msg->type; stmt }
 #include "msg-decl.h"
 
@@ -118,6 +119,7 @@ Msg *msg_duplicate(Msg *msg)
     if (q->name == NULL) p->name = NULL; \
     else p->name = octstr_duplicate(q->name);
 #define UUID(name) uuid_copy(p->name, q->name)
+#define VOID(name) p->name = q->name
 #define MSG(type, stmt) { \
     struct type *p = &new->type; \
     struct type *q = &msg->type; \
@@ -135,6 +137,7 @@ void msg_destroy(Msg *msg)
 #define INTEGER(name) p->name = 0
 #define OCTSTR(name) octstr_destroy(p->name)
 #define UUID(name) uuid_clear(p->name)
+#define VOID(name)
 #define MSG(type, stmt) { struct type *p = &msg->type; stmt }
 #include "msg-decl.h"
 
@@ -160,6 +163,8 @@ void msg_dump(Msg *msg, int level)
 #define UUID(name) \
     uuid_unparse(p->name, buf); \
     debug("gw.msg", 0 , "%*s %s.%s: %s", level, "", t, #name, buf)
+#define VOID(name) \
+     debug("gw.msg", 0, "%*s %s.%s: %p", level, "", t, #name, p->name)
 #define MSG(tt, stmt) \
     if (tt == msg->type) \
         { char *t = #tt; struct tt *p = &msg->tt; stmt }
@@ -183,6 +188,7 @@ Octstr *msg_pack(Msg *msg)
 #define INTEGER(name) append_integer(os, p->name)
 #define OCTSTR(name) append_string(os, p->name)
 #define UUID(name) append_uuid(os, p->name)
+#define VOID(name)
 #define MSG(type, stmt) \
     case type: { struct type *p = &msg->type; stmt } break;
 
@@ -219,6 +225,7 @@ Msg *msg_unpack_real(Octstr *os, const c
     if (parse_string(&(p->name), os, &off) == -1) goto error
 #define UUID(name) \
     if (parse_uuid(p->name, os, &off) == -1) goto error
+#define VOID(name)
 #define MSG(type, stmt) \
     case type: { struct type *p = &(msg->type); stmt } break;
 
Index: gw/msg.h
===================================================================
RCS file: /home/cvs/gateway/gw/msg.h,v
retrieving revision 1.22
diff -a -u -p -r1.22 msg.h
--- gw/msg.h	28 Jun 2004 15:48:29 -0000	1.22
+++ gw/msg.h	24 Aug 2004 21:56:11 -0000
@@ -82,10 +82,16 @@ typedef struct {
 	#define INTEGER(name) long name
 	#define OCTSTR(name) Octstr *name
 	#define UUID(name) uuid_t name
+	#define VOID(name) void *name
 	#define MSG(type, stmt) struct type stmt type;
 	#include "msg-decl.h"
 } Msg;
 
+struct split_parts {
+    Msg *orig;
+    Counter *parts_left;
+    long status;
+};
 
 /* enums for Msg fields */
 
Index: gw/sms.h
===================================================================
RCS file: /home/cvs/gateway/gw/sms.h,v
retrieving revision 1.11
diff -a -u -p -r1.11 sms.h
--- gw/sms.h	28 Jun 2004 15:48:29 -0000	1.11
+++ gw/sms.h	24 Aug 2004 21:56:12 -0000
@@ -122,6 +122,11 @@
 #define SMS_7BIT_MAX_LEN 160
 #define SMS_8BIT_MAX_LEN 140
 #define SMS_UCS2_MAX_LEN 70
+/*
+ * Maximum number of octets in an SMS message. Note that this is 8 bit
+ * characters, not 7 bit characters.
+ */
+#define MAX_SMS_OCTETS 140
 
 /* Encode DCS using sms fields
  * mode = 0= encode using 00xxxxxx, 1= encode using 1111xxxx mode
Index: gw/smsbox.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsbox.c,v
retrieving revision 1.250
diff -a -u -p -r1.250 smsbox.c
--- gw/smsbox.c	11 Aug 2004 16:41:29 -0000	1.250
+++ gw/smsbox.c	24 Aug 2004 21:56:13 -0000
@@ -84,13 +84,6 @@
 #endif
 
 
-/*
- * Maximum number of octets in an SMS message. Note that this is 8 bit
- * characters, not 7 bit characters.
- */
-enum { MAX_SMS_OCTETS = 140 };
-
-
 #define SENDSMS_DEFAULT_CHARS "0123456789 +-"
 
 #define O_DESTROY(a) { if(a) octstr_destroy(a); a = NULL; }
@@ -298,12 +291,30 @@ static int send_message(URLTranslation *
     list = sms_split(msg, header, footer, suffix, split_chars, catenate,
     	    	     msg_sequence, max_msgs, sms_max_length);
     msg_count = list_len(list);
-
+    
     debug("sms", 0, "message length %ld, sending %ld messages",
           octstr_len(msg->sms.msgdata), msg_count);
-
-    while ((part = list_extract_first(list)) != NULL)
-	write_to_bearerbox(part);
+    
+    /*
+     * In order to get catenated msgs work properly, we
+     * have moved catenation to bearerbox.
+     * So here we just need to put splitted msgs into one again and send
+     * to bearerbox that will care about catenation.
+     */
+    if (catenate) {
+        Msg *new_msg = msg_duplicate(msg);
+        octstr_delete(new_msg->sms.msgdata, 0, octstr_len(new_msg->sms.msgdata));
+        while((part = list_extract_first(list)) != NULL) {
+            octstr_append(new_msg->sms.msgdata, part->sms.msgdata);
+            msg_destroy(part);
+        }
+        write_to_bearerbox(new_msg);
+    } else {
+        /* msgs are the independed parts so sent those as is */
+        while ((part = list_extract_first(list)) != NULL)
+            write_to_bearerbox(part);
+    }
+    
     list_destroy(list, NULL);
 
     return msg_count;
Index: gw/smscconn.c
===================================================================
RCS file: /home/cvs/gateway/gw/smscconn.c,v
retrieving revision 1.48
diff -a -u -p -r1.48 smscconn.c
--- gw/smscconn.c	28 Jun 2004 15:18:35 -0000	1.48
+++ gw/smscconn.c	24 Aug 2004 21:56:13 -0000
@@ -70,6 +70,9 @@
 #include "smscconn.h"
 #include "smscconn_p.h"
 #include "bb_smscconn_cb.h"
+#include "sms.h"
+
+extern Counter *split_msg_counter;
 
 /*
  * Some defaults
@@ -489,8 +492,8 @@ int smscconn_usable(SMSCConn *conn, Msg 
 
 int smscconn_send(SMSCConn *conn, Msg *msg)
 {
-    int ret;
-    char *uf;
+    int ret = -1;
+    List *parts = NULL;
     
     gw_assert(conn != NULL);
     mutex_lock(conn->flow_mutex);
@@ -499,11 +502,55 @@ int smscconn_send(SMSCConn *conn, Msg *m
         return -1;
     }
 
-    /* normalize the destination number for this smsc */
-    uf = conn->unified_prefix ? octstr_get_cstr(conn->unified_prefix) : NULL;
-    normalize_number(uf, &(msg->sms.receiver));
-
-    ret = conn->send_msg(conn, msg);
+    /* if this a retry of splitted message, don't unify prefix and don't try to split */
+    if (msg->sms.split_parts == NULL) {    
+        /* normalize the destination number for this smsc */
+        char *uf = conn->unified_prefix ? octstr_get_cstr(conn->unified_prefix) : NULL;
+        normalize_number(uf, &(msg->sms.receiver));
+
+        /* split msg */
+        parts = sms_split(msg, NULL, NULL, NULL, NULL, 1, 
+            counter_increase(split_msg_counter) & 0xff, 0xff, MAX_SMS_OCTETS);
+    }
+    
+    if (parts == NULL)
+        ret = conn->send_msg(conn, msg);
+    else {
+        long i, parts_len = list_len(parts);
+        struct split_parts *split = gw_malloc(sizeof(*split));
+         /* must duplicate, because smsc2_route will destroy this msg */
+        split->orig = msg_duplicate(msg);
+        split->parts_left = counter_create();
+        split->status = SMSCCONN_SUCCESS;
+        counter_set(split->parts_left, parts_len);
+        debug("bb.sms.splits", 0, "new split_parts created %p", split);
+        for (i = 0; i < parts_len; i++) {
+            msg = list_get(parts, i);
+            msg->sms.split_parts = split;
+            ret = conn->send_msg(conn, msg);
+            if (ret < 0) {
+                if (i == 0) {
+                    counter_destroy(split->parts_left);
+                    list_destroy(parts, msg_destroy_item);
+                    gw_free(split);
+                    mutex_unlock(conn->flow_mutex);
+                    return ret;
+                }
+                /*
+                 * Some parts were sent. So handle this within
+                 * bb_smscconn_XXX().
+                 */
+                split->status = SMSCCONN_FAILED_REJECTED;
+                while (++i < parts_len) {
+                    msg_destroy(list_get(parts, i));
+                    counter_decrease(split->parts_left);
+                }
+                warning(0, "Could not send all parts of a split message");
+                break;
+            }
+        }
+        list_destroy(parts, NULL);
+    }
     mutex_unlock(conn->flow_mutex);
     return ret;
 }
Index: gw/wapbox.c
===================================================================
RCS file: /home/cvs/gateway/gw/wapbox.c,v
retrieving revision 1.173
diff -a -u -p -r1.173 wapbox.c
--- gw/wapbox.c	22 Jan 2004 14:08:24 -0000	1.173
+++ gw/wapbox.c	24 Aug 2004 21:56:14 -0000
@@ -95,8 +95,6 @@ enum {
     WTLS_CONNECTION_ORIENTED_PORT = 9203
 };
 
-enum { MAX_SMS_OCTETS = 140 };
-
 enum { DEFAULT_TIMER_FREQ = 1};
 
 static Octstr *bearerbox_host;
Index: gw/smsc/smsc_http.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsc/smsc_http.c,v
retrieving revision 1.36
diff -a -u -p -r1.36 smsc_http.c
--- gw/smsc/smsc_http.c	11 Aug 2004 16:41:29 -0000	1.36
+++ gw/smsc/smsc_http.c	24 Aug 2004 21:56:15 -0000
@@ -313,7 +313,6 @@ static void httpsmsc_send_cb(void *arg)
  */
 
 enum { HEX_NOT_UPPERCASE = 0 };
-enum { MAX_SMS_OCTETS = 140 };
 
 
 static void kannel_send_sms(SMSCConn *conn, Msg *sms)
Index: gw/smsc/smsc_soap.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsc/smsc_soap.c,v
retrieving revision 1.12
diff -a -u -p -r1.12 smsc_soap.c
--- gw/smsc/smsc_soap.c	11 Aug 2004 16:41:29 -0000	1.12
+++ gw/smsc/smsc_soap.c	24 Aug 2004 21:56:17 -0000
@@ -2062,6 +2062,7 @@ static Octstr* soap_convert_token(Msg* m
         if (!octstr_str_compare(name, #fieldname)) \
                 return octstr_duplicate(p->fieldname);
 #define UUID(fieldname) 
+#define VOID(fieldname)
 
 #define MSG(type, stmt) \
         case type: { struct type *p = &msg->type; stmt } break;
Index: utils/mtbatch.c
===================================================================
RCS file: /home/cvs/gateway/utils/mtbatch.c,v
retrieving revision 1.4
diff -a -u -p -r1.4 mtbatch.c
--- utils/mtbatch.c	22 Jan 2004 14:08:25 -0000	1.4
+++ utils/mtbatch.c	24 Aug 2004 21:56:17 -0000
@@ -80,12 +80,6 @@
 #include "shared.h"
 #include "heartbeat.h"
 
-/*
- * Maximum number of octets in an SMS message. Note that this is 8 bit
- * characters, not 7 bit characters.
- */
-enum { MAX_SMS_OCTETS = 140 };
-
 static char *pid_file;
 static Octstr *smsbox_id = NULL;
 static Octstr *content = NULL;

Reply via email to