Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

bb_smscconn.c File Reference

#include "gw-config.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include "gwlib/gwlib.h"
#include "msg.h"
#include "sms.h"
#include "bearerbox.h"
#include "numhash.h"
#include "smscconn.h"
#include "dlr.h"
#include "bb_smscconn_cb.h"
#include "smscconn_p.h"

Include dependency graph for bb_smscconn.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  ConcatMsg

Typedefs

typedef ConcatMsg ConcatMsg

Enumerations

enum  { concat_error = -1, concat_complete = 0, concat_pending = 1, concat_none }

Functions

long route_incoming_to_smsc (SMSCConn *conn, Msg *msg)
void init_concat_handler (void)
void shutdown_concat_handler (void)
int check_concatenation (Msg **msg, Octstr *smscid)
void clear_old_concat_parts (void)
void bb_smscconn_ready (SMSCConn *conn)
void bb_smscconn_connected (SMSCConn *conn)
void bb_smscconn_killed (void)
void handle_split (SMSCConn *conn, Msg *msg, long reason)
void bb_smscconn_sent (SMSCConn *conn, Msg *sms, Octstr *reply)
void bb_smscconn_send_failed (SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
long bb_smscconn_receive (SMSCConn *conn, Msg *sms)
void sms_router (void *arg)
int smsc2_start (Cfg *cfg)
long smsc2_find (Octstr *id, long start)
int smsc2_stop_smsc (Octstr *id)
int smsc2_restart_smsc (Octstr *id)
void smsc2_resume (void)
void smsc2_suspend (void)
int smsc2_shutdown (void)
void smsc2_cleanup (void)
Octstrsmsc2_status (int status_type)
long smsc2_rout (Msg *msg, int resend)
void destroy_concatMsg (void *x)

Variables

volatile sig_atomic_t bb_status
Listincoming_sms
Listoutgoing_sms
Counterincoming_sms_counter
Counteroutgoing_sms_counter
Listflow_threads
Listsuspended
Listisolated
long max_outgoing_sms_qlength
long max_incoming_sms_qlength
volatile sig_atomic_t smsc_running
Listsmsc_list
RWLock smsc_list_lock
Listsmsc_groups
Octstrunified_prefix
Numhashblack_list
Numhashwhite_list
regex_t * white_list_regex
regex_t * black_list_regex
long router_thread = -1
long sms_resend_frequency
long sms_resend_retry
Countersplit_msg_counter
int handle_concatenated_mo
long concatenated_mo_timeout
Dictincoming_concat_msgs
Mutexconcat_lock


Typedef Documentation

typedef struct ConcatMsg ConcatMsg
 


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
concat_error 
concat_complete 
concat_pending 
concat_none 

Definition at line 143 of file bb_smscconn.c.


Function Documentation

void bb_smscconn_connected SMSCConn conn  ) 
 

Definition at line 168 of file bb_smscconn.c.

References gwthread_wakeup(), router_thread, and SMSCConn.

Referenced by at2_device_thread(), cgw_open_send_connection(), cgw_sender(), fake_listener(), handle_pdu(), io_thread(), open_send_connection(), reconnect(), and soap_listener().

00169 {
00170     if (router_thread >= 0)
00171     gwthread_wakeup(router_thread);
00172 }

Here is the call graph for this function:

void bb_smscconn_killed void   ) 
 

Definition at line 175 of file bb_smscconn.c.

References flow_threads, gwlist_remove_producer(), and incoming_sms.

Referenced by at2_device_thread(), cgw_sender(), cimd2_shutdown_cb(), emi2_sender(), fake_listener(), httpsmsc_send_cb(), oisd_shutdown_cb(), shutdown_cb(), soap_listener(), and wrapper_sender().

00176 {
00177     /* NOTE: after status has been set to SMSCCONN_DEAD, bearerbox
00178      *   is free to release/delete 'conn'
00179      */
00180     gwlist_remove_producer(incoming_sms);
00181     gwlist_remove_producer(flow_threads);
00182 }

Here is the call graph for this function:

void bb_smscconn_ready SMSCConn conn  ) 
 

Definition at line 161 of file bb_smscconn.c.

References flow_threads, gwlist_add_producer(), incoming_sms, and SMSCConn.

Referenced by smscconn_create().

00162 {
00163     gwlist_add_producer(flow_threads);
00164     gwlist_add_producer(incoming_sms);
00165 }

Here is the call graph for this function:

long bb_smscconn_receive SMSCConn conn,
Msg sms
 

Definition at line 350 of file bb_smscconn.c.

References ack_failed, bb_alog_sms(), black_list, black_list_regex, check_concatenation(), concat_complete, concat_error, concat_none, concat_pending, counter_increase(), gwthread_sleep(), handle_concatenated_mo, smscconn::id, incoming_sms_counter, info(), msg_destroy(), msg_duplicate(), normalize_number(), numhash_find_number(), octstr_get_cstr, panic, smscconn::received, route_incoming_to_boxc(), route_incoming_to_smsc(), sms, SMSCConn, SMSCCONN_FAILED_QFULL, SMSCCONN_SUCCESS, store_save, store_save_ack, smscconn::unified_prefix, unified_prefix, warning(), white_list, and white_list_regex.

Referenced by at2_wait_modem_command(), bb_smscconn_send_failed(), bb_smscconn_sent(), brunet_receive_sms(), cgw_handle_op(), clear_old_concat_parts(), clickatell_receive_sms(), handle_operation(), handle_pdu(), io_thread(), kannel_receive_sms(), main_connection_loop(), msg_to_bb(), soap_parse_dlr(), soap_parse_mo(), wrapper_receiver(), and xidris_receive_sms().

00351 {
00352     char *uf;
00353     int rc;
00354     Msg *copy;
00355 
00356    /*
00357     * First normalize in smsc level and then on global level.
00358     * In outbound direction it's vise versa, hence first global then smsc.
00359     */
00360     uf = (conn && conn->unified_prefix) ? octstr_get_cstr(conn->unified_prefix) : NULL;
00361     normalize_number(uf, &(sms->sms.sender));
00362 
00363     uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
00364     normalize_number(uf, &(sms->sms.sender));
00365 
00366     if (white_list &&
00367     numhash_find_number(white_list, sms->sms.sender) < 1) {
00368     info(0, "Number <%s> is not in white-list, message discarded",
00369          octstr_get_cstr(sms->sms.sender));
00370     bb_alog_sms(conn, sms, "REJECTED - not white-listed SMS");
00371     msg_destroy(sms);
00372         return SMSCCONN_FAILED_REJECTED;
00373     }
00374 
00375     if (white_list_regex && gw_regex_match_pre(white_list_regex, sms->sms.sender) == 0) {
00376         info(0, "Number <%s> is not in white-list, message discarded",
00377              octstr_get_cstr(sms->sms.sender));
00378         bb_alog_sms(conn, sms, "REJECTED - not white-regex-listed SMS");
00379         msg_destroy(sms);
00380         return SMSCCONN_FAILED_REJECTED;
00381     }
00382     
00383     if (black_list &&
00384     numhash_find_number(black_list, sms->sms.sender) == 1) {
00385     info(0, "Number <%s> is in black-list, message discarded",
00386          octstr_get_cstr(sms->sms.sender));
00387     bb_alog_sms(conn, sms, "REJECTED - black-listed SMS");
00388     msg_destroy(sms);
00389     return SMSCCONN_FAILED_REJECTED;
00390     }
00391 
00392     if (black_list_regex && gw_regex_match_pre(black_list_regex, sms->sms.sender) == 0) {
00393         info(0, "Number <%s> is not in black-list, message discarded",
00394              octstr_get_cstr(sms->sms.sender));
00395         bb_alog_sms(conn, sms, "REJECTED - black-regex-listed SMS");
00396         msg_destroy(sms);
00397         return SMSCCONN_FAILED_REJECTED;
00398     }
00399 
00400     /* fix sms type if not set already */
00401     if (sms->sms.sms_type != report_mo)
00402         sms->sms.sms_type = mo;
00403 
00404     /* write to store (if enabled) */
00405     if (store_save(sms) == -1) {
00406         msg_destroy(sms);
00407         return SMSCCONN_FAILED_TEMPORARILY;
00408     }
00409 
00410     copy = msg_duplicate(sms);
00411 
00412     /*
00413      * Try to reroute internally to an smsc-id without leaving
00414      * actually bearerbox scope.
00415      * Scope: internal routing (to smsc-ids)
00416      */
00417     if ((rc = route_incoming_to_smsc(conn, copy)) == -1) {
00418         int ret;
00419         /* Before routing to some box, do concat handling
00420          * and replace copy as such.
00421          */
00422         if (handle_concatenated_mo && copy->sms.sms_type == mo) {
00423             ret = check_concatenation(&copy, (conn ? conn->id : NULL));
00424             switch(ret) {
00425             case concat_pending:
00426                 counter_increase(incoming_sms_counter); /* ?? */
00427                 if (conn != NULL)
00428                     counter_increase(conn->received);
00429                 msg_destroy(sms);
00430                 return SMSCCONN_SUCCESS;
00431             case concat_complete:
00432                 /* Combined sms received! save new one since it is now combined. */ 
00433                 msg_destroy(sms);
00434                 /* Change the sms. */
00435                 sms = msg_duplicate(copy);
00436                 break;
00437             case concat_error:
00438                 /* failed to save, go away. */
00439                 msg_destroy(sms);
00440                 return SMSCCONN_FAILED_TEMPORARILY;
00441             case concat_none:
00442                 break;
00443             default:
00444                 panic(0, "Internal error: Unhandled concat result.");
00445                 break;
00446             }
00447         }
00448         /*
00449          * Now try to route the message to a specific smsbox
00450          * connection based on the existing msg->sms.boxc_id or
00451          * the registered receiver numbers for specific smsbox'es.
00452          * Scope: external routing (to smsbox connections)
00453          */
00454         rc = route_incoming_to_boxc(copy);
00455     }
00456     
00457     if (rc == -1 || (rc != SMSCCONN_SUCCESS && rc != SMSCCONN_QUEUED)) {
00458         warning(0, "incoming messages queue too long, dropping a message");
00459         if (sms->sms.sms_type == report_mo)
00460            bb_alog_sms(conn, sms, "DROPPED Received DLR");
00461         else
00462            bb_alog_sms(conn, sms, "DROPPED Received SMS");
00463 
00464         /* put nack into store-file */
00465         store_save_ack(sms, ack_failed);
00466 
00467         msg_destroy(copy);
00468         msg_destroy(sms);
00469         gwthread_sleep(0.1); /* letting the queue go down */
00470         return (rc == -1 ? SMSCCONN_FAILED_QFULL : rc);
00471     }
00472 
00473     if (sms->sms.sms_type != report_mo)
00474     bb_alog_sms(conn, sms, "Receive SMS");
00475     else
00476     bb_alog_sms(conn, sms, "Receive DLR");
00477 
00478     counter_increase(incoming_sms_counter);
00479     if (conn != NULL) counter_increase(conn->received);
00480 
00481     msg_destroy(sms);
00482 
00483     return SMSCCONN_SUCCESS;
00484 }

