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

bearerbox.h File Reference

#include "gwlib/gwlib.h"
#include "msg.h"
#include "smscconn.h"
#include "bb_store.h"

Include dependency graph for bearerbox.h:

Include dependency graph

This graph shows which files directly or indirectly include this file:

Included by dependency graph

Go to the source code of this file.

Enumerations

enum  {
  BB_RUNNING = 0, BB_ISOLATED = 1, BB_SUSPENDED = 2, BB_SHUTDOWN = 3,
  BB_DEAD = 4, BB_FULL = 5
}
enum  { BBSTATUS_HTML = 0, BBSTATUS_TEXT = 1, BBSTATUS_WML = 2, BBSTATUS_XML = 3 }

Functions

int smsbox_start (Cfg *config)
int smsbox_restart (Cfg *config)
int wapbox_start (Cfg *config)
Octstrboxc_status (int status_type)
int boxc_incoming_wdp_queue (void)
void boxc_cleanup (void)
int route_incoming_to_boxc (Msg *msg)
int udp_start (Cfg *config)
int udp_shutdown (void)
int udp_die (void)
int udp_addwdp (Msg *msg)
int udp_outgoing_queue (void)
int smsc2_start (Cfg *config)
int smsc2_restart (Cfg *config)
void smsc2_suspend (void)
void smsc2_resume (void)
int smsc2_shutdown (void)
void smsc2_cleanup (void)
Octstrsmsc2_status (int status_type)
long smsc2_rout (Msg *msg, int resend)
int smsc2_stop_smsc (Octstr *id)
int smsc2_restart_smsc (Octstr *id)
int httpadmin_start (Cfg *config)
void httpadmin_stop (void)
void bb_alog_init (const Octstr *format)
void bb_alog_shutdown (void)
void bb_alog_sms (SMSCConn *conn, Msg *sms, const char *message)
int bb_shutdown (void)
int bb_isolate (void)
int bb_suspend (void)
int bb_resume (void)
int bb_restart (void)
int bb_flush_dlr (void)
int bb_stop_smsc (Octstr *id)
int bb_restart_smsc (Octstr *id)
Octstrbb_print_status (int status_type)
char * bb_status_linebreak (int status_type)


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
BB_RUNNING 
BB_ISOLATED 
BB_SUSPENDED 
BB_SHUTDOWN 
BB_DEAD 
BB_FULL 

Definition at line 71 of file bearerbox.h.

00071      {
00072     BB_RUNNING = 0,
00073     BB_ISOLATED = 1,    /* do not receive new messgaes from UDP/SMSC */
00074     BB_SUSPENDED = 2,   /* do not transfer any messages */
00075     BB_SHUTDOWN = 3,
00076     BB_DEAD = 4,
00077     BB_FULL = 5         /* message queue too long, do not accept new messages */
00078 };

anonymous enum
 

Enumeration values:
BBSTATUS_HTML 
BBSTATUS_TEXT 
BBSTATUS_WML 
BBSTATUS_XML 

Definition at line 82 of file bearerbox.h.

00082      {
00083     BBSTATUS_HTML = 0,
00084     BBSTATUS_TEXT = 1,
00085     BBSTATUS_WML = 2,
00086     BBSTATUS_XML = 3
00087 };


Function Documentation

void bb_alog_init const Octstr format  ) 
 

Definition at line 327 of file bb_alog.c.

References custom_log_format, gw_assert, and octstr_duplicate.

Referenced by init_bearerbox().

00328 {
00329     gw_assert(format != NULL);
00330 
00331     custom_log_format = octstr_duplicate(format);
00332 }

void bb_alog_shutdown void   ) 
 

Definition at line 335 of file bb_alog.c.

References custom_log_format, and octstr_destroy().

Referenced by main().

00336 {
00337     octstr_destroy(custom_log_format);
00338     custom_log_format = NULL;
00339 }

Here is the call graph for this function:

void bb_alog_sms SMSCConn conn,
Msg sms,
const char *  message
 

Definition at line 342 of file bb_alog.c.

References alog(), custom_log_format, DC_8BIT, get_pattern(), gw_assert, message, msg_type, octstr_binary_to_hex(), octstr_convert_printable(), octstr_create, octstr_destroy(), octstr_duplicate, octstr_get_cstr, octstr_imm(), octstr_len(), sms, SMSCConn, smscconn_id(), smscconn_name(), and text.

Referenced by bb_smscconn_receive(), bb_smscconn_send_failed(), bb_smscconn_sent(), and handle_pdu().

00343 {
00344     Octstr *text = NULL;
00345     
00346     gw_assert(msg_type(msg) == sms);
00347 
00348     /* if we don't have any custom log, then use our "default" one */
00349     
00350     if (custom_log_format == NULL) {
00351         Octstr *udh;
00352         const Octstr *cid;
00353 
00354         text = msg->sms.msgdata ? octstr_duplicate(msg->sms.msgdata) : octstr_create("");
00355         udh = msg->sms.udhdata ? octstr_duplicate(msg->sms.udhdata) : octstr_create("");
00356 
00357         if (conn && smscconn_id(conn))
00358             cid = smscconn_id(conn);
00359         else if (conn && smscconn_name(conn))
00360             cid = smscconn_name(conn);
00361         else if (msg->sms.smsc_id)
00362             cid = msg->sms.smsc_id;
00363         else
00364             cid = octstr_imm("");
00365 
00366         if ((msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2))
00367             octstr_binary_to_hex(text, 1);
00368         else
00369             octstr_convert_printable(text);
00370         octstr_binary_to_hex(udh, 1);
00371 
00372         alog("%s [SMSC:%s] [SVC:%s] [ACT:%s] [BINF:%s] [from:%s] [to:%s] [flags:%ld:%ld:%ld:%ld:%ld] "
00373              "[msg:%ld:%s] [udh:%ld:%s]",
00374              message,
00375              octstr_get_cstr(cid),
00376              msg->sms.service ? octstr_get_cstr(msg->sms.service) : "",
00377              msg->sms.account ? octstr_get_cstr(msg->sms.account) : "",
00378              msg->sms.binfo ? octstr_get_cstr(msg->sms.binfo) : "",
00379              msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : "",
00380              msg->sms.receiver ? octstr_get_cstr(msg->sms.receiver) : "",
00381              msg->sms.mclass, msg->sms.coding, msg->sms.mwi, msg->sms.compress,
00382              msg->sms.dlr_mask, 
00383              octstr_len(msg->sms.msgdata), octstr_get_cstr(text),
00384              octstr_len(msg->sms.udhdata), octstr_get_cstr(udh)
00385         );
00386 
00387         octstr_destroy(udh);
00388     } else {
00389         text = get_pattern(conn, msg, message);
00390         alog("%s", octstr_get_cstr(text));
00391     }
00392 
00393     octstr_destroy(text);
00394 }

