bb_smscconn.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:19k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * SMSC Connection interface for Bearerbox.
  3.  *
  4.  * Includes callback functions called by SMSCConn implementations
  5.  *
  6.  * Handles all startup/shutdown adminstrative work in bearerbox, plus
  7.  * routing, writing actual access logs, handling failed messages etc.
  8.  *
  9.  * Kalle Marjola 2000 for project Kannel
  10.  */
  11. #include <errno.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <time.h>
  15. #include <string.h>
  16. #include <sys/time.h>
  17. #include <sys/types.h>
  18. #include <unistd.h>
  19. #include <signal.h>
  20. #include <fcntl.h>
  21. #include "gwlib/gwlib.h"
  22. #include "msg.h"
  23. #include "sms.h"
  24. #include "bearerbox.h"
  25. #include "numhash.h"
  26. #include "smscconn.h"
  27. #include "bb_smscconn_cb.h"    /* callback functions for connections */
  28. #include "smscconn_p.h"        /* to access counters */
  29. /* passed from bearerbox core */
  30. extern volatile sig_atomic_t bb_status;
  31. extern List *incoming_wdp;
  32. extern List *incoming_sms;
  33. extern List *outgoing_sms;
  34. extern Counter *incoming_sms_counter;
  35. extern Counter *outgoing_sms_counter;
  36. extern List *flow_threads;
  37. extern List *suspended;
  38. extern List *isolated;
  39. /* our own thingies */
  40. static volatile sig_atomic_t smsc_running;
  41. static List *smsc_list;
  42. static List *smsc_groups;
  43. static Octstr *unified_prefix;
  44. static Numhash *black_list;
  45. static Numhash *white_list;
  46. static long maximum_queue_length;
  47. static long router_thread = -1;
  48. static void log_sms(SMSCConn *conn, Msg *sms, char *message)
  49. {
  50.     Octstr *text, *udh;
  51.     
  52.     text = sms->sms.msgdata ? octstr_duplicate(sms->sms.msgdata) : octstr_create("");
  53.     udh = sms->sms.udhdata ? octstr_duplicate(sms->sms.udhdata) : octstr_create("");
  54.     if ((sms->sms.coding == DC_8BIT || sms->sms.coding == DC_UCS2))
  55. octstr_binary_to_hex(text, 1);
  56.     octstr_binary_to_hex(udh, 1);
  57.     alog("%s [SMSC:%s] [SVC:%s] [ACT:%s] [from:%s] [to:%s] [flags:%d:%d:%d:%d:%d] [msg:%d:%s]"
  58. " [udh:%d:%s]",
  59.  message,
  60.  conn ? (smscconn_id(conn) ? octstr_get_cstr(smscconn_id(conn)) : "")
  61.  : "",
  62.  sms->sms.service ? octstr_get_cstr(sms->sms.service) : "",
  63.  sms->sms.account ? octstr_get_cstr(sms->sms.account) : "",
  64.  sms->sms.sender ? octstr_get_cstr(sms->sms.sender) : "",
  65.  sms->sms.receiver ? octstr_get_cstr(sms->sms.receiver) : "",
  66.  sms->sms.mclass, sms->sms.coding, sms->sms.mwi, sms->sms.compress,
  67.  sms->sms.dlr_mask,
  68.  octstr_len(sms->sms.msgdata), octstr_get_cstr(text),
  69.  octstr_len(sms->sms.udhdata), octstr_get_cstr(udh)
  70.     );
  71.     octstr_destroy(udh);
  72.     octstr_destroy(text);
  73. }
  74. /*---------------------------------------------------------------------------
  75.  * CALLBACK FUNCTIONS
  76.  *
  77.  * called by SMSCConn implementations when appropriate
  78.  */
  79. void bb_smscconn_ready(SMSCConn *conn)
  80. {
  81.     list_add_producer(flow_threads);
  82.     list_add_producer(incoming_sms);
  83. }
  84. void bb_smscconn_connected(SMSCConn *conn)
  85. {
  86.     if (router_thread >= 0)
  87. gwthread_wakeup(router_thread);
  88. }
  89. void bb_smscconn_killed(void)
  90. {
  91.     /* NOTE: after status has been set to SMSCCONN_DEAD, bearerbox
  92.      *   is free to release/delete 'conn'
  93.      */
  94.     list_remove_producer(incoming_sms);
  95.     list_remove_producer(flow_threads);
  96. }
  97. void bb_smscconn_sent(SMSCConn *conn, Msg *sms)
  98. {
  99.     Msg *mack;
  100.     
  101.     counter_increase(outgoing_sms_counter);
  102.     if (conn) counter_increase(conn->sent);
  103.     
  104.     /* write ACK to store file */
  105.     mack = msg_create(ack);
  106.     mack->ack.nack = 0;
  107.     mack->ack.time = sms->sms.time;
  108.     mack->ack.id = sms->sms.id;
  109.     
  110.     (void) store_save(mack);
  111.     msg_destroy(mack);
  112.     
  113.     /* XXX relay confirmancy message should be generated here */
  114.     
  115.     log_sms(conn, sms, "Sent SMS");
  116.     msg_destroy(sms);
  117. }
  118. void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason)
  119. {
  120.     Msg *mnack;
  121.     
  122.     switch (reason) {
  123.     case SMSCCONN_FAILED_SHUTDOWN:
  124.     case SMSCCONN_FAILED_TEMPORARILY:
  125. list_produce(outgoing_sms, sms);
  126. break;
  127.     default:
  128. /* write NACK to store file */
  129. mnack = msg_create(ack);
  130. mnack->ack.nack = 1;
  131. mnack->ack.time = sms->sms.time;
  132. mnack->ack.id = sms->sms.id;
  133. (void) store_save(mnack);
  134. msg_destroy(mnack);
  135.     
  136. if (conn) counter_increase(conn->failed);
  137. if (reason == SMSCCONN_FAILED_DISCARDED)
  138.     log_sms(conn, sms, "DISCARDED SMS");
  139. else
  140.     log_sms(conn, sms, "FAILED Send SMS");
  141. msg_destroy(sms);
  142.     } 
  143. }    
  144. int bb_smscconn_receive(SMSCConn *conn, Msg *sms)
  145. {
  146.     char *uf;
  147.     /* do some queue control */
  148.     if (maximum_queue_length != -1 && bb_status == BB_FULL && 
  149.             list_len(incoming_sms) <= maximum_queue_length) {
  150.         bb_status = BB_RUNNING;
  151.         warning(0, "started to accept messages again");
  152.     }
  153.     
  154.     if (maximum_queue_length != -1 && 
  155.             list_len(incoming_sms) > maximum_queue_length) {
  156.         if (bb_status != BB_FULL)
  157.             bb_status = BB_FULL;
  158.         warning(0, "incoming messages queue too long, dropping a message");
  159.         log_sms(conn, sms, "DROPPED Received SMS");
  160.         gwthread_sleep(0.1); /* letting the queue go down */
  161.       return -1;
  162.     }
  163.     /* else if (list_len(incoming_sms) > 100)
  164.      * gwthread_sleep(0.5);
  165.      */
  166.     
  167.     if (unified_prefix == NULL)
  168.      uf = NULL;
  169.     else
  170.      uf = octstr_get_cstr(unified_prefix);
  171.     normalize_number(uf, &(sms->sms.sender));
  172.     if (white_list &&
  173. numhash_find_number(white_list, sms->sms.sender) < 1) {
  174. info(0, "Number <%s> is not in white-list, message discarded",
  175.      octstr_get_cstr(sms->sms.sender));
  176. log_sms(conn, sms, "REJECTED - not white-listed SMS");
  177. msg_destroy(sms);
  178.         return -1;
  179.     }
  180.     if (black_list &&
  181. numhash_find_number(black_list, sms->sms.sender) == 1) {
  182. info(0, "Number <%s> is in black-list, message discarded",
  183.      octstr_get_cstr(sms->sms.sender));
  184. log_sms(conn, sms, "REJECTED - black-listed SMS");
  185. msg_destroy(sms);
  186. return -1;
  187.     }
  188.     if (sms->sms.sms_type != report)
  189. sms->sms.sms_type = mo;
  190.     
  191.     /* write to store (if enabled) */
  192.     if (store_save(sms) == -1)
  193. return -1;
  194.     
  195.     if (sms->sms.sms_type != report)
  196. log_sms(conn, sms, "Receive SMS");
  197.     else
  198. log_sms(conn, sms, "DLR SMS");
  199.     list_produce(incoming_sms, sms);
  200.     counter_increase(incoming_sms_counter);
  201.     counter_increase(conn->received);
  202.     return 0;
  203. }
  204. /*---------------------------------------------------------------------
  205.  * Other functions
  206.  */
  207.     
  208. /* function to route outgoing SMS'es from delay-list
  209.  * use some nice magics to route them to proper SMSC
  210.  */
  211. static void sms_router(void *arg)
  212. {
  213.     Msg *msg, *newmsg, *startmsg;
  214.     int ret;
  215.     
  216.     list_add_producer(flow_threads);
  217.     gwthread_wakeup(MAIN_THREAD_ID);
  218.     newmsg = startmsg = NULL;
  219.     ret = 0;
  220.     
  221.     while(bb_status != BB_DEAD) {
  222. if (newmsg == startmsg) {
  223.     if (ret != 1) {
  224. debug("bb.sms", 0, "sms_router: time to sleep"); 
  225. gwthread_sleep(600.0); /* hopefully someone wakes us up */
  226. debug("bb.sms", 0, "sms_router: list_len = %ld",
  227.       list_len(outgoing_sms));
  228.     }
  229.     startmsg = list_consume(outgoing_sms);
  230.     newmsg = NULL;
  231.     msg = startmsg;
  232. } else {
  233.     newmsg = list_consume(outgoing_sms);
  234.     msg = newmsg;
  235. }
  236. /* debug("bb.sms", 0, "sms_router: handling message (%p vs %p)",
  237.  *         newmsg, startmsg); */
  238. if (msg == NULL)
  239.             break;
  240. ret = smsc2_rout(msg);
  241. if (ret == -1) {
  242.             warning(0, "No SMSCes to receive message, discarding it!");
  243.     bb_smscconn_send_failed(NULL, msg, SMSCCONN_FAILED_DISCARDED);
  244.         } else if (ret == 1) {
  245.     newmsg = startmsg = NULL;
  246. }
  247.     
  248.     
  249.     }
  250.     /* router has died, make sure that rest die, too */
  251.     
  252.     smsc_running = 0;
  253.     list_remove_producer(flow_threads);
  254. }
  255. /*-------------------------------------------------------------
  256.  * public functions
  257.  *
  258.  */
  259. int smsc2_start(Cfg *cfg)
  260. {
  261.     CfgGroup *grp;
  262.     SMSCConn *conn;
  263.     Octstr *os;
  264.     int i;
  265.     if (smsc_running) return -1;
  266.     smsc_list = list_create();
  267.     smsc_groups = list_create();
  268.     grp = cfg_get_single_group(cfg, octstr_imm("core"));
  269.     unified_prefix = cfg_get(grp, octstr_imm("unified-prefix"));
  270.     if (cfg_get_integer(&maximum_queue_length, grp, 
  271.                            octstr_imm("maximum-queue-length")) == -1)
  272.         maximum_queue_length = -1;
  273.     white_list = black_list = NULL;
  274.     os = cfg_get(grp, octstr_imm("white-list"));
  275.     if (os != NULL) {
  276.         white_list = numhash_create(octstr_get_cstr(os));
  277. octstr_destroy(os);
  278.     }
  279.     os = cfg_get(grp, octstr_imm("black-list"));
  280.     if (os != NULL) {
  281.         black_list = numhash_create(octstr_get_cstr(os));
  282. octstr_destroy(os);
  283.     }
  284.     smsc_groups = cfg_get_multi_group(cfg, octstr_imm("smsc"));
  285.     /*
  286.     while(groups && (grp = list_extract_first(groups)) != NULL) {
  287.         conn = smscconn_create(grp, 1); 
  288.         if (conn == NULL)
  289.             panic(0, "Cannot start with SMSC connection failing");
  290.         
  291.         list_append(smsc_list, conn);
  292.     }
  293.     */
  294.     list_add_producer(smsc_list);
  295.     for (i = 0; i < list_len(smsc_groups) && 
  296.         (grp = list_get(smsc_groups, i)) != NULL; i++) {
  297.         conn = smscconn_create(grp, 1); 
  298.         if (conn == NULL)
  299.             panic(0, "Cannot start with SMSC connection failing");
  300.         list_append(smsc_list, conn);
  301.     }
  302.     list_remove_producer(smsc_list);
  303.     
  304.     if ((router_thread = gwthread_create(sms_router, NULL)) == -1)
  305. panic(0, "Failed to start a new thread for SMS routing");
  306.     
  307.     list_add_producer(incoming_sms);
  308.     list_add_producer(incoming_wdp);
  309.     smsc_running = 1;
  310.     return 0;
  311. }
  312. static int smsc2_find(Octstr *id)
  313. {
  314.     SMSCConn *conn = NULL;
  315.     int i;
  316.     list_lock(smsc_list);
  317.     for (i = 0; i < list_len(smsc_list); i++) {
  318.         conn = list_get(smsc_list, i);
  319.         if (conn != NULL && octstr_compare(conn->id, id) == 0) {
  320.             break;
  321.         }
  322.     }
  323.     list_unlock(smsc_list);
  324.     if (i >= list_len(smsc_list))
  325.         i = -1;
  326.     return i;
  327. }
  328. int smsc2_stop_smsc(Octstr *id)
  329. {
  330.     SMSCConn *conn;
  331.     int i;
  332.     /* find the specific smsc via id */
  333.     if ((i = smsc2_find(id)) == -1) {
  334.         error(0, "HTTP: Could not shutdown smsc-id `%s'", octstr_get_cstr(id));
  335.         return -1;
  336.     }
  337.     conn = list_get(smsc_list, i);
  338.     if (conn != NULL && conn->status == SMSCCONN_DEAD) {
  339.         error(0, "HTTP: Could not shutdown already deaed smsc-id `%s'", 
  340.               octstr_get_cstr(id));
  341.         return -1;
  342.     }
  343.     info(0,"HTTP: Shutting down smsc-id `%s'", octstr_get_cstr(id));
  344.     smscconn_shutdown(conn, 1);   /* shutdown the smsc */
  345.     return 0;
  346. }
  347. int smsc2_restart_smsc(Octstr *id)
  348. {
  349.     CfgGroup *grp;
  350.     SMSCConn *conn;
  351.     Octstr *smscid;
  352.     int i;
  353.     /* find the specific smsc via id */
  354.     if ((i = smsc2_find(id)) == -1) {
  355.         error(0, "HTTP: Could not re-start non defined smsc-id `%s'", 
  356.               octstr_get_cstr(id));
  357.         return -1;
  358.     }
  359.     /* check if smsc is online status already */
  360.     conn = list_get(smsc_list, i);
  361.     if (conn != NULL && conn->status != SMSCCONN_DEAD) {
  362.         error(0, "HTTP: Could not re-start already running smsc-id `%s'", 
  363.               octstr_get_cstr(id));
  364.         return -1;
  365.     }
  366.   
  367.     list_delete(smsc_list, i, 1); /* drop it from the active smsc list */
  368. smscconn_destroy(conn);       /* destroy the connection */
  369.     /* find the group with smsc id */
  370.     grp = NULL;
  371.     list_lock(smsc_groups);
  372.     for (i = 0; i < list_len(smsc_groups) && 
  373.         (grp = list_get(smsc_groups, i)) != NULL; i++) {
  374.         smscid = cfg_get(grp, octstr_imm("smsc-id"));
  375.         if (smscid != NULL && octstr_compare(smscid, id) == 0) {
  376.             break;
  377.         }
  378.     }
  379.     list_unlock(smsc_groups);
  380.     if (i > list_len(smsc_groups))
  381.         return -1;
  382.     
  383.     info(0,"HTTP: Re-starting smsc-id `%s'", octstr_get_cstr(id));
  384.     conn = smscconn_create(grp, 1); 
  385.     if (conn == NULL)
  386.         error(0, "Cannot start with SMSC connection failing");
  387.     list_append(smsc_list, conn);
  388.     smscconn_start(conn);
  389.     if (router_thread >= 0)
  390.         gwthread_wakeup(router_thread);
  391.     return 0;
  392. }
  393. void smsc2_resume(void)
  394. {
  395.     SMSCConn *conn;
  396.     int i;
  397.     
  398.     for (i = 0; i < list_len(smsc_list); i++) {
  399.         conn = list_get(smsc_list, i);
  400.         smscconn_start(conn);
  401.     }
  402.     if (router_thread >= 0)
  403. gwthread_wakeup(router_thread);
  404. }
  405. void smsc2_suspend(void)
  406. {
  407.     SMSCConn *conn;
  408.     int i;
  409.     
  410.     list_lock(smsc_list);
  411.     for (i = 0; i < list_len(smsc_list); i++) {
  412.         conn = list_get(smsc_list, i);
  413.         smscconn_stop(conn);
  414.     }
  415.     list_unlock(smsc_list);
  416. }
  417. int smsc2_shutdown(void)
  418. {
  419.     SMSCConn *conn;
  420.     int i;
  421.     if (!smsc_running) return -1;
  422.     /* Call shutdown for all SMSC Connections; they should
  423.      * handle that they quit, by emptying queues and then dying off
  424.      */
  425.     list_lock(smsc_list);
  426.     for(i=0; i < list_len(smsc_list); i++) {
  427.         conn = list_get(smsc_list, i);
  428. smscconn_shutdown(conn, 1);
  429.     }
  430.     list_unlock(smsc_list);
  431.     if (router_thread >= 0)
  432. gwthread_wakeup(router_thread);
  433.     /* start avalanche by calling shutdown */
  434.     /* XXX shouldn'w we be sure that all smsces have closed their
  435.      * receive thingies? Is this guaranteed by setting bb_status
  436.      * to shutdown before calling these?
  437.      */
  438.     list_remove_producer(incoming_sms);
  439.     list_remove_producer(incoming_wdp);
  440.     return 0;
  441. }
  442. void smsc2_cleanup(void)
  443. {
  444.     SMSCConn *conn;
  445.     int i;
  446.     debug("smscconn", 0, "final clean-up for SMSCConn");
  447.     
  448.     list_lock(smsc_list);
  449.     for (i = 0; i < list_len(smsc_list); i++) {
  450.         conn = list_get(smsc_list, i);
  451.         smscconn_destroy(conn);
  452.     }
  453.     list_unlock(smsc_list);
  454.     list_destroy(smsc_list, NULL);
  455.     list_destroy(smsc_groups, NULL);
  456.     octstr_destroy(unified_prefix);    
  457.     numhash_destroy(white_list);
  458.     numhash_destroy(black_list);
  459. }
  460. Octstr *smsc2_status(int status_type)
  461. {
  462.     Octstr *tmp;
  463.     char tmp3[64];
  464.     char *lb;
  465.     int i, para = 0;
  466.     SMSCConn *conn;
  467.     StatusInfo info;
  468.     Octstr *conn_id = NULL;
  469.     Octstr *conn_name = NULL;
  470.     if ((lb = bb_status_linebreak(status_type)) == NULL)
  471.         return octstr_create("Un-supported format");
  472.     if (status_type == BBSTATUS_HTML || status_type == BBSTATUS_WML)
  473.         para = 1;
  474.     if (!smsc_running) {
  475.         if (status_type == BBSTATUS_XML)
  476.             return octstr_create ("<smscs>nt<count>0</count>n</smscs>");
  477.         else
  478.             return octstr_format("%sNo SMSC connections%snn", para ? "<p>" : "",
  479.                                  para ? "</p>" : "");
  480.     }
  481.     if (status_type != BBSTATUS_XML)
  482.         tmp = octstr_format("%sSMSC connections:%s", para ? "<p>" : "", lb);
  483.     else
  484.         tmp = octstr_format("<smscs><count>%d</count>nt", list_len(smsc_list));
  485.     
  486.     list_lock(smsc_list);
  487.     for (i = 0; i < list_len(smsc_list); i++) {
  488.         conn = list_get(smsc_list, i);
  489.         if ((smscconn_info(conn, &info) == -1)) {
  490.             /* 
  491.              * we do not delete SMSCs from the list 
  492.              * this way we can show in the status which links are dead
  493.              */
  494.             continue;
  495.         }
  496.         conn_id = conn ? smscconn_id(conn) : octstr_imm("unknown");
  497.         conn_id = conn_id ? conn_id : octstr_imm("unknown");
  498.         conn_name = conn ? smscconn_name(conn) : octstr_imm("unknown");
  499.         if (status_type == BBSTATUS_HTML) {
  500.             octstr_append_cstr(tmp, "&nbsp;&nbsp;&nbsp;&nbsp;<b>");
  501.             octstr_append(tmp, conn_id);
  502.             octstr_append_cstr(tmp, "</b>&nbsp;&nbsp;&nbsp;&nbsp;");
  503.         } else if (status_type == BBSTATUS_TEXT) {
  504.             octstr_append_cstr(tmp, "    ");
  505.             octstr_append(tmp, conn_id);
  506.             octstr_append_cstr(tmp, "    ");
  507.         } 
  508.         if (status_type == BBSTATUS_XML) {
  509.             octstr_append_cstr(tmp, "<smsc>ntt<name>");
  510.             octstr_append(tmp, conn_name);
  511.             octstr_append_cstr(tmp, "</name>ntt");
  512.             octstr_append_cstr(tmp, "<id>");
  513.             octstr_append(tmp, conn_id);
  514.             octstr_append_cstr(tmp, "</id>ntt");
  515.         } else
  516.             octstr_append(tmp, conn_name);
  517.         switch (info.status) {
  518.             case SMSCCONN_ACTIVE:
  519.             case SMSCCONN_ACTIVE_RECV:
  520.                 sprintf(tmp3, "online %lds", info.online);
  521.                 break;
  522.             case SMSCCONN_DISCONNECTED:
  523.                 sprintf(tmp3, "disconnected");
  524.                 break;
  525.             case SMSCCONN_CONNECTING:
  526.                 sprintf(tmp3, "connecting");
  527.                 break;
  528.             case SMSCCONN_RECONNECTING:
  529.                 sprintf(tmp3, "re-connecting");
  530.                 break;
  531.             case SMSCCONN_DEAD:
  532.                 sprintf(tmp3, "dead");
  533.                 break;
  534.             default:
  535.                 sprintf(tmp3, "unknown");
  536.         }
  537.         if (status_type == BBSTATUS_XML)
  538.             octstr_format_append(tmp, "<status>%s</status>ntt<received>%ld</received>"
  539.                 "ntt<sent>%ld</sent>ntt<failed>%ld</failed>ntt"
  540.                 "<queued>%ld</queued>nt</smsc>n", tmp3,
  541.                 info.received, info.sent, info.failed,
  542.                 info.queued);
  543.         else
  544.             octstr_format_append(tmp, " (%s, rcvd %ld, sent %ld, failed %ld, "
  545.                 "queued %ld msgs)%s", tmp3,
  546.             info.received, info.sent, info.failed,
  547.             info.queued, lb);
  548.     }
  549.     list_unlock(smsc_list);
  550.     if (para)
  551.         octstr_append_cstr(tmp, "</p>");
  552.     if (status_type == BBSTATUS_XML)
  553.         octstr_append_cstr(tmp, "</smscs>n");
  554.     else
  555.         octstr_append_cstr(tmp, "nn");
  556.     return tmp;
  557. }
  558. /* function to route outgoing SMS'es
  559.  *
  560.  * If finds a good one, puts into it and returns 1
  561.  * If finds only bad ones, but acceptable, queues and
  562.  *  returns 0  (like all acceptable currently disconnected)
  563.  * If cannot find nothing at all, returns -1 and
  564.  * message is NOT destroyed (otherwise it is)
  565.  */
  566. int smsc2_rout(Msg *msg)
  567. {
  568.     StatusInfo info;
  569.     SMSCConn *conn, *best_preferred, *best_ok;
  570.     long bp_load, bo_load;
  571.     int i, s, ret, bad_found;
  572.     char *uf;
  573.     bp_load = bo_load = 0;
  574.     /* XXX handle ack here? */
  575.     if (msg_type(msg) != sms)
  576. return -1;
  577.     
  578.     if (list_len(smsc_list) == 0) {
  579. warning(0, "No SMSCes to receive message");
  580. return -1;
  581.     }
  582.     /* unify prefix of receiver, in case of it has not been
  583.      * already done */
  584.     uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
  585.     normalize_number(uf, &(msg->sms.receiver));
  586.             
  587.     /* select in which list to add this
  588.      * start - from random SMSCConn, as they are all 'equal'
  589.      */
  590.     list_lock(smsc_list);
  591.     s = gw_rand() % list_len(smsc_list);
  592.     best_preferred = best_ok = NULL;
  593.     bad_found = 0;
  594.     
  595.     conn = NULL;
  596.     for (i=0; i < list_len(smsc_list); i++) {
  597. conn = list_get(smsc_list,  (i+s) % list_len(smsc_list));
  598. ret = smscconn_usable(conn,msg);
  599. if (ret == -1)
  600.     continue;
  601. /* if we already have a preferred one, skip non-preferred */
  602. if (ret != 1 && best_preferred)
  603.     continue;
  604. smscconn_info(conn, &info);
  605. /* If connection is not currently answering... */
  606. if (info.status != SMSCCONN_ACTIVE) {
  607.     bad_found = 1;
  608.     continue;
  609. }
  610. if (ret == 1) {          /* preferred */
  611.     if (best_preferred == NULL || info.load < bp_load) {
  612. best_preferred = conn;
  613. bp_load = info.load;
  614. continue;
  615.     }
  616. }
  617. if (best_ok == NULL || info.load < bo_load) {
  618.     best_ok = conn;
  619.     bo_load = info.load;
  620. }
  621.     }
  622.     list_unlock(smsc_list);
  623.     if (best_preferred)
  624. ret = smscconn_send(best_preferred, msg);
  625.     else if (best_ok)
  626. ret = smscconn_send(best_ok, msg);
  627.     else if (bad_found) {
  628. if (bb_status != BB_SHUTDOWN)
  629.     list_produce(outgoing_sms, msg);
  630. return 0;
  631.     }
  632.     else {
  633. if (bb_status == BB_SHUTDOWN)
  634.     return 0;
  635. warning(0, "Cannot find SMSCConn for message to <%s>, rejected.",
  636. octstr_get_cstr(msg->sms.receiver));
  637. return -1;
  638.     }
  639.     /* check the status of sending operation */
  640.     if (ret == -1)
  641. return (smsc2_rout(msg)); /* re-try */
  642.     msg_destroy(msg);
  643.     return 1;
  644. }