Here is the call graph for this function:

void bb_smscconn_send_failed SMSCConn conn,
Msg sms,
int  reason,
Octstr reply
 

Definition at line 281 of file bb_smscconn.c.

References ack_failed, bb_alog_sms(), bb_smscconn_receive(), counter_increase(), create_dlr_from_msg(), DLR_IS_FAIL, DLR_IS_SMSC_FAIL, DLR_SMSC_FAIL, smscconn::failed, gwlist_produce(), handle_split(), smscconn::id, msg_destroy(), smscconn::name, octstr_create, octstr_destroy(), octstr_insert_data(), outgoing_sms, reason, sms, sms_resend_retry, SMSCConn, SMSCCONN_FAILED_DISCARDED, SMSCCONN_FAILED_SHUTDOWN, SMSCCONN_FAILED_TEMPORARILY, smscconn_status(), store_save_ack, and warning().

Referenced by at2_send_one_message(), at2_shutdown_cb(), brunet_parse_reply(), cgw_handle_op(), cgw_open_send_connection(), cgw_sender(), cgw_shutdown_cb(), cimd2_shutdown_cb(), cimd2_submit_msg(), clickatell_parse_reply(), do_queue_cleanup(), emi2_handle_smscreq(), emi2_sender(), fake_listener(), generic_parse_reply(), handle_pdu(), handle_split(), io_thread(), kannel_parse_reply(), main_connection_loop(), oisd_shutdown_cb(), oisd_submit_msg(), open_send_connection(), reconnect(), send_messages(), shutdown_cb(), sms_send(), smsc2_rout(), soap_listener(), soap_read_response(), soap_send_loop(), soap_shutdown_cb(), wapme_smsproxy_parse_reply(), wrapper_sender(), wrapper_shutdown(), and xidris_parse_reply().

00282 {
00283     if (sms->sms.split_parts != NULL) {
00284         handle_split(conn, sms, reason);
00285         octstr_destroy(reply);
00286         return;
00287     }
00288     
00289     switch (reason) {
00290     case SMSCCONN_FAILED_TEMPORARILY:
00291         /*
00292          * Check if SMSC link alive and if so increase resend_try and set resend_time.
00293          * If SMSC link is not active don't increase resend_try and don't set resend_time
00294          * because we don't want to delay messages because of connection broken.
00295          */
00296        if (conn && smscconn_status(conn) == SMSCCONN_ACTIVE) {
00297             /*
00298              * Check if sms_resend_retry set and this msg has exceeded a limit also
00299              * honor "single shot" with sms_resend_retry set to zero.
00300              */
00301            if (sms_resend_retry >= 0 && sms->sms.resend_try >= sms_resend_retry) {
00302                warning(0, "Maximum retries for message exceeded, discarding it!");
00303                bb_smscconn_send_failed(NULL, sms, SMSCCONN_FAILED_DISCARDED, 
00304                                        octstr_create("Retries Exceeded"));
00305                break;
00306            }
00307            sms->sms.resend_try = (sms->sms.resend_try > 0 ? sms->sms.resend_try + 1 : 1);
00308            time(&sms->sms.resend_time);
00309        }
00310        gwlist_produce(outgoing_sms, sms);
00311        break;
00312        
00313     case SMSCCONN_FAILED_SHUTDOWN:
00314         gwlist_produce(outgoing_sms, sms);
00315         break;
00316 
00317     default:
00318     /* write NACK to store file */
00319         store_save_ack(sms, ack_failed);
00320 
00321     if (conn) counter_increase(conn->failed);
00322     if (reason == SMSCCONN_FAILED_DISCARDED)
00323         bb_alog_sms(conn, sms, "DISCARDED SMS");
00324     else
00325         bb_alog_sms(conn, sms, "FAILED Send SMS");
00326 
00327         /* generate relay confirmancy message */
00328         if (DLR_IS_SMSC_FAIL(sms->sms.dlr_mask) ||
00329         DLR_IS_FAIL(sms->sms.dlr_mask)) {
00330             Msg *dlrmsg;
00331 
00332         if (reply == NULL)
00333             reply = octstr_create("");
00334 
00335         octstr_insert_data(reply, 0, "NACK/", 5);
00336             dlrmsg = create_dlr_from_msg((conn ? (conn->id?conn->id:conn->name) : NULL), sms,
00337                                      reply, DLR_SMSC_FAIL);
00338             if (dlrmsg != NULL) {
00339                 bb_smscconn_receive(conn, dlrmsg);
00340             }
00341         }
00342 
00343         msg_destroy(sms);
00344         break;
00345     }
00346 
00347     octstr_destroy(reply);
00348 }

Here is the call graph for this function:

void bb_smscconn_sent SMSCConn conn,
Msg sms,
Octstr reply
 

Definition at line 245 of file bb_smscconn.c.

References ack_success, bb_alog_sms(), bb_smscconn_receive(), counter_increase(), create_dlr_from_msg(), DLR_IS_SMSC_SUCCESS, DLR_SMSC_SUCCESS, handle_split(), smscconn::id, msg_destroy(), smscconn::name, octstr_create, octstr_destroy(), octstr_insert_data(), outgoing_sms_counter, smscconn::sent, sms, SMSCConn, SMSCCONN_SUCCESS, and store_save_ack.

Referenced by at2_send_one_message(), brunet_parse_reply(), cgw_handle_op(), cimd2_submit_msg(), clickatell_parse_reply(), emi2_handle_smscreq(), generic_parse_reply(), handle_pdu(), handle_split(), kannel_parse_reply(), main_connection_loop(), oisd_submit_msg(), sms_send(), soap_read_response(), wapme_smsproxy_parse_reply(), and xidris_parse_reply().

00246 {
00247     if (sms->sms.split_parts != NULL) {
00248         handle_split(conn, sms, SMSCCONN_SUCCESS);
00249         octstr_destroy(reply);
00250         return;
00251     }
00252     
00253     counter_increase(outgoing_sms_counter);
00254     if (conn) counter_increase(conn->sent);
00255 
00256     /* write ACK to store file */
00257     store_save_ack(sms, ack_success);
00258 
00259     bb_alog_sms(conn, sms, "Sent SMS");
00260 
00261     /* generate relay confirmancy message */
00262     if (DLR_IS_SMSC_SUCCESS(sms->sms.dlr_mask)) {
00263         Msg *dlrmsg;
00264 
00265     if (reply == NULL)
00266         reply = octstr_create("");
00267 
00268     octstr_insert_data(reply, 0, "ACK/", 4);
00269         dlrmsg = create_dlr_from_msg((conn->id?conn->id:conn->name), sms,
00270                     reply, DLR_SMSC_SUCCESS);
00271         if (dlrmsg != NULL) {
00272             bb_smscconn_receive(conn, dlrmsg);
00273         }
00274     }
00275 
00276     msg_destroy(sms);
00277     octstr_destroy(reply);
00278 }