Here is the call graph for this function:

int bb_flush_dlr void   ) 
 

Definition at line 783 of file bearerbox.c.

References bb_status, and dlr_flush().

Referenced by httpd_flush_dlr().

00784 {
00785     /* beware that mutex locking is done in dlr_foobar() routines */
00786     if (bb_status != BB_SUSPENDED) {
00787         return -1;
00788     }
00789     dlr_flush();
00790     return 0;
00791 }

Here is the call graph for this function:

int bb_isolate void   ) 
 

Definition at line 728 of file bearerbox.c.

References BB_RUNNING, bb_status, gwlist_add_producer(), gwlist_remove_producer(), isolated, mutex_lock, mutex_unlock, smsc2_suspend(), status_mutex, and suspended.

Referenced by httpd_isolate().

00729 {
00730     mutex_lock(status_mutex);
00731     if (bb_status != BB_RUNNING && bb_status != BB_SUSPENDED) {
00732         mutex_unlock(status_mutex);
00733         return -1;
00734     }
00735     if (bb_status == BB_RUNNING) {
00736         smsc2_suspend();
00737         gwlist_add_producer(isolated);
00738     } else
00739     gwlist_remove_producer(suspended);
00740 
00741     bb_status = BB_ISOLATED;
00742     mutex_unlock(status_mutex);
00743     return 0;
00744 }

Here is the call graph for this function:

Octstr* bb_print_status int  status_type  ) 
 

Definition at line 815 of file bearerbox.c.

References append_status, bb_status, bb_status_linebreak(), boxc_incoming_wdp_queue(), boxc_status(), counter_value(), dlr_messages(), dlr_type(), gwlist_len(), incoming_sms, incoming_sms_counter, incoming_wdp, incoming_wdp_counter, octstr_append_cstr(), octstr_create, octstr_destroy(), octstr_get_cstr, outgoing_sms, outgoing_sms_counter, outgoing_wdp, outgoing_wdp_counter, smsc2_status(), store_messages, udp_outgoing_queue(), and version_report_string().

Referenced by httpd_status().

00816 {
00817     char *s, *lb;
00818     char *frmt, *footer;
00819     char buf[1024];
00820     Octstr *ret, *str, *version;
00821     time_t t;
00822 
00823     if ((lb = bb_status_linebreak(status_type)) == NULL)
00824         return octstr_create("Un-supported format");
00825 
00826     t = time(NULL) - start_time;
00827     
00828     if (bb_status == BB_RUNNING)
00829         s = "running";
00830     else if (bb_status == BB_ISOLATED)
00831         s = "isolated";
00832     else if (bb_status == BB_SUSPENDED)
00833         s = "suspended";
00834     else if (bb_status == BB_FULL)
00835         s = "filled";
00836     else
00837         s = "going down";
00838 
00839     version = version_report_string("bearerbox");
00840 
00841     if (status_type == BBSTATUS_HTML) {
00842         frmt = "%s</p>\n\n"
00843                " <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
00844                " <p>WDP: received %ld (%ld queued), sent %ld "
00845                "(%ld queued)</p>\n\n"
00846                " <p>SMS: received %ld (%ld queued), sent %ld "
00847                "(%ld queued), store size %ld</p>\n"
00848                " <p>SMS: inbound %.2f msg/sec, outbound %.2f msg/sec</p>\n\n"
00849                " <p>DLR: %ld queued, using %s storage</p>\n\n";
00850         footer = "<p>";
00851     } else if (status_type == BBSTATUS_WML) {
00852         frmt = "%s</p>\n\n"
00853                "   <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>\n\n"
00854                "   <p>WDP: received %ld (%ld queued)<br/>\n"
00855                "      WDP: sent %ld (%ld queued)</p>\n\n"
00856                "   <p>SMS: received %ld (%ld queued)<br/>\n"
00857                "      SMS: sent %ld (%ld queued)<br/>\n"
00858                "      SMS: store size %ld<br/>\n"
00859                "      SMS: inbound %.2f msg/sec<br/>\n"
00860                "      SMS: outbound %.2f msg/sec</p>\n\n"
00861                "   <p>DLR: %ld queued<br/>\n"
00862                "      DLR: using %s storage</p>\n\n";
00863         footer = "<p>";
00864     } else if (status_type == BBSTATUS_XML) {
00865         frmt = "<version>%s</version>\n"
00866                "<status>%s, uptime %ldd %ldh %ldm %lds</status>\n"
00867                "\t<wdp>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
00868                "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
00869                "</sent>\n\t</wdp>\n"
00870                "\t<sms>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
00871                "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
00872                "</sent>\n\t\t<storesize>%ld</storesize>\n\t\t"
00873                "<inbound>%.2f</inbound>\n\t\t<outbound>%.2f</outbound>\n\t</sms>\n"
00874                "\t<dlr>\n\t\t<queued>%ld</queued>\n\t\t<storage>%s</storage>\n\t</dlr>\n";
00875         footer = "";
00876     } else {
00877         frmt = "%s\n\nStatus: %s, uptime %ldd %ldh %ldm %lds\n\n"
00878                "WDP: received %ld (%ld queued), sent %ld (%ld queued)\n\n"
00879                "SMS: received %ld (%ld queued), sent %ld (%ld queued), store size %ld\n"
00880                "SMS: inbound %.2f msg/sec, outbound %.2f msg/sec\n\n"
00881                "DLR: %ld queued, using %s storage\n\n";
00882         footer = "";
00883     }
00884     
00885     sprintf(buf, frmt,
00886         octstr_get_cstr(version),
00887         s, t/3600/24, t/3600%24, t/60%60, t%60,
00888         counter_value(incoming_wdp_counter),
00889         gwlist_len(incoming_wdp) + boxc_incoming_wdp_queue(),
00890         counter_value(outgoing_wdp_counter), gwlist_len(outgoing_wdp) + udp_outgoing_queue(),
00891         counter_value(incoming_sms_counter), gwlist_len(incoming_sms),
00892         counter_value(outgoing_sms_counter), gwlist_len(outgoing_sms),
00893         store_messages(),
00894         (float) counter_value(incoming_sms_counter)/t,
00895         (float) counter_value(outgoing_sms_counter)/t,
00896         dlr_messages(), dlr_type());
00897 
00898     octstr_destroy(version);
00899     ret = octstr_create(buf);
00900     
00901     append_status(ret, str, boxc_status, status_type);
00902     append_status(ret, str, smsc2_status, status_type);
00903     octstr_append_cstr(ret, footer);
00904     
00905     return ret;
00906 }

