00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #include "gw-config.h"
00070
00071 #include <errno.h>
00072 #include <stdlib.h>
00073 #include <stdio.h>
00074 #include <time.h>
00075 #include <string.h>
00076 #include <sys/time.h>
00077 #include <sys/types.h>
00078 #include <unistd.h>
00079 #include <signal.h>
00080 #include <fcntl.h>
00081
00082
00083 #include "gwlib/gwlib.h"
00084 #include "msg.h"
00085 #include "sms.h"
00086 #include "bearerbox.h"
00087 #include "numhash.h"
00088 #include "smscconn.h"
00089 #include "dlr.h"
00090
00091 #include "bb_smscconn_cb.h"
00092 #include "smscconn_p.h"
00093
00094
00095
00096 extern volatile sig_atomic_t bb_status;
00097 extern List *incoming_sms;
00098 extern List *outgoing_sms;
00099
00100 extern Counter *incoming_sms_counter;
00101 extern Counter *outgoing_sms_counter;
00102
00103 extern List *flow_threads;
00104 extern List *suspended;
00105 extern List *isolated;
00106
00107
00108 extern long max_outgoing_sms_qlength;
00109
00110 extern long max_incoming_sms_qlength;
00111
00112
00113
00114 static volatile sig_atomic_t smsc_running;
00115 static List *smsc_list;
00116 static RWLock smsc_list_lock;
00117 static List *smsc_groups;
00118 static Octstr *unified_prefix;
00119
00120 static Numhash *black_list;
00121 static Numhash *white_list;
00122
00123 static regex_t *white_list_regex;
00124 static regex_t *black_list_regex;
00125
00126 static long router_thread = -1;
00127
00128
00129 static long sms_resend_frequency;
00130 static long sms_resend_retry;
00131
00132
00133
00134
00135
00136 Counter *split_msg_counter;
00137
00138
00139 static int handle_concatenated_mo;
00140
00141 static long concatenated_mo_timeout;
00142
00143 enum {concat_error = -1, concat_complete = 0, concat_pending = 1, concat_none};
00144
00145
00146
00147
00148 static long route_incoming_to_smsc(SMSCConn *conn, Msg *msg);
00149
00150 static void init_concat_handler(void);
00151 static void shutdown_concat_handler(void);
00152 static int check_concatenation(Msg **msg, Octstr *smscid);
00153 static void clear_old_concat_parts(void);
00154
00155
00156
00157
00158
00159
00160
00161 void bb_smscconn_ready(SMSCConn *conn)
00162 {
00163 gwlist_add_producer(flow_threads);
00164 gwlist_add_producer(incoming_sms);
00165 }
00166
00167
00168 void bb_smscconn_connected(SMSCConn *conn)
00169 {
00170 if (router_thread >= 0)
00171 gwthread_wakeup(router_thread);
00172 }
00173
00174
00175 void bb_smscconn_killed(void)
00176 {
00177
00178
00179
00180 gwlist_remove_producer(incoming_sms);
00181 gwlist_remove_producer(flow_threads);
00182 }
00183
00184
00185 static void handle_split(SMSCConn *conn, Msg *msg, long reason)
00186 {
00187 struct split_parts *split = msg->sms.split_parts;
00188
00189
00190
00191
00192
00193
00194 if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_status(conn) == SMSCCONN_ACTIVE &&
00195 smscconn_send(conn, msg) == 0) {
00196
00197 msg_destroy(msg);
00198 return;
00199 }
00200
00201
00202
00203
00204
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;
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
00225
00226
00227 msg_destroy(msg);
00228
00229 if (counter_decrease(split->parts_left) <= 1) {
00230
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 }
00243
00244
00245 void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *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
00257 store_save_ack(sms, ack_success);
00258
00259 bb_alog_sms(conn, sms, "Sent SMS");
00260
00261
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 }
00279
00280
00281 void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *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
00293
00294
00295
00296 if (conn && smscconn_status(conn) == SMSCCONN_ACTIVE) {
00297
00298
00299
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
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
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 }
00349
00350 long bb_smscconn_receive(SMSCConn *conn, Msg *sms)
00351 {
00352 char *uf;
00353 int rc;
00354 Msg *copy;
00355
00356
00357
00358
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
00401 if (sms->sms.sms_type != report_mo)
00402 sms->sms.sms_type = mo;
00403
00404
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
00414
00415
00416
00417 if ((rc = route_incoming_to_smsc(conn, copy)) == -1) {
00418 int ret;
00419
00420
00421
00422 if (handle_concatenated_mo && copy->sms.sms_type == mo) {
00423 ret = check_concatenation(©, (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
00433 msg_destroy(sms);
00434
00435 sms = msg_duplicate(copy);
00436 break;
00437 case concat_error:
00438
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
00450
00451
00452
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
00465 store_save_ack(sms, ack_failed);
00466
00467 msg_destroy(copy);
00468 msg_destroy(sms);
00469 gwthread_sleep(0.1);
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 }
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 static void sms_router(void *arg)
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
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
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
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 }
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 int smsc2_start(Cfg *cfg)
00579 {
00580 CfgGroup *grp;
00581 SMSCConn *conn;
00582 Octstr *os;
00583 int i;
00584
00585 if (smsc_running) return -1;
00586
00587
00588 split_msg_counter = counter_create();
00589
00590
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;
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 }
00660
00661
00662
00663
00664
00665 static long smsc2_find(Octstr *id, long start)
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 }
00683
00684 int smsc2_stop_smsc(Octstr *id)
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
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);
00702 }
00703 }
00704 gw_rwlock_unlock(&smsc_list_lock);
00705 return 0;
00706 }
00707
00708 int smsc2_restart_smsc(Octstr *id)
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
00721 while((i = smsc2_find(id, ++i)) != -1) {
00722 int hit;
00723 long group_index;
00724
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
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
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;
00759 }
00760
00761
00762 gwlist_delete(smsc_list, i, 1);
00763
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
00772 if (router_thread >= 0)
00773 gwthread_wakeup(router_thread);
00774
00775 return 0;
00776 }
00777
00778 void smsc2_resume(void)
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 }
00796
00797
00798 void smsc2_suspend(void)
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 }
00813
00814
00815 int smsc2_shutdown(void)
00816 {
00817 SMSCConn *conn;
00818 long i;
00819
00820 if (!smsc_running)
00821 return -1;
00822
00823
00824
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
00836
00837
00838
00839
00840
00841 gwlist_remove_producer(incoming_sms);
00842 return 0;
00843 }
00844
00845
00846 void smsc2_cleanup(void)
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
00873 counter_destroy(split_msg_counter);
00874 gw_rwlock_destroy(&smsc_list_lock);
00875
00876
00877 shutdown_concat_handler();
00878
00879 smsc_running = 0;
00880 }
00881
00882
00883 Octstr *smsc2_status(int status_type)
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
00921
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, " <b>");
00932 octstr_append(tmp, conn_id);
00933 octstr_append_cstr(tmp, "</b> ");
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 }
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004 long smsc2_rout(Msg *msg, int resend)
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
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
01020
01021
01022 uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
01023 normalize_number(uf, &(msg->sms.receiver));
01024
01025
01026
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
01037
01038
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
01064 if (ret != 1 && best_preferred)
01065 continue;
01066
01067
01068 if (info.status != SMSCCONN_ACTIVE) {
01069 bad_found = 1;
01070 continue;
01071 }
01072
01073 if (info.queued > max_queue) {
01074 full_found = 1;
01075 continue;
01076 }
01077 if (ret == 1) {
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;
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
01129 if (ret == -1)
01130 return smsc2_rout(msg, resend);
01131
01132 msg_destroy(msg);
01133 return SMSCCONN_SUCCESS;
01134 }
01135
01136
01137
01138
01139
01140
01141 static long route_incoming_to_smsc(SMSCConn *conn, Msg *msg)
01142 {
01143 Octstr *smsc;
01144
01145
01146 if (!conn || !msg)
01147 return -1;
01148
01149
01150 if (!conn->reroute_dlr && (msg->sms.sms_type == report_mo || msg->sms.sms_type == report_mt))
01151 return -1;
01152
01153
01154
01155
01156
01157 if (conn->reroute) {
01158
01159 store_save_ack(msg, ack_success);
01160 msg->sms.sms_type = mt_push;
01161 store_save(msg);
01162
01163 return smsc2_rout(msg, 0);
01164 }
01165
01166 if (conn->reroute_to_smsc) {
01167
01168 store_save_ack(msg, ack_success);
01169 msg->sms.sms_type = mt_push;
01170 store_save(msg);
01171
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
01180 store_save_ack(msg, ack_success);
01181 msg->sms.sms_type = mt_push;
01182 store_save(msg);
01183
01184
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 }
01192
01193
01194
01195
01196
01197
01198 typedef struct ConcatMsg {
01199 int refnum;
01200 int total_parts;
01201 int num_parts;
01202 time_t trecv;
01203 Octstr *key;
01204 int ack;
01205
01206 Msg **parts;
01207 } ConcatMsg;
01208
01209 static Dict *incoming_concat_msgs;
01210 static Mutex *concat_lock;
01211
01212 static void destroy_concatMsg(void *x)
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 }
01228
01229 static void init_concat_handler(void)
01230 {
01231 if (incoming_concat_msgs != NULL)
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 }
01238
01239 static void shutdown_concat_handler(void)
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 }
01250
01251 static void clear_old_concat_parts(void)
01252 {
01253 List *keys;
01254 Octstr *key;
01255
01256
01257 if (incoming_concat_msgs == NULL)
01258 return;
01259
01260 debug("bb.sms.splits", 0, "clear_old_concat_parts called");
01261
01262
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
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) {
01308 int i;
01309 if (x->total_parts != x1->total_parts) {
01310
01311
01312
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 }
01335
01336
01337
01338
01339
01340
01341 static int check_concatenation(Msg **pmsg, Octstr *smscid)
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
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)
01359 return concat_none;
01360
01361
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));
01390
01391 dict_put(incoming_concat_msgs, key, cmsg);
01392 }
01393 octstr_destroy(key);
01394
01395 if (totalparts != cmsg->total_parts) {
01396
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
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
01418 cmsg->trecv = time(NULL);
01419 }
01420
01421 if (cmsg->num_parts < cmsg->total_parts) {
01422 *pmsg = msg = NULL;
01423 mutex_unlock(concat_lock);
01424 return concat_pending;
01425 }
01426
01427
01428 msg = msg_duplicate(cmsg->parts[0]);
01429 uuid_generate(msg->sms.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
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;
01445
01446
01447
01448 dict_put(incoming_concat_msgs, cmsg->key, NULL);
01449 mutex_unlock(concat_lock);
01450
01451
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)
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 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.