Here is the call graph for this function:

int check_concatenation Msg **  msg,
Octstr smscid
[static]
 

Definition at line 1341 of file bb_smscconn.c.

References ack_success, concat_lock, debug(), dict_get(), dict_put(), error(), incoming_concat_msgs, ConcatMsg::key, msg_destroy(), msg_dump(), msg_duplicate(), mutex_lock, mutex_unlock, ConcatMsg::num_parts, octstr_append(), octstr_delete(), octstr_destroy(), octstr_duplicate, octstr_format(), octstr_get_char(), octstr_get_cstr, octstr_len(), octstr_set_char(), ConcatMsg::parts, ConcatMsg::refnum, store_save, store_save_ack, ConcatMsg::total_parts, ConcatMsg::trecv, uuid_generate(), and warning().

Referenced by bb_smscconn_receive().

01342 {
01343     Msg *msg = *pmsg;
01344     int l, iel, refnum, pos, c, part, totalparts, i, sixteenbit;
01345     Octstr *udh = msg->sms.udhdata, *key;
01346     ConcatMsg *cmsg;
01347     int ret = concat_complete;
01348 
01349     /* ... module not initialised or there is no UDH or smscid is NULL. */
01350     if (incoming_concat_msgs == NULL || (l = octstr_len(udh)) == 0 || smscid == NULL)
01351         return concat_none;
01352 
01353     for (pos = 1, c = -1; pos < l - 1; pos += iel + 2) {
01354         iel = octstr_get_char(udh, pos + 1);
01355         if ((c = octstr_get_char(udh,pos)) == 0 || c == 8)
01356             break;
01357     }
01358     if (pos >= l)  /* no concat UDH found. */
01359         return concat_none;
01360 
01361     /* c = 0 means 8 bit, c = 8 means 16 bit concat info */
01362     sixteenbit = (c == 8);
01363     refnum = (!sixteenbit) ? octstr_get_char(udh, pos + 2) :
01364         (octstr_get_char(udh, pos + 2) << 8) | octstr_get_char(udh, pos + 3);
01365     totalparts = octstr_get_char(udh, pos + 3 + sixteenbit);
01366     part = octstr_get_char(udh, pos + 4 + sixteenbit);
01367 
01368     if (part < 1 || part > totalparts) {
01369         warning(0, "Invalid concatenation UDH [ref = %d] in message from %s!",
01370                 refnum, octstr_get_cstr(msg->sms.sender));
01371         return concat_none;
01372     }
01373 
01374     debug("bb.sms.splits", 0, "Got part %d [ref %d, total parts %d] of message from %s. Dump follows:",
01375           part, refnum,totalparts, octstr_get_cstr(msg->sms.sender));
01376      
01377     msg_dump(msg,0);
01378      
01379     key = octstr_format("%S %S %S %d", msg->sms.sender, msg->sms.receiver, smscid, refnum);
01380     mutex_lock(concat_lock);
01381     if ((cmsg = dict_get(incoming_concat_msgs, key)) == NULL) {
01382         cmsg = gw_malloc(sizeof(*cmsg));
01383         cmsg->refnum = refnum;
01384         cmsg->total_parts = totalparts;
01385         cmsg->num_parts = 0;
01386         cmsg->key = octstr_duplicate(key);
01387         cmsg->ack = ack_success;
01388         cmsg->parts = gw_malloc(totalparts * sizeof(*cmsg->parts));
01389         memset(cmsg->parts, 0, cmsg->total_parts * sizeof(*cmsg->parts)); /* clear it. */
01390 
01391         dict_put(incoming_concat_msgs, key, cmsg);
01392     }
01393     octstr_destroy(key);
01394 
01395     if (totalparts != cmsg->total_parts) {
01396         /* totalparts in udh and cmsg not equal assume bad message */
01397         error(0, "Totalparts in UDH doesn't match received before, "
01398                 "total parts <%d>:<%d> part %d, ref %d, from %s, to %s. Discarded!",
01399                 cmsg->total_parts, totalparts, part, refnum, octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver));
01400         mutex_unlock(concat_lock);
01401         store_save_ack(msg, ack_success);
01402         msg_destroy(msg);
01403         *pmsg = msg = NULL;
01404         return concat_error;
01405     }
01406 
01407     /* check if we have seen message part before... */
01408     if (cmsg->parts[part - 1] != NULL) {      
01409         warning(0, "Duplicate message part %d, ref %d, from %s, to %s. Discarded!",
01410                 part, refnum, octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver));
01411         store_save_ack(msg, ack_success);
01412         msg_destroy(msg); 
01413         *pmsg = msg = NULL;
01414     } else {
01415         cmsg->parts[part -1] = msg;
01416         cmsg->num_parts++;
01417         /* always update receive time so we have it from last part and don't timeout */
01418         cmsg->trecv = time(NULL);
01419     }
01420 
01421     if (cmsg->num_parts < cmsg->total_parts) {  /* wait for more parts. */
01422         *pmsg = msg = NULL;
01423         mutex_unlock(concat_lock);
01424         return concat_pending;
01425     }
01426 
01427     /* we have all the parts: Put them together, mod UDH, return message. */
01428     msg = msg_duplicate(cmsg->parts[0]);
01429     uuid_generate(msg->sms.id); /* give it a new ID. */
01430 
01431     debug("bb.sms.splits",0,"Received all concatenated message parts from %s, to %s, refnum %d",
01432           octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver), refnum);
01433 
01434     for (i = 1; i < cmsg->total_parts; i++)
01435         octstr_append(msg->sms.msgdata, cmsg->parts[i]->sms.msgdata);
01436 
01437     /* Attempt to save the new one, if that fails, then reply with fail. */
01438     if (store_save(msg) == -1) {      
01439         mutex_unlock(concat_lock);
01440         msg_destroy(msg);
01441         *pmsg = msg = NULL;
01442         return concat_error;
01443     } else 
01444         *pmsg = msg; /* return the message part. */
01445 
01446     /* Delete it from the queue and from the Dict. */
01447     /* Note: dict_put with NULL value delete and destroy value */
01448     dict_put(incoming_concat_msgs, cmsg->key, NULL);
01449     mutex_unlock(concat_lock);
01450 
01451     /* fix up UDH */
01452     udh = msg->sms.udhdata;
01453     l = octstr_len(udh);
01454     for (pos = 1; pos < l - 1; pos += iel + 2) {
01455         iel = octstr_get_char(udh, pos + 1);
01456         if ((c = octstr_get_char(udh, pos)) == 0 || c == 8) {
01457             octstr_delete(udh, pos, iel + 2);
01458 
01459             if (octstr_len(udh) <= 1) /* no other UDH elements. */
01460                 octstr_delete(udh, 0, octstr_len(udh));
01461             else
01462                 octstr_set_char(udh, 0, octstr_len(udh) - 1);
01463             break;
01464         }
01465     }
01466     debug("bb.sms.splits", 0, "Got full message [ref %d] of message from %s to %s. Dumping: ",
01467           refnum, octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver));
01468     msg_dump(msg,0);
01469 
01470     return ret;
01471 }

Here is the call graph for this function:

void clear_old_concat_parts void   )  [static]
 

Definition at line 1251 of file bb_smscconn.c.

References ack_success, bb_smscconn_receive(), concat_lock, debug(), destroy_concatMsg(), dict_get(), dict_keys(), dict_put(), dict_remove(), gwlist_destroy(), gwlist_extract_first(), incoming_concat_msgs, ConcatMsg::key, msg_destroy(), msg_duplicate(), mutex_lock, mutex_unlock, ConcatMsg::num_parts, octstr_destroy(), octstr_destroy_item(), octstr_format_append(), octstr_get_cstr, ConcatMsg::parts, SMSCCONN_FAILED_QFULL, SMSCCONN_FAILED_REJECTED, SMSCCONN_FAILED_TEMPORARILY, SMSCCONN_SUCCESS, store_save, store_save_ack, ConcatMsg::total_parts, ConcatMsg::trecv, and warning().

Referenced by sms_router().