Here is the call graph for this function:

int bb_restart void   ) 
 

Definition at line 805 of file bearerbox.c.

References bb_shutdown(), and restart.

Referenced by httpd_restart().

00806 {
00807     restart = 1;
00808     return bb_shutdown();
00809 }

Here is the call graph for this function:

int bb_restart_smsc Octstr id  ) 
 

Definition at line 800 of file bearerbox.c.

References smsc2_restart_smsc().

Referenced by httpd_restart_smsc().

00801 {
00802     return smsc2_restart_smsc(id);
00803 }

Here is the call graph for this function:

int bb_resume void   ) 
 

Definition at line 765 of file bearerbox.c.

References bb_status, BB_SUSPENDED, gwlist_remove_producer(), isolated, mutex_lock, mutex_unlock, smsc2_resume(), status_mutex, and suspended.

Referenced by httpd_resume().

00766 {
00767     mutex_lock(status_mutex);
00768     if (bb_status != BB_SUSPENDED && bb_status != BB_ISOLATED) {
00769         mutex_unlock(status_mutex);
00770         return -1;
00771     }
00772     if (bb_status == BB_SUSPENDED)
00773         gwlist_remove_producer(suspended);
00774 
00775     smsc2_resume();
00776     bb_status = BB_RUNNING;
00777     gwlist_remove_producer(isolated);
00778     mutex_unlock(status_mutex);
00779     return 0;
00780 }

Here is the call graph for this function:

int bb_shutdown void   ) 
 

Definition at line 699 of file bearerbox.c.

References debug(), GW_NAME, mutex_lock, mutex_unlock, set_shutdown_status(), smsc2_shutdown(), status_mutex, and udp_shutdown().

Referenced by bb_restart(), httpadmin_run(), httpd_shutdown(), and main().

00700 {
00701     static int called = 0;
00702     
00703     mutex_lock(status_mutex);
00704     
00705     if (called) {
00706         mutex_unlock(status_mutex);
00707         return -1;
00708     }
00709     debug("bb", 0, "Shutting down " GW_NAME "...");
00710 
00711     called = 1;
00712     set_shutdown_status();
00713     mutex_unlock(status_mutex);
00714 
00715 #ifndef NO_SMS
00716     debug("bb", 0, "shutting down smsc");
00717     smsc2_shutdown();
00718 #endif
00719 #ifndef NO_WAP
00720     debug("bb", 0, "shutting down udp");
00721     udp_shutdown();
00722 #endif
00723     
00724     return 0;
00725 }

Here is the call graph for this function:

char* bb_status_linebreak int  status_type  ) 
 

Definition at line 909 of file bearerbox.c.

References BBSTATUS_HTML, BBSTATUS_TEXT, BBSTATUS_WML, and BBSTATUS_XML.

Referenced by bb_print_status(), boxc_status(), httpd_serve(), and smsc2_status().

00910 {
00911     switch (status_type) {
00912         case BBSTATUS_HTML:
00913             return "<br>\n";
00914         case BBSTATUS_WML:
00915             return "<br/>\n";
00916         case BBSTATUS_TEXT:
00917             return "\n";
00918         case BBSTATUS_XML:
00919             return "\n";
00920         default:
00921             return NULL;
00922     }
00923 }

int bb_stop_smsc Octstr id  ) 
 

Definition at line 794 of file bearerbox.c.

References smsc2_stop_smsc().

Referenced by httpd_stop_smsc().

00795 {
00796     return smsc2_stop_smsc(id);
00797 }

Here is the call graph for this function:

int bb_suspend void   ) 
 

Definition at line 747 of file bearerbox.c.

References BB_RUNNING, bb_status, gwlist_add_producer(), isolated, mutex_lock, mutex_unlock, smsc2_suspend(), status_mutex, and suspended.

Referenced by httpd_suspend().

00748 {
00749     mutex_lock(status_mutex);
00750     if (bb_status != BB_RUNNING && bb_status != BB_ISOLATED) {
00751         mutex_unlock(status_mutex);
00752         return -1;
00753     }
00754     if (bb_status != BB_ISOLATED) {
00755         smsc2_suspend();
00756         gwlist_add_producer(isolated);
00757     }
00758     bb_status = BB_SUSPENDED;
00759     gwlist_add_producer(suspended);
00760     mutex_unlock(status_mutex);
00761     return 0;
00762 }

Here is the call graph for this function:

void boxc_cleanup void   ) 
 

Definition at line 1395 of file bb_boxc.c.

References box_allow_ip, box_deny_ip, boxid, counter_destroy(), and octstr_destroy().

Referenced by main().

