[PATCH] fix bug #529 (sms-resend-* ignored for concatenated messages)

Alejandro Guerrieri aguerrieri at kannel.org
Mon Sep 13 19:25:01 CEST 2010


The uuid would be different each time you start the service right?

What would happen if Kannel is restarted and there were pending parts to send? The new uuid wouldn't match with the pending segments.

Regards,
--
Alejandro Guerrieri
aguerrieri at kannel.org



On 13/09/2010, at 19:16, Alexander Malysh wrote:

> Hi,
> 
> great idea to use uuid to uniquely identify smscconn. we can use this for http admin as well.
> 
> Thanks,
> Alexander Malysh 
> 
> Am 13.09.2010 um 19:04 schrieb Michael Zervakis:
> 
>> Hi,
>> 
>> I figured out that we can use the same mechanism as in Msg struct to uniquelly identify each SMSCconn. In the attached patch the smscconn struct was modified to include a uuid_t field and Msg struct to store the smscconn uuid_t if we get a temporary error. Smsc_rout2 was also modified to respect msg->msg_ConnId if set.
>> 
>> SMSC-A -> splits (2 parts) -> 1 part sent OK -> 2 part get temp. error -> write the conn->uuid_t and put it into global queue for resend  -> router reads msg->msg_ConnId and sends failed part via same connection (if still active)
>> 
>> 
>> -----Original Message-----
>> From: Alexander Malysh [mailto:malysh00 at googlemail.com] On Behalf Of Alexander Malysh
>> Sent: Sunday, September 12, 2010 1:06 PM
>> To: Michael Zervakis
>> Cc: devel at kannel.org; poncha at appcell.net
>> Subject: Re: [PATCH] fix bug #529 (sms-resend-* ignored for concatenated messages)
>> 
>> 
>> Hi,
>> 
>> 
>> as I already wrote, this patch is not enough. Please see ML wy...
>> 
>> 
>> Thanks,
>> 
>> Alexander Malysh
>> 
>> 
>> 
>> Am 09.09.2010 um 19:04 schrieb Michael Zervakis:
>> 
>> 
>>> Hi,
>> 
>>> 
>> 
>>> This patch is a possible solution fog Bug #529. The Msg definition was modified so we can store the conn->id originally selected by router.
>> 
>>> 
>> 
>>> SMSC-A -> splits (2 parts) -> 1 part sent OK -> 2 part get temp. error -> write the conn->id and put it into global queue for resend  -> router reads msg->sms.msg_ConnId and sends failed part via same connection (if still active)
>> 
>>> 
>> 
>>> 
>> 
>>> Regards,
>> 
>>> 
>> 
>>> 
>> 
>>> From: devel-bounces at kannel.org [mailto:devel-bounces at kannel.org] On Behalf Of Konstantin Vayner
>> 
>>> Sent: Thursday, December 17, 2009 12:28 PM
>> 
>>> To: Alexander Malysh
>> 
>>> Cc: devel at kannel.org
>> 
>>> Subject: Re: [PATCH] fix bug #529 (sms-resend-* ignored for concatenated messages)
>> 
>>> 
>> 
>>> 
>> 
>>> why remembering smsc-id in sms.smsc_id is not enough?
>> 
>>> how does smsbox remember routing when i submit a message with predefined smsc id from http (sendsms) ?
>> 
>>> 
>> 
>>> On Thu, Dec 17, 2009 at 12:10 PM, Alexander Malysh <amalysh at kannel.org> wrote:
>> 
>>> 
>> 
>>> 
>> 
>>> Am 17.12.2009 um 10:43 schrieb Konstantin Vayner:
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> so the best option would be to requeue the part via same smsc, right ?
>> 
>>> 
>> 
>>> 
>> 
>>> yes, but it's not easy todo. You have to remember SMSC pointer not only SMSC-name/id and then teach all routing parts
>> 
>>> 
>> 
>>> to respect it...
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> cause requeueing all parts may also get extra messages to the handset despite it not being able to reconstruct (not to mention the extra money ;) )
>> 
>>> 
>> 
>>> On Thu, Dec 17, 2009 at 11:33 AM, Alexander Malysh <amalysh at kannel.org> wrote:
>> 
>>> 
>> 
>>> Hi,
>> 
>>> 
>> 
>>> 
>> 
>>> unfortunately this will not work as expected (the rule is: _all_ parts if multipart message have to be send via the same SMSC)...
>> 
>>> 
>> 
>>> 
>> 
>>> example:
>> 
>>> 
>> 
>>> 
>> 
>>>          SMSC-A -> splits (2 parts) -> 1 part sent OK -> 2 part get temp. error -> you put it into global queue for resend -> 2 part sent via SMSC-B -> handset rejects it
>> 
>>> 
>> 
>>> 
>> 
>>> We have only two possibility here:
>> 
>>> 
>> 
>>> 1) if temp error occurs put the _whole_ message into resend queue and resend then _all_ parts (very easy todo)
>> 
>>> 
>> 
>>> 2) remember smsc which was used for first parts and resend it via the same smsc (complicated but save money :) )
>> 
>>> 
>> 
>>> 
>> 
>>> Thanks,
>> 
>>> 
>> 
>>> Alexander Malysh
>> 
>>> 
>> 
>>> 
>> 
>>> Am 16.12.2009 um 18:17 schrieb Konstantin Vayner:
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> Bug report: http://redmine.kannel.org/issues/show/529
>> 
>>> 
>> 
>>> Quote from gw/bb_smscconn.c :
>> 
>>> 
>> 
>>> static void handle_split(SMSCConn *conn, Msg *msg, long reason)
>> 
>>> {
>> 
>>>  struct split_parts *split = msg->sms.split_parts;
>> 
>>> 
>> 
>>>  /*
>> 
>>>   * If temporarely failed, try again immediately but only if connection active.
>> 
>>>   * Because if connection is not active we will loop for ever here consuming 100% CPU
>> 
>>>   * time due to internal queue cleanup in smsc module that call bb_smscconn_failed.
>> 
>>>   */
>> 
>>>  if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
>> 
>>>      smscconn_send(conn, msg) == 0) {
>> 
>>>      /* destroy this message because it will be duplicated in smsc module */
>> 
>>>      msg_destroy(msg);
>> 
>>>      return;
>> 
>>>  }
>> 
>>> 
>> 
>>> (end quote)
>> 
>>> 
>> 
>>> So, if an smsc is alive and throws temporary error every time you try to submit such a message, we enter endless loop of attempting to resend it....
>> 
>>> 
>> 
>>> 
>> 
>>> Suggested patch follows (also attached).
>> 
>>> Sorry its not cvs diff - having firewall issues accessing pserver now so i ran diff vs snapshot generated yesterday
>> 
>>> I will be able to produce a normal cvs diff tomorrow morning if it is needed
>> 
>>> 
>> 
>>> 
>> 
>>> --- kannel-snapshot/gw/bb_smscconn.c    2009-11-15 16:12:28.000000000 +0200
>> 
>>> +++ gateway-cvs/gw/bb_smscconn.c        2009-12-16 19:47:32.000000000 +0200
>> 
>>> @@ -203,18 +203,6 @@
>> 
>>>   struct split_parts *split = msg->sms.split_parts;
>> 
>>>      /*
>> 
>>> -     * If temporarely failed, try again immediately but only if connection active.
>> 
>>> -     * Because if connection is not active we will loop for ever here consuming 100% CPU
>> 
>>> -     * time due to internal queue cleanup in smsc module that call bb_smscconn_failed.
>> 
>>> -     */
>> 
>>> -    if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
>> 
>>> -        smscconn_send(conn, msg) == 0) {
>> 
>>> -        /* destroy this message because it will be duplicated in smsc module */
>> 
>>> -        msg_destroy(msg);
>> 
>>> -        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!
>> 
>>> @@ -303,7 +291,7 @@
>> 
>>> void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
>> 
>>> {
>> 
>>> -    if (sms->sms.split_parts != NULL) {
>> 
>>> +    if (reason != SMSCCONN_FAILED_TEMPORARILY && sms->sms.split_parts != NULL) {
>> 
>>>       handle_split(conn, sms, reason);
>> 
>>>       octstr_destroy(reply);
>> 
>>>       return;
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> <bb_smscconn.diff>
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> 
>> 
>>> Index: gw/bb_smscconn.c
>> 
>>> ===================================================================
>> 
>>> --- gw/bb_smscconn.c  (revision 4838)
>> 
>>> +++ gw/bb_smscconn.c  (working copy)
>> 
>>> @@ -207,11 +207,34 @@
>> 
>>>     * Because if connection is not active we will loop for ever here consuming 100% CPU
>> 
>>>     * time due to internal queue cleanup in smsc module that call bb_smscconn_failed.
>> 
>>>     */
>> 
>>> -    if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
>> 
>>> -        smscconn_send(conn, msg) == 0) {
>> 
>>> +    /*if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
>> 
>>> +        smscconn_send(conn, msg) == 0) { */
>> 
>>>        /* destroy this message because it will be duplicated in smsc module */
>> 
>>> -        msg_destroy(msg);
>> 
>>> +    /*    msg_destroy(msg);
>> 
>>>        return;
>> 
>>> +    }*/
>> 
>>> +       
>>> +   
>>> +
>> 
>>> +    if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE)
>> 
>>> +    {
>> 
>>> +       if (sms_resend_retry >= 0 && msg->sms.resend_try >= sms_resend_retry) /*check how many times the split message has been sent */
>> 
>>> +       { 
>>> +          warning(0, "SMPP[%s] :Maximum retries for message [%s] exceeded resend %ld times, discarding it!", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.msgdata),msg->sms.resend_try);
>> 
>>> +          handle_split(conn, msg, SMSCCONN_FAILED_DISCARDED); 
>>> +          /* msg_destroy(msg); */
>> 
>>> +          return;
>> 
>>> +       }
>> 
>>> +         
>>> +       warning(0, "SMPP[%s] :Split message failed temporarily sending back to sms_router", octstr_get_cstr(conn->id));
>> 
>>> +      
>>> +       msg->sms.resend_try = (msg->sms.resend_try > 0 ? msg->sms.resend_try + 1 : 1);
>> 
>>> +       debug("bb.sms.splits", 0, "SMPP[%s] :Resend counter of message set to %ld", octstr_get_cstr(conn->id),msg->sms.resend_try);
>> 
>>> +       time(&msg->sms.resend_time);
>> 
>>> +       msg->sms.msg_ConnId = octstr_duplicate(conn->id); 
>>> +      
>>> +       gwlist_produce(outgoing_sms, msg); /* write it back to global queue */
>> 
>>> +       return;
>> 
>>>    }
>> 
>>> 
>> 
>>>    /*
>> 
>>> @@ -1229,6 +1252,28 @@
>> 
>>>    bp_load = bo_load = queue_length = 0;
>> 
>>> 
>> 
>>>    conn = NULL;
>> 
>>> +    /* if msg was a failed part then route to the defined SMSC connection */
>> 
>>> +    if (msg->sms.msg_ConnId != NULL)
>> 
>>> +    {   
>>> +       for (i=0; i < gwlist_len(smsc_list); i++)
>> 
>>> +       {
>> 
>>> +          conn = gwlist_get(smsc_list,  i);
>> 
>>> +          smscconn_info(conn, &info);
>> 
>>> +          queue_length += (info.queued > 0 ? info.queued : 0);
>> 
>>> +         
>>> +          if(octstr_compare(msg->sms.msg_ConnId, conn->id) == 0)
>> 
>>> +          { 
>>> +             if((smscconn_usable(conn,msg) != -1) && (info.status == SMSCCONN_ACTIVE && info.queued < max_queue))
>> 
>>> +             {
>> 
>>> +                best_preferred = conn; 
>>> +                debug("bb.sms",0,"Message with pre-set connection to SMSC[%s] found",octstr_get_cstr(msg->sms.msg_ConnId));
>> 
>>> +                continue;
>> 
>>> +             }
>> 
>>> +          }
>> 
>>> +       }
>> 
>>> +    }
>> 
>>> +    else
>> 
>>> +    {
>> 
>>>    for (i=0; i < gwlist_len(smsc_list); i++) {
>> 
>>>    conn = gwlist_get(smsc_list,  (i+s) % gwlist_len(smsc_list));
>> 
>>> 
>> 
>>> @@ -1265,6 +1310,8 @@
>> 
>>>        bo_load = info.load;
>> 
>>>    }
>> 
>>>    }
>> 
>>> +    }
>> 
>>> +   
>>>    queue_length += gwlist_len(outgoing_sms);
>> 
>>>    if (max_outgoing_sms_qlength > 0 && !resend &&
>> 
>>>         queue_length > gwlist_len(smsc_list) * max_outgoing_sms_qlength) {
>> 
>>> Index: gw/msg-decl.h
>> 
>>> ===================================================================
>> 
>>> --- gw/msg-decl.h     (revision 4838)
>> 
>>> +++ gw/msg-decl.h     (working copy)
>> 
>>> @@ -85,6 +85,7 @@
>> 
>>>        OCTSTR(msgdata)
>> 
>>>        INTEGER(time)
>> 
>>>        OCTSTR(smsc_id)
>> 
>>> +        OCTSTR(msg_ConnId); /* field required to reroute concatenated Msg parts via the same SMSC connection. Bug 529*/
>> 
>>>        OCTSTR(smsc_number)
>> 
>>>        OCTSTR(foreign_id)
>> 
>>>        OCTSTR(service)
>> 
>> 
>> Index: bb_smscconn.c
>> ===================================================================
>> --- bb_smscconn.c	(revision 4843)
>> +++ bb_smscconn.c	(working copy)
>> @@ -201,17 +201,46 @@
>> static void handle_split(SMSCConn *conn, Msg *msg, long reason)
>> {
>>    struct split_parts *split = msg->sms.split_parts;
>> +    char id[UUID_STR_LEN + 1];
>> 
>> +    
>>    /*
>>     * If temporarely failed, try again immediately but only if connection active.
>>     * Because if connection is not active we will loop for ever here consuming 100% CPU
>>     * time due to internal queue cleanup in smsc module that call bb_smscconn_failed.
>>     */
>> -    if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
>> -        smscconn_send(conn, msg) == 0) {
>> +    /*if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
>> +        smscconn_send(conn, msg) == 0) { */
>>        /* destroy this message because it will be duplicated in smsc module */
>> -        msg_destroy(msg);
>> +    /*    msg_destroy(msg);
>>        return;
>> +    }*/
>> +        
>> +    
>> +    if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE)
>> +    {
>> +       if (sms_resend_retry >= 0 && msg->sms.resend_try >= sms_resend_retry) /*check how many times the split message has been sent */
>> +       {  
>> +          uuid_unparse(msg->sms.id, id);
>> +          warning(0, "SMPP[%s] :Maximum retries for message [%s] exceeded resend %ld times, discarding it!", octstr_get_cstr(conn->id), id, msg->sms.resend_try); 
>> +          handle_split(conn, msg, SMSCCONN_FAILED_DISCARDED);  
>> +          return;
>> +       }
>> +                    
>> +        
>> +       uuid_unparse(msg->sms.id, id);
>> +       warning(0, "SMPP[%s] :Split message [%s] failed temporary sending it to sms_router but with fixed connection", octstr_get_cstr(conn->id), id);  
>> +       
>> +       msg->sms.resend_try = (msg->sms.resend_try > 0 ? msg->sms.resend_try + 1 : 1); /* inc its retries */
>> +       debug("bb.sms.splits", 0, "SMPP[%s] :Resend counter of message [%s]  set to %ld", octstr_get_cstr(conn->id), id, msg->sms.resend_try);
>> +       time(&msg->sms.resend_time); /* take resend time - this will be used in sms_router */
>> +              
>> +        
>> +       if(uuid_is_null(msg->msg_ConnId) == 1)
>> +         uuid_copy(msg->msg_ConnId, conn->smscconn_uuid);
>> +       
>> +       gwlist_produce(outgoing_sms, msg); /* send it back to global queue */ 
>> +       return;
>>    }
>> 
>>    /*
>> @@ -1187,8 +1216,8 @@
>>    long bp_load, bo_load;
>>    int i, s, ret, bad_found, full_found;
>>    long max_queue, queue_length;
>> -    char *uf;
>> -
>> +    char *uf, id[UUID_STR_LEN + 1];
>> +    
>>    /* XXX handle ack here? */
>>    if (msg_type(msg) != sms) {
>>        error(0, "Attempt to route non SMS message through smsc2_rout!");
>> @@ -1229,6 +1258,29 @@
>>    bp_load = bo_load = queue_length = 0;
>> 
>>    conn = NULL;
>> +    /*if msg was a split and failed temporary then use stored connection */
>> +    if(uuid_is_null(msg->msg_ConnId) != 1) 
>> +    {    
>> +       for (i=0; i < gwlist_len(smsc_list); i++)
>> +       {
>> +          conn = gwlist_get(smsc_list,  i);
>> +          smscconn_info(conn, &info);
>> +          queue_length += (info.queued > 0 ? info.queued : 0); 
>> +          
>> +          if(uuid_compare(msg->msg_ConnId, conn->smscconn_uuid) == 0)
>> +          {  
>> +             if((smscconn_usable(conn,msg) != -1) && (info.status == SMSCCONN_ACTIVE && info.queued < max_queue))
>> +             {
>> +                best_preferred = conn;  
>> +                uuid_unparse(msg->sms.id, id);
>> +                debug("bb.sms",0,"Message [%s] with pre-set connection found", id);
>> +                continue; 
>> +             }
>> +          } 
>> +       } 
>> +    }
>> +    else
>> +    {
>>    for (i=0; i < gwlist_len(smsc_list); i++) {
>> 	conn = gwlist_get(smsc_list,  (i+s) % gwlist_len(smsc_list));
>> 
>> @@ -1265,6 +1317,8 @@
>> 	    bo_load = info.load;
>> 	}
>>    }
>> +    }
>> +    
>>    queue_length += gwlist_len(outgoing_sms);
>>    if (max_outgoing_sms_qlength > 0 && !resend &&
>>         queue_length > gwlist_len(smsc_list) * max_outgoing_sms_qlength) {
>> Index: msg.c
>> ===================================================================
>> --- msg.c	(revision 4843)
>> +++ msg.c	(working copy)
>> @@ -98,6 +98,7 @@
>>    msg = gw_malloc_trace(sizeof(Msg), file, line, func);
>> 
>>    msg->type = type;
>> +    uuid_clear(msg->msg_ConnId);
>> #define INTEGER(name) p->name = MSG_PARAM_UNDEFINED;
>> #define OCTSTR(name) p->name = NULL;
>> #define UUID(name) uuid_generate(p->name);
>> @@ -113,7 +114,7 @@
>>    Msg *new;
>> 
>>    new = msg_create(msg->type);
>> -
>> +    uuid_copy(new->msg_ConnId, msg->msg_ConnId);
>> #define INTEGER(name) p->name = q->name;
>> #define OCTSTR(name) \
>>    if (q->name == NULL) p->name = NULL; \
>> Index: msg.h
>> ===================================================================
>> --- msg.h	(revision 4843)
>> +++ msg.h	(working copy)
>> @@ -78,7 +78,7 @@
>> 
>> typedef struct {
>> 	enum msg_type type;
>> -
>> +    uuid_t msg_ConnId;       
>> 	#define INTEGER(name) long name;
>> 	#define OCTSTR(name) Octstr *name;
>> 	#define UUID(name) uuid_t name;
>> Index: smscconn.c
>> ===================================================================
>> --- smscconn.c	(revision 4843)
>> +++ smscconn.c	(working copy)
>> @@ -157,13 +157,16 @@
>>    Octstr *denied_prefix_regex;
>>    Octstr *preferred_prefix_regex;
>>    Octstr *tmp;
>> -
>> +    char id[UUID_STR_LEN + 1];
>> +        
>>    if (grp == NULL)
>> 	return NULL;
>> 
>>    conn = gw_malloc(sizeof(*conn));
>>    memset(conn, 0, sizeof(*conn));
>> 
>> +    uuid_generate(conn->smscconn_uuid);
>> +            
>>    conn->why_killed = SMSCCONN_ALIVE;
>>    conn->status = SMSCCONN_CONNECTING;
>>    conn->connect_time = -1;
>> @@ -295,7 +298,10 @@
>>    gw_assert(conn->send_msg != NULL);
>> 
>>    bb_smscconn_ready(conn);
>> -
>> +    
>> +    uuid_unparse(conn->smscconn_uuid, id);
>> +    debug("smscconn",0,"Adding smsc connection [%s] with id [%s]", octstr_get_cstr(conn->id), id);
>> +    
>>    return conn;
>> }
>> 
>> Index: smscconn_p.h
>> ===================================================================
>> --- smscconn_p.h	(revision 4843)
>> +++ smscconn_p.h	(working copy)
>> @@ -146,6 +146,8 @@
>> #include "smscconn.h"
>> 
>> struct smscconn {
>> +    /* variable added in order to uniquely identify each smsc connection */ 
>> +    uuid_t smscconn_uuid;
>>    /* variables set by appropriate SMSCConn driver */
>>    smscconn_status_t status;		/* see smscconn.h */
>>    int 	load;	       	/* load factor, 0 = no load */
> 
> 




More information about the devel mailing list