01252 {
01253     List *keys;
01254     Octstr *key;
01255 
01256     /* not initialised, go away */
01257     if (incoming_concat_msgs == NULL)
01258         return;
01259 
01260     debug("bb.sms.splits", 0, "clear_old_concat_parts called");
01261 
01262     /* Remove any pending messages that are too old. */
01263     keys = dict_keys(incoming_concat_msgs);
01264     while((key = gwlist_extract_first(keys)) != NULL) {
01265         ConcatMsg *x;
01266         Msg *msg;
01267         int i, destroy = 1;
01268 
01269         mutex_lock(concat_lock);
01270         x = dict_get(incoming_concat_msgs, key);
01271         octstr_destroy(key);
01272         if (x == NULL || difftime(time(NULL), x->trecv) < concatenated_mo_timeout) {
01273             mutex_unlock(concat_lock);
01274             continue;
01275         }
01276         dict_remove(incoming_concat_msgs, x->key);
01277         mutex_unlock(concat_lock);
01278         warning(0, "Time-out waiting for concatenated message '%s'. Send message parts as is.",
01279                 octstr_get_cstr(x->key));
01280         for (i = 0; i < x->total_parts && destroy == 1; i++) {
01281             if (x->parts[i] == NULL)
01282                 continue;
01283             msg = msg_duplicate(x->parts[i]);
01284             store_save_ack(x->parts[i], ack_success);
01285             switch(bb_smscconn_receive(NULL, msg)) {
01286             case SMSCCONN_FAILED_REJECTED:
01287             case SMSCCONN_SUCCESS:
01288                 msg_destroy(x->parts[i]);
01289                 x->parts[i] = NULL;
01290                 x->num_parts--;
01291                 break;
01292             case SMSCCONN_FAILED_TEMPORARILY:
01293             case SMSCCONN_FAILED_QFULL:
01294             default:
01295                 /* oops put it back into dict and retry on next run */
01296                 store_save(x->parts[i]);
01297                 destroy = 0;
01298                 break;
01299             }
01300         }
01301         if (destroy) {
01302             destroy_concatMsg(x);
01303         } else {
01304             ConcatMsg *x1;
01305             mutex_lock(concat_lock);
01306             x1 = dict_get(incoming_concat_msgs, x->key);
01307             if (x1 != NULL) { /* oops we have new part */
01308                 int i;
01309                 if (x->total_parts != x1->total_parts) {
01310                     /* broken handset, don't know what todo here??
01311                      * for now just put old concatMsg into dict with
01312                      * another key and it will be cleaned up on next run.
01313                      */
01314                     octstr_format_append(x->key, " %d", x->total_parts);
01315                     dict_put(incoming_concat_msgs, x->key, x);
01316                 } else {
01317                     for (i = 0; i < x->total_parts; i++) {
01318                         if (x->parts[i] == NULL)
01319                             continue;
01320                         if (x1->parts[i] == NULL) {
01321                             x1->parts[i] = x->parts[i];
01322                             x->parts[i] = NULL;
01323                         }
01324                     }
01325                     destroy_concatMsg(x);
01326                 }
01327             } else {
01328                 dict_put(incoming_concat_msgs, x->key, x);
01329             }
01330             mutex_unlock(concat_lock);
01331         }
01332     }
01333     gwlist_destroy(keys, octstr_destroy_item);
01334 }

Here is the call graph for this function:

void destroy_concatMsg void *  x  )  [static]
 

Definition at line 1212 of file bb_smscconn.c.

References ConcatMsg::ack, gw_assert, ConcatMsg::key, msg_destroy(), octstr_destroy(), ConcatMsg::parts, store_save_ack, and ConcatMsg::total_parts.

Referenced by clear_old_concat_parts(), and init_concat_handler().

01213 {
01214     int i;
01215     ConcatMsg *msg = x;
01216 
01217     gw_assert(msg);
01218     for (i = 0; i < msg->total_parts; i++) {
01219         if (msg->parts[i]) {
01220             store_save_ack(msg->parts[i], msg->ack);
01221             msg_destroy(msg->parts[i]);
01222         }
01223     }
01224     gw_free(msg->parts);
01225     octstr_destroy(msg->key);
01226     gw_free(msg);
01227 }

Here is the call graph for this function:

void handle_split SMSCConn conn,
Msg msg,
long  reason
[static]
 

Definition at line 185 of file bb_smscconn.c.

References bb_smscconn_send_failed(), bb_smscconn_sent(), counter_decrease(), counter_destroy(), debug(), msg_destroy(), split_parts::orig, split_parts::parts_left, reason, SMSCConn, SMSCCONN_ACTIVE, SMSCCONN_FAILED_DISCARDED, SMSCCONN_FAILED_MALFORMED, SMSCCONN_FAILED_REJECTED, SMSCCONN_FAILED_TEMPORARILY, smscconn_send(), smscconn_status(), SMSCCONN_SUCCESS, and split_parts::status.

Referenced by bb_smscconn_send_failed(), and bb_smscconn_sent().

00186 {
00187     struct split_parts *split = msg->sms.split_parts;
00188     
00189     /*
00190      * If temporarely failed, try again immediately but only if connection active.
00191      * Because if connection is not active we will loop for ever here consuming 100% CPU
00192      * time due to internal queue cleanup in smsc module that call bb_smscconn_failed.
00193      */
00194     if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
00195         smscconn_send(conn, msg) == 0) {
00196         /* destroy this message because it will be duplicated in smsc module */
00197         msg_destroy(msg);
00198         return;
00199     }
00200     
00201     /*
00202      * if the reason is not a success and status is still success
00203      * then set status of a split to the reason.
00204      * Note: reason 'malformed','discarded' or 'rejected' has higher priority!
00205      */
00206     switch(reason) {
00207     case SMSCCONN_FAILED_DISCARDED:
00208     case SMSCCONN_FAILED_REJECTED:
00209     case SMSCCONN_FAILED_MALFORMED:
00210         debug("bb.sms.splits", 0, "Set split msg status to %ld", reason);
00211         split->status = reason;
00212         break;
00213     case SMSCCONN_SUCCESS:
00214         break; /* nothing todo */
00215     default:
00216         if (split->status == SMSCCONN_SUCCESS) {
00217             debug("bb.sms.splits", 0, "Set split msg status to %ld", reason);
00218             split->status = reason;
00219         }
00220         break;
00221     }
00222 
00223     /*
00224      * now destroy this message, because we don't need it anymore.
00225      * we will split it again in smscconn_send(...).
00226      */
00227     msg_destroy(msg);
00228         
00229     if (counter_decrease(split->parts_left) <= 1) {
00230         /* all splited parts were processed */
00231         counter_destroy(split->parts_left);
00232         msg = split->orig;
00233         msg->sms.split_parts = NULL;
00234         if (split->status == SMSCCONN_SUCCESS)
00235             bb_smscconn_sent(conn, msg, NULL);
00236         else {
00237             debug("bb.sms.splits", 0, "Parts of concatenated message failed.");
00238             bb_smscconn_send_failed(conn, msg, split->status, NULL);
00239         }
00240         gw_free(split);
00241     }
00242 }

Here is the call graph for this function:

void init_concat_handler void   )  [static]
 

Definition at line 1229 of file bb_smscconn.c.

References concat_lock, debug(), destroy_concatMsg(), dict_create(), incoming_concat_msgs, max_incoming_sms_qlength, and mutex_create.

Referenced by smsc2_start().

01230 {
01231     if (incoming_concat_msgs != NULL) /* already initialised? */
01232         return;
01233     incoming_concat_msgs = dict_create(max_incoming_sms_qlength > 0 ? max_incoming_sms_qlength : 1024, 
01234                                        destroy_concatMsg);
01235     concat_lock = mutex_create();
01236     debug("bb.sms",0,"smsbox MO concatenated message handling enabled");
01237 }

Here is the call graph for this function:

long route_incoming_to_smsc SMSCConn conn,
Msg msg
[static]
 

Definition at line 1141 of file bb_smscconn.c.

References ack_success, dict_get(), octstr_destroy(), octstr_duplicate, report_mo, smscconn::reroute, smscconn::reroute_by_receiver, smscconn::reroute_dlr, smscconn::reroute_to_smsc, smsc2_rout(), SMSCConn, store_save, and store_save_ack.

Referenced by bb_smscconn_receive().

01142 {
01143     Octstr *smsc;
01144     
01145     /* sanity check */
01146     if (!conn || !msg)
01147         return -1;
01148         
01149     /* check for dlr rerouting */
01150     if (!conn->reroute_dlr && (msg->sms.sms_type == report_mo || msg->sms.sms_type == report_mt))
01151         return -1;
01152 
01153     /*
01154      * Check if we have any "reroute" rules to obey. Which means msg gets
01155      * transported internally from MO to MT msg.
01156      */
01157     if (conn->reroute) {
01158         /* change message direction */
01159         store_save_ack(msg, ack_success);
01160         msg->sms.sms_type = mt_push;
01161         store_save(msg);
01162         /* drop into outbound queue again for routing */
01163         return smsc2_rout(msg, 0);
01164     }
01165     
01166     if (conn->reroute_to_smsc) {
01167         /* change message direction */
01168         store_save_ack(msg, ack_success);
01169         msg->sms.sms_type = mt_push;
01170         store_save(msg);
01171         /* apply directly to the given smsc-id for MT traffic */
01172         octstr_destroy(msg->sms.smsc_id);
01173         msg->sms.smsc_id = octstr_duplicate(conn->reroute_to_smsc);
01174         return smsc2_rout(msg, 0);
01175     }
01176     
01177     if (conn->reroute_by_receiver && msg->sms.receiver &&
01178                  (smsc = dict_get(conn->reroute_by_receiver, msg->sms.receiver))) {
01179         /* change message direction */
01180         store_save_ack(msg, ack_success);
01181         msg->sms.sms_type = mt_push;
01182         store_save(msg);
01183         /* route by receiver number */
01184         /* XXX implement wildcard matching too! */
01185         octstr_destroy(msg->sms.smsc_id);
01186         msg->sms.smsc_id = octstr_duplicate(smsc);
01187         return smsc2_rout(msg, 0);
01188     }
01189 
01190     return -1; 
01191 }