01396 {
01397     octstr_destroy(box_allow_ip);
01398     octstr_destroy(box_deny_ip);
01399     box_allow_ip = NULL;
01400     box_deny_ip = NULL;
01401     counter_destroy(boxid);
01402     boxid = NULL;
01403 }

Here is the call graph for this function:

int boxc_incoming_wdp_queue void   ) 
 

Definition at line 1378 of file bb_boxc.c.

References Boxc, gwlist_get(), gwlist_len(), gwlist_lock(), gwlist_unlock(), _boxc::incoming, and wapbox_list.

Referenced by bb_print_status().

01379 {
01380     int i, q = 0;
01381     Boxc *boxc;
01382     
01383     if (wapbox_list) {
01384         gwlist_lock(wapbox_list);
01385         for(i=0; i < gwlist_len(wapbox_list); i++) {
01386             boxc = gwlist_get(wapbox_list, i);
01387             q += gwlist_len(boxc->incoming);
01388         }
01389         gwlist_unlock(wapbox_list);
01390     }
01391     return q;
01392 }

Here is the call graph for this function:

Octstr* boxc_status int  status_type  ) 
 

Definition at line 1254 of file bb_boxc.c.

References _boxc::alive, bb_status_linebreak(), BBSTATUS_HTML, Boxc, _boxc::boxc_id, _boxc::client_ip, _boxc::conn, conn_get_ssl(), _boxc::connect_time, dict_key_count(), gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), gwlist_len(), gwlist_lock(), gwlist_unlock(), HAVE_LIBSSL, _boxc::incoming, octstr_append_cstr(), octstr_create, octstr_destroy(), octstr_format(), octstr_format_append(), octstr_get_cstr, _boxc::sent, smsbox_list, smsbox_list_rwlock, and wapbox_list.

Referenced by bb_print_status().

01255 {
01256     Octstr *tmp;
01257     char *lb, *ws;
01258     int i, boxes, para = 0;
01259     time_t orig, t;
01260     Boxc *bi;
01261 
01262     orig = time(NULL);
01263 
01264     /*
01265      * XXX: this will cause segmentation fault if this is called
01266      *    between 'destroy_list and setting list to NULL calls.
01267      *    Ok, this has to be fixed, but now I am too tired.
01268      */
01269     
01270     if ((lb = bb_status_linebreak(status_type))==NULL)
01271         return octstr_create("Un-supported format");
01272 
01273     if (status_type == BBSTATUS_HTML)
01274         ws = "&nbsp;&nbsp;&nbsp;&nbsp;";
01275     else if (status_type == BBSTATUS_TEXT)
01276         ws = "    ";
01277     else
01278         ws = "";
01279 
01280     if (status_type == BBSTATUS_HTML || status_type == BBSTATUS_WML)
01281         para = 1;
01282     
01283     if (status_type == BBSTATUS_XML) {
01284         tmp = octstr_create ("");
01285         octstr_append_cstr(tmp, "<boxes>\n\t");
01286     }
01287     else
01288         tmp = octstr_format("%sBox connections:%s", para ? "<p>" : "", lb);
01289     boxes = 0;
01290     
01291     if (wapbox_list) {
01292         gwlist_lock(wapbox_list);
01293         for(i=0; i < gwlist_len(wapbox_list); i++) {
01294             bi = gwlist_get(wapbox_list, i);
01295             if (bi->alive == 0)
01296                 continue;
01297             t = orig - bi->connect_time;
01298             if (status_type == BBSTATUS_XML)
01299                 octstr_format_append(tmp,
01300                 "<box>\n\t\t<type>wapbox</type>\n\t\t<IP>%s</IP>\n"
01301                 "\t\t<status>on-line %ldd %ldh %ldm %lds</status>\n"
01302                 "\t\t<ssl>%s</ssl>\n\t</box>\n",
01303                 octstr_get_cstr(bi->client_ip),
01304                 t/3600/24, t/3600%24, t/60%60, t%60,
01305 #ifdef HAVE_LIBSSL
01306                 conn_get_ssl(bi->conn) != NULL ? "yes" : "no"
01307 #else 
01308                 "not installed"
01309 #endif
01310                 );
01311             else
01312                 octstr_format_append(tmp,
01313                 "%swapbox, IP %s (on-line %ldd %ldh %ldm %lds) %s %s",
01314                 ws, octstr_get_cstr(bi->client_ip),
01315                 t/3600/24, t/3600%24, t/60%60, t%60, 
01316 #ifdef HAVE_LIBSSL
01317                 conn_get_ssl(bi->conn) != NULL ? "using SSL" : "",
01318 #else
01319                 "",
01320 #endif 
01321                 lb);
01322                 boxes++;
01323            }
01324            gwlist_unlock(wapbox_list);
01325         }
01326         if (smsbox_list) {
01327             gw_rwlock_rdlock(smsbox_list_rwlock);
01328         for(i=0; i < gwlist_len(smsbox_list); i++) {
01329             bi = gwlist_get(smsbox_list, i);
01330             if (bi->alive == 0)
01331                 continue;
01332             t = orig - bi->connect_time;
01333             if (status_type == BBSTATUS_XML)
01334                 octstr_format_append(tmp, "<box>\n\t\t<type>smsbox</type>\n"
01335                     "\t\t<id>%s</id>\n\t\t<IP>%s</IP>\n"
01336                     "\t\t<queue>%ld</queue>\n"
01337                     "\t\t<status>on-line %ldd %ldh %ldm %lds</status>\n"
01338                     "\t\t<ssl>%s</ssl>\n\t</box>",
01339                     (bi->boxc_id ? octstr_get_cstr(bi->boxc_id) : ""),
01340                     octstr_get_cstr(bi->client_ip),
01341                     gwlist_len(bi->incoming) + dict_key_count(bi->sent),
01342                     t/3600/24, t/3600%24, t/60%60, t%60,
01343 #ifdef HAVE_LIBSSL
01344                     conn_get_ssl(bi->conn) != NULL ? "yes" : "no"
01345 #else 
01346                     "not installed"
01347 #endif
01348                     );
01349             else
01350                 octstr_format_append(tmp, "%ssmsbox:%s, IP %s (%ld queued), (on-line %ldd %ldh %ldm %lds) %s %s",
01351                     ws, (bi->boxc_id ? octstr_get_cstr(bi->boxc_id) : "(none)"), 
01352                     octstr_get_cstr(bi->client_ip), gwlist_len(bi->incoming) + dict_key_count(bi->sent),
01353                     t/3600/24, t/3600%24, t/60%60, t%60, 
01354 #ifdef HAVE_LIBSSL
01355                     conn_get_ssl(bi->conn) != NULL ? "using SSL" : "",
01356 #else
01357                     "",
01358 #endif 
01359                     lb);
01360            boxes++;
01361         }
01362         gw_rwlock_unlock(smsbox_list_rwlock);
01363     }
01364     if (boxes == 0 && status_type != BBSTATUS_XML) {
01365         octstr_destroy(tmp);
01366         tmp = octstr_format("%sNo boxes connected", para ? "<p>" : "");
01367     }
01368     if (para)
01369         octstr_append_cstr(tmp, "</p>");
01370     if (status_type == BBSTATUS_XML)
01371         octstr_append_cstr(tmp, "</boxes>\n");
01372     else
01373         octstr_append_cstr(tmp, "\n\n");
01374     return tmp;
01375 }