Here is the call graph for this function:

void shutdown_concat_handler void   )  [static]
 

Definition at line 1239 of file bb_smscconn.c.

References concat_lock, debug(), dict_destroy(), incoming_concat_msgs, and mutex_destroy().

Referenced by smsc2_cleanup().

01240 {
01241     if (incoming_concat_msgs == NULL)
01242         return;
01243     dict_destroy(incoming_concat_msgs);
01244     mutex_destroy(concat_lock);
01245 
01246     incoming_concat_msgs = NULL;
01247     concat_lock = NULL;
01248     debug("bb.sms",0,"smsbox MO concatenated message handling cleaned up");
01249 }

Here is the call graph for this function:

void sms_router void *  arg  )  [static]
 

Definition at line 496 of file bb_smscconn.c.

References BB_SHUTDOWN, bb_status, clear_old_concat_parts(), concatenated_mo_timeout, debug(), flow_threads, gwlist_add_producer(), gwlist_len(), gwlist_produce(), gwlist_remove_producer(), gwlist_timed_consume(), gwthread_sleep(), gwthread_wakeup(), MAIN_THREAD_ID, msg_destroy(), outgoing_sms, sms_resend_frequency, smsc2_rout(), SMSCCONN_FAILED_DISCARDED, SMSCCONN_FAILED_QFULL, SMSCCONN_QUEUED, and SMSCCONN_SUCCESS.

Referenced by smsc2_start().

00497 {
00498     Msg *msg, *startmsg, *newmsg;
00499     long ret;
00500     time_t concat_mo_check;
00501 
00502     gwlist_add_producer(flow_threads);
00503     gwthread_wakeup(MAIN_THREAD_ID);
00504 
00505     startmsg = newmsg = NULL;
00506     ret = SMSCCONN_SUCCESS;
00507     concat_mo_check = time(NULL);
00508 
00509     while(bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) {
00510 
00511     if (newmsg == startmsg) {
00512             if (ret == SMSCCONN_QUEUED || ret == SMSCCONN_FAILED_QFULL) {
00513                 /* sleep: sms_resend_frequency / 2 , so we reduce amount of msgs to send */
00514                 double sleep_time = (sms_resend_frequency / 2 > 1 ? sms_resend_frequency / 2 : sms_resend_frequency);
00515                 debug("bb.sms", 0, "sms_router: time to sleep %.2f secs.", sleep_time);
00516                 gwthread_sleep(sleep_time);
00517                 debug("bb.sms", 0, "sms_router: gwlist_len = %ld", gwlist_len(outgoing_sms));
00518             }
00519             startmsg = msg = gwlist_timed_consume(outgoing_sms, concatenated_mo_timeout);
00520             newmsg = NULL;
00521         } else {
00522             newmsg = msg = gwlist_timed_consume(outgoing_sms, concatenated_mo_timeout);
00523         }
00524 
00525         if (difftime(time(NULL), concat_mo_check) > concatenated_mo_timeout) {
00526             concat_mo_check = time(NULL);
00527             clear_old_concat_parts();
00528         }
00529 
00530         /* shutdown or timeout */
00531         if (msg == NULL) {
00532             newmsg = startmsg = NULL;
00533             continue;
00534         }
00535 
00536         debug("bb.sms", 0, "sms_router: handling message (%p vs %p)",
00537                   msg, startmsg);
00538 
00539         /* handle delayed msgs */
00540         if (msg->sms.resend_try > 0 && difftime(time(NULL), msg->sms.resend_time) < sms_resend_frequency &&
00541             bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) {
00542             debug("bb.sms", 0, "re-queing SMS not-yet-to-be resent");
00543             gwlist_produce(outgoing_sms, msg);
00544             ret = SMSCCONN_QUEUED;
00545             continue;
00546         }
00547 
00548         ret = smsc2_rout(msg, 1);
00549         switch(ret) {
00550         case SMSCCONN_SUCCESS:
00551             debug("bb.sms", 0, "Message routed successfully.");
00552             newmsg = startmsg = NULL;
00553             break;
00554         case SMSCCONN_QUEUED:
00555             debug("bb.sms", 0, "Routing failed, re-queued.");
00556             break;
00557     case SMSCCONN_FAILED_DISCARDED:
00558             msg_destroy(msg);
00559             newmsg = startmsg = NULL;
00560             break;
00561         case SMSCCONN_FAILED_QFULL:
00562             debug("bb.sms", 0, "Routing failed, re-queuing.");
00563             gwlist_produce(outgoing_sms, msg);
00564             break;
00565         }
00566     }
00567     gwlist_remove_producer(flow_threads);
00568 }

Here is the call graph for this function:

void smsc2_cleanup void   ) 
 

Definition at line 846 of file bb_smscconn.c.

References black_list, black_list_regex, counter_destroy(), debug(), gw_regex_destroy(), gw_rwlock_destroy(), gw_rwlock_unlock(), gw_rwlock_wrlock(), gwlist_destroy(), gwlist_get(), gwlist_len(), numhash_destroy(), octstr_destroy(), shutdown_concat_handler(), smsc_groups, smsc_list, smsc_list_lock, smsc_running, SMSCConn, smscconn_destroy(), split_msg_counter, unified_prefix, white_list, and white_list_regex.

Referenced by main().

00847 {
00848     SMSCConn *conn;
00849     long i;
00850 
00851     if (!smsc_running)
00852         return;
00853 
00854     debug("smscconn", 0, "final clean-up for SMSCConn");
00855     
00856     gw_rwlock_wrlock(&smsc_list_lock);
00857     for (i = 0; i < gwlist_len(smsc_list); i++) {
00858         conn = gwlist_get(smsc_list, i);
00859         smscconn_destroy(conn);
00860     }
00861     gwlist_destroy(smsc_list, NULL);
00862     smsc_list = NULL;
00863     gw_rwlock_unlock(&smsc_list_lock);
00864     gwlist_destroy(smsc_groups, NULL);
00865     octstr_destroy(unified_prefix);    
00866     numhash_destroy(white_list);
00867     numhash_destroy(black_list);
00868     if (white_list_regex != NULL)
00869         gw_regex_destroy(white_list_regex);
00870     if (black_list_regex != NULL)
00871         gw_regex_destroy(black_list_regex);
00872     /* destroy msg split counter */
00873     counter_destroy(split_msg_counter);
00874     gw_rwlock_destroy(&smsc_list_lock);
00875 
00876     /* Stop concat handling */
00877     shutdown_concat_handler();
00878 
00879     smsc_running = 0;
00880 }

Here is the call graph for this function:

long smsc2_find Octstr id,
long  start
[static]
 

Definition at line 665 of file bb_smscconn.c.

References gwlist_get(), gwlist_len(), smscconn::id, octstr_compare(), smsc_list, and SMSCConn.

Referenced by smsc2_restart_smsc(), and smsc2_stop_smsc().

00666 {
00667     SMSCConn *conn = NULL;
00668     long i;
00669 
00670     if (start > gwlist_len(smsc_list) || start < 0)
00671         return -1;
00672 
00673     for (i = start; i < gwlist_len(smsc_list); i++) {
00674         conn = gwlist_get(smsc_list, i);
00675         if (conn != NULL && octstr_compare(conn->id, id) == 0) {
00676             break;
00677         }
00678     }
00679     if (i >= gwlist_len(smsc_list))
00680         i = -1;
00681     return i;
00682 }

Here is the call graph for this function:

int smsc2_restart_smsc Octstr id  ) 
 

Definition at line 708 of file bb_smscconn.c.

References cfg_get, error(), gw_rwlock_unlock(), gw_rwlock_wrlock(), gwlist_delete(), gwlist_get(), gwlist_insert(), gwlist_len(), gwthread_wakeup(), info(), octstr_compare(), octstr_destroy(), octstr_get_cstr, octstr_imm(), router_thread, smsc2_find(), smsc_groups, smsc_list, smsc_list_lock, SMSCConn, smscconn_create(), smscconn_destroy(), smscconn_start(), smscconn_status(), and warning().

Referenced by bb_restart_smsc().