Here is the call graph for this function:

int httpadmin_start Cfg config  ) 
 

Definition at line 454 of file bb_http.c.

References cfg_get, cfg_get_bool(), cfg_get_integer(), cfg_get_single_group(), gwthread_create, ha_allow_ip, ha_deny_ip, ha_interface, ha_password, ha_port, ha_status_pw, http_open_port_if(), httpadmin_run(), httpadmin_running, octstr_destroy(), octstr_imm(), panic, and ssl.

Referenced by init_bearerbox().

00455 {
00456     CfgGroup *grp;
00457     int ssl = 0; 
00458 #ifdef HAVE_LIBSSL
00459     Octstr *ssl_server_cert_file;
00460     Octstr *ssl_server_key_file;
00461 #endif /* HAVE_LIBSSL */
00462     
00463     if (httpadmin_running) return -1;
00464 
00465 
00466     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00467     if (cfg_get_integer(&ha_port, grp, octstr_imm("admin-port")) == -1)
00468     panic(0, "Missing admin-port variable, cannot start HTTP admin");
00469 
00470     ha_interface = cfg_get(grp, octstr_imm("admin-interface"));
00471     ha_password = cfg_get(grp, octstr_imm("admin-password"));
00472     if (ha_password == NULL)
00473     panic(0, "You MUST set HTTP admin-password");
00474     
00475     ha_status_pw = cfg_get(grp, octstr_imm("status-password"));
00476 
00477     ha_allow_ip = cfg_get(grp, octstr_imm("admin-allow-ip"));
00478     ha_deny_ip = cfg_get(grp, octstr_imm("admin-deny-ip"));
00479 
00480 #ifdef HAVE_LIBSSL
00481     cfg_get_bool(&ssl, grp, octstr_imm("admin-port-ssl"));
00482     
00483     /*
00484      * check if SSL is desired for HTTP servers and then
00485      * load SSL client and SSL server public certificates 
00486      * and private keys
00487      */    
00488     ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
00489     ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
00490     if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) {
00491         /* we are fine here, the following call is now in conn_config_ssl(),
00492          * so there is no reason to do this twice.
00493 
00494         use_global_server_certkey_file(ssl_server_cert_file, 
00495             ssl_server_key_file);
00496         */
00497     } else if (ssl) {
00498        panic(0, "You MUST specify cert and key files within core group for SSL-enabled HTTP servers!");
00499     }
00500 
00501     octstr_destroy(ssl_server_cert_file);
00502     octstr_destroy(ssl_server_key_file);
00503 #endif /* HAVE_LIBSSL */
00504 
00505     http_open_port_if(ha_port, ssl, ha_interface);
00506 
00507     if (gwthread_create(httpadmin_run, NULL) == -1)
00508     panic(0, "Failed to start a new thread for HTTP admin");
00509 
00510     httpadmin_running = 1;
00511     return 0;
00512 }

Here is the call graph for this function:

void httpadmin_stop void   ) 
 

Definition at line 515 of file bb_http.c.

References gwthread_join_every(), ha_allow_ip, ha_deny_ip, ha_interface, ha_password, ha_status_pw, http_close_all_ports(), httpadmin_run(), and octstr_destroy().

Referenced by main().

00516 {
00517     http_close_all_ports();
00518     gwthread_join_every(httpadmin_run);
00519     octstr_destroy(ha_interface);    
00520     octstr_destroy(ha_password);
00521     octstr_destroy(ha_status_pw);
00522     octstr_destroy(ha_allow_ip);
00523     octstr_destroy(ha_deny_ip);
00524     ha_password = NULL;
00525     ha_status_pw = NULL;
00526     ha_allow_ip = NULL;
00527     ha_deny_ip = NULL;
00528 }

Here is the call graph for this function:

int route_incoming_to_boxc Msg msg  ) 
 

Definition at line 1415 of file bb_boxc.c.

References Boxc, _boxc::boxc_id, dict_get(), gw_assert, gw_rand(), gw_rwlock_rdlock(), gw_rwlock_unlock(), gwlist_get(), gwlist_len(), gwlist_produce(), _boxc::incoming, incoming_sms, _boxc::load, max_incoming_sms_qlength, msg_type, octstr_destroy(), octstr_format(), octstr_get_cstr, octstr_len(), _boxc::routable, sms, smsbox_by_id, smsbox_by_receiver, smsbox_by_smsc, smsbox_by_smsc_receiver, smsbox_list, smsbox_list_rwlock, and warning().

Referenced by bb_smscconn_receive(), and sms_to_smsboxes().