00709 {
00710     CfgGroup *grp;
00711     SMSCConn *conn, *new_conn;
00712     Octstr *smscid = NULL;
00713     long i = -1;
00714     int num = 0;
00715 
00716     if (!smsc_running)
00717         return -1;
00718 
00719     gw_rwlock_wrlock(&smsc_list_lock);
00720     /* find the specific smsc via id */
00721     while((i = smsc2_find(id, ++i)) != -1) {
00722         int hit;
00723         long group_index;
00724         /* check if smsc has online status already */
00725         conn = gwlist_get(smsc_list, i);
00726         if (conn != NULL && smscconn_status(conn) != SMSCCONN_DEAD) {
00727             warning(0, "HTTP: Could not re-start already running smsc-id `%s'",
00728                 octstr_get_cstr(id));
00729             continue;
00730         }
00731         /* find the group with equal smsc id */
00732         hit = 0;
00733         grp = NULL;
00734         for (group_index = 0; group_index < gwlist_len(smsc_groups) && 
00735              (grp = gwlist_get(smsc_groups, group_index)) != NULL; group_index++) {
00736             smscid = cfg_get(grp, octstr_imm("smsc-id"));
00737             if (smscid != NULL && octstr_compare(smscid, id) == 0) {
00738                 if (hit == num)
00739                     break;
00740                 else
00741                     hit++;
00742             }
00743             octstr_destroy(smscid);
00744             smscid = NULL;
00745         }
00746         octstr_destroy(smscid);
00747         if (hit != num) {
00748             /* config group not found */
00749             error(0, "HTTP: Could not find config for smsc-id `%s'", octstr_get_cstr(id));
00750             break;
00751         }
00752         
00753         info(0,"HTTP: Re-starting smsc-id `%s'", octstr_get_cstr(id));
00754 
00755         new_conn = smscconn_create(grp, 1);
00756         if (new_conn == NULL) {
00757             error(0, "Start of SMSC connection failed, smsc-id `%s'", octstr_get_cstr(id));
00758             continue; /* keep old connection on the list */
00759         }
00760         
00761         /* drop old connection from the active smsc list */
00762         gwlist_delete(smsc_list, i, 1);
00763         /* destroy the connection */
00764         smscconn_destroy(conn);
00765         gwlist_insert(smsc_list, i, new_conn);
00766         smscconn_start(new_conn);
00767         num++;
00768     }
00769     gw_rwlock_unlock(&smsc_list_lock);
00770     
00771     /* wake-up the router */
00772     if (router_thread >= 0)
00773         gwthread_wakeup(router_thread);
00774     
00775     return 0;
00776 }

Here is the call graph for this function:

void smsc2_resume void   ) 
 

Definition at line 778 of file bb_smscconn.c.

References gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), gwlist_len(), gwthread_wakeup(), router_thread, smsc_list, smsc_list_lock, SMSCConn, and smscconn_start().

Referenced by bb_resume(), and main().

00779 {
00780     SMSCConn *conn;
00781     long i;
00782 
00783     if (!smsc_running)
00784         return;
00785 
00786     gw_rwlock_rdlock(&smsc_list_lock);
00787     for (i = 0; i < gwlist_len(smsc_list); i++) {
00788         conn = gwlist_get(smsc_list, i);
00789         smscconn_start(conn);
00790     }
00791     gw_rwlock_unlock(&smsc_list_lock);
00792     
00793     if (router_thread >= 0)
00794         gwthread_wakeup(router_thread);
00795 }

Here is the call graph for this function:

long smsc2_rout Msg msg,
int  resend
 

Definition at line 1004 of file bb_smscconn.c.

References bb_smscconn_send_failed(), bb_status, debug(), error(), gw_rand(), gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), gwlist_len(), gwlist_produce(), info(), smsc_state::load, max_outgoing_sms_qlength, msg_destroy(), msg_duplicate(), msg_type, normalize_number(), octstr_create, octstr_get_cstr, outgoing_sms, smsc_state::queued, resend, smsc_list, smsc_list_lock, SMSCConn, SMSCCONN_FAILED_DISCARDED, smscconn_info(), smscconn_send(), smscconn_usable(), smsc_state::status, StatusInfo, unified_prefix, and warning().

Referenced by deliver_sms_to_queue(), route_incoming_to_smsc(), and sms_router().

01005 {
01006     StatusInfo info;
01007     SMSCConn *conn, *best_preferred, *best_ok;
01008     long bp_load, bo_load;
01009     int i, s, ret, bad_found, full_found;
01010     long max_queue, queue_length;
01011     char *uf;
01012 
01013     /* XXX handle ack here? */
01014     if (msg_type(msg) != sms) {
01015         error(0, "Attempt to route non SMS message through smsc2_rout!");
01016         return SMSCCONN_FAILED_DISCARDED;
01017     }
01018 
01019     /* unify prefix of receiver, in case of it has not been
01020      * already done */
01021 
01022     uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
01023     normalize_number(uf, &(msg->sms.receiver));
01024 
01025     /* select in which list to add this
01026      * start - from random SMSCConn, as they are all 'equal'
01027      */
01028     gw_rwlock_rdlock(&smsc_list_lock);
01029     if (gwlist_len(smsc_list) == 0) {
01030         warning(0, "No SMSCes to receive message");
01031         gw_rwlock_unlock(&smsc_list_lock);
01032         return SMSCCONN_FAILED_DISCARDED;
01033     }
01034 
01035     /*
01036      * if global queue not empty then 20% reserved for old msgs
01037      * and 80% for new msgs. So we can guarantee that old msgs find
01038      * place in the SMSC's queue.
01039      */
01040     if (max_outgoing_sms_qlength > 0 && gwlist_len(outgoing_sms) > 0) {
01041         max_queue = (resend ? max_outgoing_sms_qlength :
01042                                max_outgoing_sms_qlength * 0.8);
01043     }
01044     else
01045         max_queue = (max_outgoing_sms_qlength > 0 ? max_outgoing_sms_qlength : 1000000);
01046 
01047     s = gw_rand() % gwlist_len(smsc_list);
01048     best_preferred = best_ok = NULL;
01049     bad_found = full_found = 0;
01050     bp_load = bo_load = queue_length = 0;
01051 
01052     conn = NULL;
01053     for (i=0; i < gwlist_len(smsc_list); i++) {
01054     conn = gwlist_get(smsc_list,  (i+s) % gwlist_len(smsc_list));
01055 
01056     smscconn_info(conn, &info);
01057         queue_length += (info.queued > 0 ? info.queued : 0);
01058 
01059         ret = smscconn_usable(conn,msg);
01060     if (ret == -1)
01061         continue;
01062 
01063     /* if we already have a preferred one, skip non-preferred */
01064     if (ret != 1 && best_preferred)
01065         continue;
01066 
01067     /* If connection is not currently answering ... */
01068     if (info.status != SMSCCONN_ACTIVE) {
01069         bad_found = 1;
01070         continue;
01071     }
01072         /* check queue length */
01073         if (info.queued > max_queue) {
01074             full_found = 1;
01075             continue;
01076         }
01077     if (ret == 1) {          /* preferred */
01078         if (best_preferred == NULL || info.load < bp_load) {
01079         best_preferred = conn;
01080         bp_load = info.load;
01081         continue;
01082         }
01083     }
01084     if (best_ok == NULL || info.load < bo_load) {
01085         best_ok = conn;
01086         bo_load = info.load;
01087     }
01088     }
01089     queue_length += gwlist_len(outgoing_sms);
01090     if (max_outgoing_sms_qlength > 0 && !resend &&
01091          queue_length > gwlist_len(smsc_list) * max_outgoing_sms_qlength) {
01092         gw_rwlock_unlock(&smsc_list_lock);
01093         debug("bb.sms", 0, "sum(#queues) limit");
01094         return SMSCCONN_FAILED_QFULL;
01095     }
01096 
01097     if (best_preferred)
01098     ret = smscconn_send(best_preferred, msg);
01099     else if (best_ok)
01100     ret = smscconn_send(best_ok, msg);
01101     else if (bad_found) {
01102         gw_rwlock_unlock(&smsc_list_lock);
01103         if (max_outgoing_sms_qlength < 0 || gwlist_len(outgoing_sms) < max_outgoing_sms_qlength) {
01104             gwlist_produce(outgoing_sms, msg);
01105             return SMSCCONN_QUEUED;
01106         }
01107         debug("bb.sms", 0, "bad_found queue full");
01108         return SMSCCONN_FAILED_QFULL; /* queue full */
01109     }
01110     else if (full_found) {
01111         gw_rwlock_unlock(&smsc_list_lock);
01112         debug("bb.sms", 0, "full_found queue full");
01113         return SMSCCONN_FAILED_QFULL;
01114     }
01115     else {
01116         gw_rwlock_unlock(&smsc_list_lock);
01117         if (bb_status == BB_SHUTDOWN) {
01118             msg_destroy(msg);
01119         return SMSCCONN_QUEUED;
01120         }
01121         warning(0, "Cannot find SMSCConn for message to <%s>, rejected.",
01122                     octstr_get_cstr(msg->sms.receiver));
01123         bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_DISCARDED, octstr_create("no SMSC"));
01124         return SMSCCONN_FAILED_DISCARDED;
01125     }
01126 
01127     gw_rwlock_unlock(&smsc_list_lock);
01128     /* check the status of sending operation */
01129     if (ret == -1)
01130     return smsc2_rout(msg, resend); /* re-try */
01131 
01132     msg_destroy(msg);
01133     return SMSCCONN_SUCCESS;
01134 }

Here is the call graph for this function:

int smsc2_shutdown void   ) 
 

Definition at line 815 of file bb_smscconn.c.

References gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), gwlist_len(), gwlist_remove_producer(), gwthread_wakeup(), incoming_sms, router_thread, smsc_list, smsc_list_lock, SMSCConn, and smscconn_shutdown().

Referenced by bb_shutdown().

00816 {
00817     SMSCConn *conn;
00818     long i;
00819 
00820     if (!smsc_running)
00821         return -1;
00822 
00823     /* Call shutdown for all SMSC Connections; they should
00824      * handle that they quit, by emptying queues and then dying off
00825      */
00826     gw_rwlock_rdlock(&smsc_list_lock);
00827     for(i=0; i < gwlist_len(smsc_list); i++) {
00828         conn = gwlist_get(smsc_list, i);
00829     smscconn_shutdown(conn, 1);
00830     }
00831     gw_rwlock_unlock(&smsc_list_lock);
00832     if (router_thread >= 0)
00833     gwthread_wakeup(router_thread);
00834 
00835     /* start avalanche by calling shutdown */
00836 
00837     /* XXX shouldn'w we be sure that all smsces have closed their
00838      * receive thingies? Is this guaranteed by setting bb_status
00839      * to shutdown before calling these?
00840      */
00841     gwlist_remove_producer(incoming_sms);
00842     return 0;
00843 }

Here is the call graph for this function:

int smsc2_start Cfg cfg  ) 
 

Definition at line 578 of file bb_smscconn.c.

References black_list, black_list_regex, cfg_get, cfg_get_bool(), cfg_get_integer(), cfg_get_multi_group(), cfg_get_single_group(), concatenated_mo_timeout, counter_create(), gw_rwlock_init_static(), gwlist_add_producer(), gwlist_append(), gwlist_create, gwlist_get(), gwlist_len(), gwlist_remove_producer(), gwthread_create, handle_concatenated_mo, incoming_sms, info(), init_concat_handler(), numhash_create(), octstr_destroy(), octstr_get_cstr, octstr_imm(), panic, router_thread, sms_resend_frequency, sms_resend_retry, sms_router(), smsc_groups, smsc_list, smsc_list_lock, smsc_running, SMSCConn, smscconn_create(), split_msg_counter, unified_prefix, white_list, and white_list_regex.

Referenced by start_smsc().

00579 {
00580     CfgGroup *grp;
00581     SMSCConn *conn;
00582     Octstr *os;
00583     int i;
00584 
00585     if (smsc_running) return -1;
00586 
00587     /* create split sms counter */
00588     split_msg_counter = counter_create();
00589     
00590     /* create smsc list and rwlock for it */
00591     smsc_list = gwlist_create();
00592     gw_rwlock_init_static(&smsc_list_lock);
00593 
00594     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00595     unified_prefix = cfg_get(grp, octstr_imm("unified-prefix"));
00596 
00597     white_list = black_list = NULL;
00598     os = cfg_get(grp, octstr_imm("white-list"));
00599     if (os != NULL) {
00600         white_list = numhash_create(octstr_get_cstr(os));
00601     octstr_destroy(os);
00602     }
00603     if ((os = cfg_get(grp, octstr_imm("white-list-regex"))) != NULL) {
00604         if ((white_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL)
00605             panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os));
00606         octstr_destroy(os);
00607     }
00608     
00609     os = cfg_get(grp, octstr_imm("black-list"));
00610     if (os != NULL) {
00611         black_list = numhash_create(octstr_get_cstr(os));
00612     octstr_destroy(os);
00613     }
00614     if ((os = cfg_get(grp, octstr_imm("black-list-regex"))) != NULL) {
00615         if ((black_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL)
00616             panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os));
00617         octstr_destroy(os);
00618     }
00619 
00620     if (cfg_get_integer(&sms_resend_frequency, grp,
00621             octstr_imm("sms-resend-freq")) == -1 || sms_resend_frequency <= 0) {
00622         sms_resend_frequency = 60;
00623     }
00624     info(0, "Set SMS resend frequency to %ld seconds.", sms_resend_frequency);
00625             
00626     if (cfg_get_integer(&sms_resend_retry, grp, octstr_imm("sms-resend-retry")) == -1) {
00627         sms_resend_retry = -1;
00628         info(0, "SMS resend retry set to unlimited.");
00629     }
00630     else
00631         info(0, "SMS resend retry set to %ld.", sms_resend_retry);
00632 
00633     if (cfg_get_bool(&handle_concatenated_mo, grp, octstr_imm("sms-combine-concatenated-mo")) == -1)
00634         handle_concatenated_mo = 1; /* default is TRUE. */
00635 
00636     if (cfg_get_integer(&concatenated_mo_timeout, grp, octstr_imm("sms-combine-concatenated-mo-timeout")) == -1)
00637         concatenated_mo_timeout = 1800;
00638 
00639     if (handle_concatenated_mo)
00640         init_concat_handler();
00641 
00642     smsc_groups = cfg_get_multi_group(cfg, octstr_imm("smsc"));
00643     gwlist_add_producer(smsc_list);
00644     for (i = 0; i < gwlist_len(smsc_groups) && 
00645         (grp = gwlist_get(smsc_groups, i)) != NULL; i++) {
00646         conn = smscconn_create(grp, 1); 
00647         if (conn == NULL)
00648             panic(0, "Cannot start with SMSC connection failing");
00649         gwlist_append(smsc_list, conn);
00650     }
00651     gwlist_remove_producer(smsc_list);
00652     
00653     if ((router_thread = gwthread_create(sms_router, NULL)) == -1)
00654     panic(0, "Failed to start a new thread for SMS routing");
00655     
00656     gwlist_add_producer(incoming_sms);
00657     smsc_running = 1;
00658     return 0;
00659 }

Here is the call graph for this function:

Octstr* smsc2_status int  status_type  ) 
 

Definition at line 883 of file bb_smscconn.c.

References bb_status_linebreak(), BBSTATUS_HTML, smsc_state::failed, gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), gwlist_len(), info(), octstr_append(), octstr_append_cstr(), octstr_create, octstr_format(), octstr_format_append(), octstr_imm(), smsc_state::online, smsc_state::queued, smsc_state::received, smsc_state::sent, smsc_list, smsc_list_lock, SMSCConn, SMSCCONN_ACTIVE, SMSCCONN_ACTIVE_RECV, SMSCCONN_CONNECTING, SMSCCONN_DEAD, SMSCCONN_DISCONNECTED, smscconn_id(), smscconn_info(), smscconn_name(), SMSCCONN_RECONNECTING, smsc_state::status, and StatusInfo.

Referenced by bb_print_status().

00884 {
00885     Octstr *tmp;
00886     char tmp3[64];
00887     char *lb;
00888     long i;
00889     int para = 0;
00890     SMSCConn *conn;
00891     StatusInfo info;
00892     const Octstr *conn_id = NULL;
00893     const Octstr *conn_name = NULL;
00894 
00895     if ((lb = bb_status_linebreak(status_type)) == NULL)
00896         return octstr_create("Un-supported format");
00897 
00898     if (status_type == BBSTATUS_HTML || status_type == BBSTATUS_WML)
00899         para = 1;
00900 
00901     if (!smsc_running) {
00902         if (status_type == BBSTATUS_XML)
00903             return octstr_create ("<smscs>\n\t<count>0</count>\n</smscs>");
00904         else
00905             return octstr_format("%sNo SMSC connections%s\n\n", para ? "<p>" : "",
00906                                  para ? "</p>" : "");
00907     }
00908 
00909     if (status_type != BBSTATUS_XML)
00910         tmp = octstr_format("%sSMSC connections:%s", para ? "<p>" : "", lb);
00911     else
00912         tmp = octstr_format("<smscs><count>%d</count>\n\t", gwlist_len(smsc_list));
00913 
00914     gw_rwlock_rdlock(&smsc_list_lock);
00915     for (i = 0; i < gwlist_len(smsc_list); i++) {
00916         conn = gwlist_get(smsc_list, i);
00917 
00918         if ((smscconn_info(conn, &info) == -1)) {
00919             /* 
00920              * we do not delete SMSCs from the list 
00921              * this way we can show in the status which links are dead
00922              */
00923             continue;
00924         }
00925 
00926         conn_id = conn ? smscconn_id(conn) : octstr_imm("unknown");
00927         conn_id = conn_id ? conn_id : octstr_imm("unknown");
00928         conn_name = conn ? smscconn_name(conn) : octstr_imm("unknown");
00929 
00930         if (status_type == BBSTATUS_HTML) {
00931             octstr_append_cstr(tmp, "&nbsp;&nbsp;&nbsp;&nbsp;<b>");
00932             octstr_append(tmp, conn_id);
00933             octstr_append_cstr(tmp, "</b>&nbsp;&nbsp;&nbsp;&nbsp;");
00934         } else if (status_type == BBSTATUS_TEXT) {
00935             octstr_append_cstr(tmp, "    ");
00936             octstr_append(tmp, conn_id);
00937             octstr_append_cstr(tmp, "    ");
00938         } 
00939         if (status_type == BBSTATUS_XML) {
00940             octstr_append_cstr(tmp, "<smsc>\n\t\t<name>");
00941             octstr_append(tmp, conn_name);
00942             octstr_append_cstr(tmp, "</name>\n\t\t");
00943             octstr_append_cstr(tmp, "<id>");
00944             octstr_append(tmp, conn_id);
00945             octstr_append_cstr(tmp, "</id>\n\t\t");
00946         } else
00947             octstr_append(tmp, conn_name);
00948 
00949         switch (info.status) {
00950             case SMSCCONN_ACTIVE:
00951             case SMSCCONN_ACTIVE_RECV:
00952                 sprintf(tmp3, "online %lds", info.online);
00953                 break;
00954             case SMSCCONN_DISCONNECTED:
00955                 sprintf(tmp3, "disconnected");
00956                 break;
00957             case SMSCCONN_CONNECTING:
00958                 sprintf(tmp3, "connecting");
00959                 break;
00960             case SMSCCONN_RECONNECTING:
00961                 sprintf(tmp3, "re-connecting");
00962                 break;
00963             case SMSCCONN_DEAD:
00964                 sprintf(tmp3, "dead");
00965                 break;
00966             default:
00967                 sprintf(tmp3, "unknown");
00968         }
00969     
00970         if (status_type == BBSTATUS_XML)
00971             octstr_format_append(tmp, "<status>%s</status>\n\t\t<received>%ld</received>"
00972                 "\n\t\t<sent>%ld</sent>\n\t\t<failed>%ld</failed>\n\t\t"
00973                 "<queued>%ld</queued>\n\t</smsc>\n", tmp3,
00974                 info.received, info.sent, info.failed,
00975                 info.queued);
00976         else
00977             octstr_format_append(tmp, " (%s, rcvd %ld, sent %ld, failed %ld, "
00978                 "queued %ld msgs)%s", tmp3,
00979             info.received, info.sent, info.failed,
00980             info.queued, lb);
00981     }
00982     gw_rwlock_unlock(&smsc_list_lock);
00983 
00984     if (para)
00985         octstr_append_cstr(tmp, "</p>");
00986     if (status_type == BBSTATUS_XML)
00987         octstr_append_cstr(tmp, "</smscs>\n");
00988     else
00989         octstr_append_cstr(tmp, "\n\n");
00990     return tmp;
00991 }