01416 {
01417     Boxc *bc = NULL, *best = NULL;
01418     Octstr *s, *r, *rs;
01419     long len, b, i;
01420     int full_found = 0;
01421 
01422     s = r = NULL;
01423     gw_assert(msg_type(msg) == sms);
01424 
01425     /* msg_dump(msg, 0); */
01426 
01427     /* 
01428      * We have a specific route to pass this msg to smsbox-id 
01429      * Lookup the connection in the dictionary.
01430      */
01431     gw_rwlock_rdlock(smsbox_list_rwlock);
01432     if (gwlist_len(smsbox_list) == 0) {
01433         gw_rwlock_unlock(smsbox_list_rwlock);
01434         warning(0, "smsbox_list empty!");
01435         if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) {
01436             gwlist_produce(incoming_sms, msg);
01437         return 0;
01438          }
01439          else
01440              return -1;
01441     }
01442 
01443     if (octstr_len(msg->sms.boxc_id) > 0) {
01444         
01445         bc = dict_get(smsbox_by_id, msg->sms.boxc_id);
01446         if (bc == NULL) {
01447             /*
01448              * something is wrong, this was the smsbox connection we used
01449              * for sending, so it seems this smsbox is gone
01450              */
01451             warning(0,"Could not route message to smsbox id <%s>, smsbox is gone!",
01452                     octstr_get_cstr(msg->sms.boxc_id));
01453         }
01454     }
01455     else {
01456         /*
01457          * Check if we have a "smsbox-route" for this msg.
01458          * Where the shortcode route has a higher priority then the smsc-id rule.
01459          * Highest priority has the combined <shortcode>:<smsc-id> route.
01460          */
01461         Octstr *os = octstr_format("%s:%s", 
01462                                    octstr_get_cstr(msg->sms.receiver),
01463                                    octstr_get_cstr(msg->sms.smsc_id));
01464         s = (msg->sms.smsc_id ? dict_get(smsbox_by_smsc, msg->sms.smsc_id) : NULL);
01465         r = (msg->sms.receiver ? dict_get(smsbox_by_receiver, msg->sms.receiver) : NULL);
01466         rs = (os ? dict_get(smsbox_by_smsc_receiver, os) : NULL);
01467         octstr_destroy(os); 
01468         bc = rs ? dict_get(smsbox_by_id, rs) : 
01469             (r ? dict_get(smsbox_by_id, r) : (s ? dict_get(smsbox_by_id, s) : NULL));
01470     }
01471 
01472     /* check if we found our routing */
01473     if (bc != NULL) {
01474         if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(bc->incoming)) {
01475             gwlist_produce(bc->incoming, msg);
01476             gw_rwlock_unlock(smsbox_list_rwlock);
01477             return 1; /* we are done */
01478         }
01479         else {
01480             gw_rwlock_unlock(smsbox_list_rwlock);
01481             return -1;
01482         }
01483     }
01484     else if (s != NULL || r != NULL || octstr_len(msg->sms.boxc_id) > 0) {
01485         gw_rwlock_unlock(smsbox_list_rwlock);
01486         /*
01487          * we have routing defined, but no smsbox connected at the moment.
01488          * put msg into global incoming queue and wait until smsbox with
01489          * such boxc_id connected.
01490          */
01491         if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) {
01492             gwlist_produce(incoming_sms, msg);
01493             return 0;
01494         }
01495         else
01496             return -1;
01497     }
01498 
01499     /*
01500      * ok, none of the routing things applied previously, so route it to
01501      * a random smsbox.
01502      */
01503 
01504     /* take random smsbox from list, and then check all smsboxes
01505      * and select the one with lowest load level - if tied, the first
01506      * one
01507      */
01508     len = gwlist_len(smsbox_list);
01509     b = gw_rand() % len;
01510 
01511     for(i = 0; i < gwlist_len(smsbox_list); i++) {
01512     bc = gwlist_get(smsbox_list, (i+b) % len);
01513 
01514         if (bc->boxc_id != NULL || bc->routable == 0)
01515             bc = NULL;
01516 
01517         if (bc != NULL && max_incoming_sms_qlength > 0 &&
01518             gwlist_len(bc->incoming) > max_incoming_sms_qlength) {
01519             full_found = 1;
01520             bc = NULL;
01521         }
01522 
01523         if ((bc != NULL && best != NULL && bc->load < best->load) ||
01524              (bc != NULL && best == NULL)) {
01525         best = bc;
01526         }
01527     }
01528 
01529     if (best != NULL) {
01530         best->load++;
01531         gwlist_produce(best->incoming, msg);
01532     }
01533 
01534     gw_rwlock_unlock(smsbox_list_rwlock);
01535 
01536     if (best == NULL && full_found == 0) {
01537     warning(0, "smsbox_list empty!");
01538         if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) {
01539             gwlist_produce(incoming_sms, msg);
01540         return 0;
01541          }
01542          else
01543              return -1;
01544     }
01545     else if (best == NULL && full_found == 1)
01546         return -1;
01547 
01548     return 1;
01549 }

Here is the call graph for this function:

int smsbox_restart Cfg config  ) 
 

Definition at line 1198 of file bb_boxc.c.

01199 {
01200     if (!smsbox_running) return -1;
01201     
01202     /* send new config to clients */
01203 
01204     return 0;
01205 }

int smsbox_start Cfg config  ) 
 

Definition at line 1144 of file bb_boxc.c.

References boxid, cfg_get_bool(), cfg_get_integer(), cfg_get_single_group(), counter_create(), debug(), dict_create(), error(), gw_rwlock_create(), gwlist_add_producer(), gwlist_create, gwthread_create, info(), init_smsbox_routes(), octstr_destroy(), octstr_imm(), outgoing_sms, panic, sms_dequeue_thread, sms_to_smsboxes(), smsbox_by_id, smsbox_by_receiver, smsbox_by_smsc, smsbox_by_smsc_receiver, smsbox_list, smsbox_list_rwlock, smsbox_max_pending, smsbox_port, smsbox_port_ssl, smsbox_running, and smsboxc_run().

Referenced by start_smsc().

01145 {
01146     CfgGroup *grp;
01147     
01148     if (smsbox_running) return -1;
01149 
01150     debug("bb", 0, "starting smsbox connection module");
01151 
01152     grp = cfg_get_single_group(cfg, octstr_imm("core"));
01153     if (cfg_get_integer(&smsbox_port, grp, octstr_imm("smsbox-port")) == -1) {
01154         error(0, "Missing smsbox-port variable, cannot start smsboxes");
01155         return -1;
01156     }
01157 #ifdef HAVE_LIBSSL
01158     cfg_get_bool(&smsbox_port_ssl, grp, octstr_imm("smsbox-port-ssl"));
01159 #endif /* HAVE_LIBSSL */
01160 
01161     if (smsbox_port_ssl)
01162         debug("bb", 0, "smsbox connection module is SSL-enabled");
01163         
01164     if (cfg_get_integer(&smsbox_max_pending, grp, octstr_imm("smsbox-max-pending")) == -1) {
01165         smsbox_max_pending = SMSBOX_MAX_PENDING;
01166         info(0, "BOXC: 'smsbox-max-pending' not set, using default (%ld).", smsbox_max_pending);
01167     }
01168     
01169     smsbox_list = gwlist_create();  /* have a list of connections */
01170     smsbox_list_rwlock = gw_rwlock_create();
01171     if (!boxid)
01172         boxid = counter_create();
01173 
01174     /* the smsbox routing specific inits */
01175     smsbox_by_id = dict_create(10, NULL);  /* and a hash directory of identified */
01176     smsbox_by_smsc = dict_create(30, (void(*)(void *)) octstr_destroy);
01177     smsbox_by_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
01178     smsbox_by_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
01179 
01180     /* load the defined smsbox routing rules */
01181     init_smsbox_routes(cfg);
01182 
01183     gwlist_add_producer(outgoing_sms);
01184     gwlist_add_producer(smsbox_list);
01185 
01186     smsbox_running = 1;
01187     
01188     if ((sms_dequeue_thread = gwthread_create(sms_to_smsboxes, NULL)) == -1)
01189         panic(0, "Failed to start a new thread for smsbox routing");
01190 
01191     if (gwthread_create(smsboxc_run, &smsbox_port) == -1)
01192         panic(0, "Failed to start a new thread for smsbox connections");
01193 
01194     return 0;
01195 }

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:

int smsc2_restart Cfg config  ) 
 

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 config  ) 
 

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:

int udp_addwdp Msg msg  ) 
 

Definition at line 385 of file bb_udp.c.

References _udpc::addr, gwlist_get(), gwlist_len(), gwlist_lock(), gwlist_produce(), gwlist_unlock(), msg_type, octstr_compare(), octstr_destroy(), _udpc::outgoing_list, udp_get_ip(), udp_get_port(), Udpc, udpc_list, and wdp_datagram.

Referenced by wdp_router().

00386 {
00387     int i;
00388     Udpc *udpc, *def_udpc;
00389     Octstr *ip;
00390     
00391     def_udpc = NULL;
00392     if (!udp_running) return -1;
00393     assert(msg != NULL);
00394     assert(msg_type(msg) == wdp_datagram);
00395     
00396     gwlist_lock(udpc_list);
00397     /* select in which list to add this */
00398     for (i=0; i < gwlist_len(udpc_list); i++) {
00399         udpc = gwlist_get(udpc_list, i);
00400 
00401         if (msg->wdp_datagram.source_port == udp_get_port(udpc->addr)) {
00402                     def_udpc = udpc;
00403                     ip = udp_get_ip(udpc->addr);
00404             if (octstr_compare(msg->wdp_datagram.source_address, ip) == 0) {
00405                         octstr_destroy(ip);
00406                 gwlist_produce(udpc->outgoing_list, msg);
00407                 gwlist_unlock(udpc_list);
00408                 return 0;
00409             }
00410                     octstr_destroy(ip);
00411         }
00412     }
00413 
00414     if (NULL != def_udpc) {
00415     gwlist_produce(def_udpc->outgoing_list, msg);
00416     gwlist_unlock(udpc_list);
00417     return 0;
00418     }
00419 
00420     gwlist_unlock(udpc_list);
00421     return -1;
00422 }

Here is the call graph for this function:

int udp_die void   ) 
 

Definition at line 434 of file bb_udp.c.

References allow_ip, debug(), deny_ip, gwlist_consume(), gwlist_destroy(), gwlist_remove_producer(), octstr_destroy(), _udpc::outgoing_list, udp_running, Udpc, and udpc_list.

Referenced by service_router(), and wdp_router().

00435 {
00436     Udpc *udpc;
00437 
00438     if (!udp_running) return -1;
00439     
00440     /*
00441      * remove producers from all outgoing lists.
00442      */
00443     debug("bb.udp", 0, "udp_die: removing producers from udp-lists");
00444 
00445     while((udpc = gwlist_consume(udpc_list)) != NULL) {
00446     gwlist_remove_producer(udpc->outgoing_list);
00447     }
00448     gwlist_destroy(udpc_list, NULL);
00449     udp_running = 0;
00450     
00451     octstr_destroy(allow_ip);
00452     octstr_destroy(deny_ip);
00453     allow_ip = NULL;
00454     deny_ip = NULL;
00455     
00456     return 0;
00457 }

Here is the call graph for this function:

int udp_outgoing_queue void   ) 
 

Definition at line 460 of file bb_udp.c.

References gwlist_get(), gwlist_len(), gwlist_lock(), gwlist_unlock(), _udpc::outgoing_list, udp_running, Udpc, and udpc_list.

Referenced by bb_print_status().

00461 {
00462     int i, q = 0;
00463     Udpc *udpc;
00464 
00465     if (!udp_running || udpc_list == NULL)
00466     return 0;
00467 
00468     gwlist_lock(udpc_list);
00469     for (i=0; i < gwlist_len(udpc_list); i++) {
00470     udpc = gwlist_get(udpc_list, i);
00471     q += gwlist_len(udpc->outgoing_list);
00472     }
00473     gwlist_unlock(udpc_list);
00474     return q;
00475 }