Here is the call graph for this function:

int smsc2_stop_smsc Octstr id  ) 
 

Definition at line 684 of file bb_smscconn.c.

References gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), info(), octstr_get_cstr, smsc2_find(), smsc_list, smsc_list_lock, SMSCConn, smscconn_shutdown(), and smscconn_status().

Referenced by bb_stop_smsc().

00685 {
00686     SMSCConn *conn;
00687     long i = -1;
00688 
00689     if (!smsc_running)
00690         return -1;
00691 
00692     gw_rwlock_rdlock(&smsc_list_lock);
00693     /* find the specific smsc via id */
00694     while((i = smsc2_find(id, ++i)) != -1) {
00695         conn = gwlist_get(smsc_list, i);
00696         if (conn != NULL && smscconn_status(conn) == SMSCCONN_DEAD) {
00697             info(0, "HTTP: Could not shutdown already dead smsc-id `%s'",
00698                 octstr_get_cstr(id));
00699         } else {
00700             info(0,"HTTP: Shutting down smsc-id `%s'", octstr_get_cstr(id));
00701             smscconn_shutdown(conn, 1);   /* shutdown the smsc */
00702         }
00703     }
00704     gw_rwlock_unlock(&smsc_list_lock);
00705     return 0;
00706 }

Here is the call graph for this function:

void smsc2_suspend void   ) 
 

Definition at line 798 of file bb_smscconn.c.

References gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), gwlist_len(), smsc_list, smsc_list_lock, SMSCConn, and smscconn_stop().

Referenced by bb_isolate(), and bb_suspend().

00799 {
00800     SMSCConn *conn;
00801     long i;
00802 
00803     if (!smsc_running)
00804         return;
00805 
00806     gw_rwlock_rdlock(&smsc_list_lock);
00807     for (i = 0; i < gwlist_len(smsc_list); i++) {
00808         conn = gwlist_get(smsc_list, i);
00809         smscconn_stop(conn);
00810     }
00811     gw_rwlock_unlock(&smsc_list_lock);
00812 }

Here is the call graph for this function:


Variable Documentation

volatile sig_atomic_t bb_status
 

Definition at line 120 of file bearerbox.c.

Numhash* black_list [static]
 

Definition at line 120 of file bb_smscconn.c.

Referenced by bb_smscconn_receive(), smsc2_cleanup(), and smsc2_start().

regex_t* black_list_regex [static]
 

Definition at line 124 of file bb_smscconn.c.

Referenced by bb_smscconn_receive(), smsc2_cleanup(), and smsc2_start().

Mutex* concat_lock [static]
 

Definition at line 1210 of file bb_smscconn.c.

Referenced by check_concatenation(), clear_old_concat_parts(), init_concat_handler(), and shutdown_concat_handler().

long concatenated_mo_timeout [static]
 

Definition at line 141 of file bb_smscconn.c.

Referenced by sms_router(), and smsc2_start().

List* flow_threads
 

Definition at line 107 of file bearerbox.c.

int handle_concatenated_mo [static]
 

Definition at line 139 of file bb_smscconn.c.

Referenced by bb_smscconn_receive(), and smsc2_start().

Dict* incoming_concat_msgs [static]
 

Definition at line 1209 of file bb_smscconn.c.

Referenced by check_concatenation(), clear_old_concat_parts(), init_concat_handler(), and shutdown_concat_handler().

List* incoming_sms
 

Definition at line 83 of file bearerbox.c.

Counter* incoming_sms_counter
 

Definition at line 89 of file bearerbox.c.

Referenced by bb_print_status(), bb_smscconn_receive(), empty_msg_lists(), and init_bearerbox().

List* isolated
 

Definition at line 118 of file bearerbox.c.

Referenced by bb_isolate(), bb_resume(), bb_suspend(), main(), set_shutdown_status(), and udp_receiver().

long max_incoming_sms_qlength
 

Definition at line 95 of file bearerbox.c.

long max_outgoing_sms_qlength
 

Definition at line 96 of file bearerbox.c.

Referenced by init_bearerbox(), and smsc2_rout().

List* outgoing_sms
 

Definition at line 84 of file bearerbox.c.

Counter* outgoing_sms_counter
 

Definition at line 90 of file bearerbox.c.

Referenced by bb_print_status(), bb_smscconn_sent(), empty_msg_lists(), and init_bearerbox().

long router_thread = -1 [static]
 

Definition at line 126 of file bb_smscconn.c.

Referenced by bb_smscconn_connected(), smsc2_restart_smsc(), smsc2_resume(), smsc2_shutdown(), and smsc2_start().

long sms_resend_frequency [static]
 

Definition at line 129 of file bb_smscconn.c.

Referenced by sms_router(), and smsc2_start().

long sms_resend_retry [static]
 

Definition at line 130 of file bb_smscconn.c.

Referenced by bb_smscconn_send_failed(), and smsc2_start().

List* smsc_groups [static]
 

Definition at line 117 of file bb_smscconn.c.

Referenced by smsc2_cleanup(), smsc2_restart_smsc(), and smsc2_start().

List* smsc_list [static]
 

Definition at line 115 of file bb_smscconn.c.

Referenced by smsc2_cleanup(), smsc2_find(), smsc2_restart_smsc(), smsc2_resume(), smsc2_rout(), smsc2_shutdown(), smsc2_start(), smsc2_status(), smsc2_stop_smsc(), and smsc2_suspend().

RWLock smsc_list_lock [static]
 

Definition at line 116 of file bb_smscconn.c.

Referenced by smsc2_cleanup(), smsc2_restart_smsc(), smsc2_resume(), smsc2_rout(), smsc2_shutdown(), smsc2_start(), smsc2_status(), smsc2_stop_smsc(), and smsc2_suspend().

volatile sig_atomic_t smsc_running [static]
 

Definition at line 114 of file bb_smscconn.c.

Referenced by smsc2_cleanup(), and smsc2_start().

Counter* split_msg_counter
 

Definition at line 136 of file bb_smscconn.c.

Referenced by smsc2_cleanup(), smsc2_start(), and smscconn_send().

List* suspended
 

Definition at line 113 of file bearerbox.c.

Octstr* unified_prefix [static]
 

Definition at line 118 of file bb_smscconn.c.

Referenced by bb_smscconn_receive(), smsc2_cleanup(), smsc2_rout(), and smsc2_start().

Numhash* white_list [static]
 

Definition at line 121 of file bb_smscconn.c.

Referenced by bb_smscconn_receive(), smsc2_cleanup(), and smsc2_start().

regex_t* white_list_regex [static]
 

Definition at line 123 of file bb_smscconn.c.

Referenced by bb_smscconn_receive(), smsc2_cleanup(), and smsc2_start().

See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.