Here is the call graph for this function:

int udp_shutdown void   ) 
 

Definition at line 424 of file bb_udp.c.

References debug(), gwlist_remove_producer(), and incoming_wdp.

Referenced by bb_shutdown(), and main().

00425 {
00426     if (!udp_running) return -1;
00427 
00428     debug("bb.thread", 0, "udp_shutdown: Starting avalanche");
00429     gwlist_remove_producer(incoming_wdp);
00430     return 0;
00431 }

Here is the call graph for this function:

int udp_start Cfg config  ) 
 

Definition at line 323 of file bb_udp.c.

References add_service(), allow_ip, cfg_get, cfg_get_single_group(), debug(), deny_ip, error(), gwlist_add_producer(), gwlist_create, gwlist_destroy(), gwlist_extract_first(), gwlist_len(), incoming_wdp, info(), octstr_destroy(), octstr_get_cstr, octstr_imm(), octstr_split(), udp_running, and udpc_list.

00324 {
00325     CfgGroup *grp;
00326     Octstr *iface;
00327     List *ifs;
00328     int allow_wtls;
00329     
00330     if (udp_running) return -1;
00331     
00332     debug("bb.udp", 0, "starting UDP sender/receiver module");
00333 
00334     grp = cfg_get_single_group(cfg, octstr_imm("core"));
00335     iface = cfg_get(grp, octstr_imm("wdp-interface-name"));
00336     if (iface == NULL) {
00337         error(0, "Missing wdp-interface-name variable, cannot start UDP");
00338         return -1;
00339     }
00340 
00341     allow_ip = cfg_get(grp, octstr_imm("udp-allow-ip"));
00342     deny_ip = cfg_get(grp, octstr_imm("udp-deny-ip"));
00343 
00344     /*  we'll activate WTLS as soon as we have a 'wtls' config group */
00345     grp = cfg_get_single_group(cfg, octstr_imm("wtls"));
00346     allow_wtls = grp != NULL ? 1 : 0;
00347 
00348     udpc_list = gwlist_create();    /* have a list of running systems */
00349 
00350     ifs = octstr_split(iface, octstr_imm(";"));
00351     octstr_destroy(iface);
00352     while (gwlist_len(ifs) > 0) {
00353         iface = gwlist_extract_first(ifs);
00354     info(0, "Adding interface %s", octstr_get_cstr(iface));
00355         add_service(9200, octstr_get_cstr(iface));   /* wsp     */
00356         add_service(9201, octstr_get_cstr(iface));   /* wsp/wtp */
00357     
00358 #ifdef HAVE_WTLS_OPENSSL
00359         if (allow_wtls) {
00360              add_service(9202, octstr_get_cstr(iface));   /* wsp/wtls   */
00361              add_service(9203, octstr_get_cstr(iface));   /* wsp/wtp/wtls */
00362         }
00363 #else
00364         if (allow_wtls)
00365              error(0, "These is a 'wtls' group in configuration, but no WTLS support compiled in!");
00366 #endif
00367     /* add_service(9204, octstr_get_cstr(interface_name));  * vcard */
00368     /* add_service(9205, octstr_get_cstr(interface_name));  * vcal  */
00369     /* add_service(9206, octstr_get_cstr(interface_name));  * vcard/wtls */
00370     /* add_service(9207, octstr_get_cstr(interface_name));  * vcal/wtls */
00371         octstr_destroy(iface);
00372     }
00373     gwlist_destroy(ifs, NULL);
00374     
00375     gwlist_add_producer(incoming_wdp);
00376     udp_running = 1;
00377     return 0;
00378 }

Here is the call graph for this function:

int wapbox_start Cfg config  ) 
 

Definition at line 1211 of file bb_boxc.c.

References box_allow_ip, box_deny_ip, boxid, cfg_get, cfg_get_bool(), cfg_get_integer(), cfg_get_single_group(), counter_create(), debug(), error(), gwlist_add_producer(), gwlist_create, gwthread_create, info(), octstr_create, octstr_imm(), outgoing_wdp, panic, wapbox_list, wapbox_port, wapbox_port_ssl, wapbox_running, wapboxc_run(), and wdp_to_wapboxes().

Referenced by start_wap().

01212 {
01213     CfgGroup *grp;
01214 
01215     if (wapbox_running) return -1;
01216 
01217     debug("bb", 0, "starting wapbox connection module");
01218     
01219     grp = cfg_get_single_group(cfg, octstr_imm("core"));
01220     
01221     if (cfg_get_integer(&wapbox_port, grp, octstr_imm("wapbox-port")) == -1) {
01222         error(0, "Missing wapbox-port variable, cannot start WAP");
01223         return -1;
01224     }
01225 #ifdef HAVE_LIBSSL
01226     cfg_get_bool(&wapbox_port_ssl, grp, octstr_imm("wapbox-port-ssl"));
01227 #endif /* HAVE_LIBSSL */
01228   
01229     box_allow_ip = cfg_get(grp, octstr_imm("box-allow-ip"));
01230     if (box_allow_ip == NULL)
01231         box_allow_ip = octstr_create("");
01232     box_deny_ip = cfg_get(grp, octstr_imm("box-deny-ip"));
01233     if (box_deny_ip == NULL)
01234         box_deny_ip = octstr_create("");
01235     if (box_allow_ip != NULL && box_deny_ip == NULL)
01236         info(0, "Box connection allowed IPs defined without any denied...");
01237     
01238     wapbox_list = gwlist_create();  /* have a list of connections */
01239     gwlist_add_producer(outgoing_wdp);
01240     if (!boxid)
01241         boxid = counter_create();
01242 
01243     if (gwthread_create(wdp_to_wapboxes, NULL) == -1)
01244         panic(0, "Failed to start a new thread for wapbox routing");
01245  
01246     if (gwthread_create(wapboxc_run, &wapbox_port) == -1)
01247         panic(0, "Failed to start a new thread for wapbox connections");
01248 
01249     wapbox_running = 1;
01250     return 0;
01251 }

Here is the call graph for this function:

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