📄 bb_smscconn.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * SMSC Connection interface for Bearerbox. * * Includes callback functions called by SMSCConn implementations * * Handles all startup/shutdown adminstrative work in bearerbox, plus * routing, writing actual access logs, handling failed messages etc. * * Kalle Marjola 2000 for project Kannel */#include <errno.h>#include <stdlib.h>#include <stdio.h>#include <time.h>#include <string.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <fcntl.h>#include "gwlib/gwlib.h"#include "msg.h"#include "sms.h"#include "bearerbox.h"#include "numhash.h"#include "smscconn.h"#include "dlr.h"#include "bb_smscconn_cb.h" /* callback functions for connections */#include "smscconn_p.h" /* to access counters *//* passed from bearerbox core */extern volatile sig_atomic_t bb_status;extern List *incoming_sms;extern List *outgoing_sms;extern Counter *incoming_sms_counter;extern Counter *outgoing_sms_counter;extern List *flow_threads;extern List *suspended;extern List *isolated;/* our own thingies */static volatile sig_atomic_t smsc_running;static List *smsc_list;static RWLock smsc_list_lock;static List *smsc_groups;static Octstr *unified_prefix;static Numhash *black_list;static Numhash *white_list;static regex_t *white_list_regex;static regex_t *black_list_regex;static long router_thread = -1;/* * Counter for catenated SMS messages. The counter that can be put into * the catenated SMS message's UDH headers is actually the lowest 8 bits. */Counter *split_msg_counter;/* * forward declaration */static long route_incoming_to_smsc(SMSCConn *conn, Msg *msg);/*--------------------------------------------------------------------------- * CALLBACK FUNCTIONS * * called by SMSCConn implementations when appropriate */void bb_smscconn_ready(SMSCConn *conn){ list_add_producer(flow_threads); list_add_producer(incoming_sms);}void bb_smscconn_connected(SMSCConn *conn){ if (router_thread >= 0) gwthread_wakeup(router_thread);}void bb_smscconn_killed(void){ /* NOTE: after status has been set to SMSCCONN_DEAD, bearerbox * is free to release/delete 'conn' */ list_remove_producer(incoming_sms); list_remove_producer(flow_threads);}static void handle_split(SMSCConn *conn, Msg *msg, long reason){ struct split_parts *split = msg->sms.split_parts; /* if temporarely failed, try again immediately */ if (reason == SMSCCONN_FAILED_TEMPORARILY && smscconn_send(conn, msg) == 0) return; /* * if the reason is not a success and status is still success * then set status of a split to the reason. * Note: reason 'malformed','discarded' or 'rejected' has higher priority! */ switch(reason) { case SMSCCONN_FAILED_DISCARDED: case SMSCCONN_FAILED_REJECTED: case SMSCCONN_FAILED_MALFORMED: debug("bb.sms.splits", 0, "Set split msg status to %ld", reason); split->status = reason; break; case SMSCCONN_SUCCESS: break; /* nothing todo */ default: if (split->status == SMSCCONN_SUCCESS) { debug("bb.sms.splits", 0, "Set split msg status to %ld", reason); split->status = reason; } break; } /* * now destroy this message, because we don't need it anymore. * we will split it again in smscconn_send(...). */ msg_destroy(msg); if (counter_decrease(split->parts_left) <= 1) { /* all splited parts were processed */ counter_destroy(split->parts_left); msg = split->orig; msg->sms.split_parts = NULL; if (split->status == SMSCCONN_SUCCESS) bb_smscconn_sent(conn, msg, NULL); else { debug("bb.sms.splits", 0, "Parts of concatenated message failed."); bb_smscconn_send_failed(conn, msg, split->status, NULL); } gw_free(split); }}void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply){ if (sms->sms.split_parts != NULL) { handle_split(conn, sms, SMSCCONN_SUCCESS); return; } counter_increase(outgoing_sms_counter); if (conn) counter_increase(conn->sent); /* write ACK to store file */ store_save_ack(sms, ack_success); bb_alog_sms(conn, sms, "Sent SMS"); /* generate relay confirmancy message */ if (DLR_IS_SMSC_SUCCESS(sms->sms.dlr_mask)) { Msg *dlrmsg; if (reply == NULL) reply = octstr_create(""); octstr_insert_data(reply, 0, "ACK/", 4); dlrmsg = create_dlr_from_msg((conn->id?conn->id:conn->name), sms, reply, DLR_SMSC_SUCCESS); if (dlrmsg != NULL) { bb_smscconn_receive(conn, dlrmsg); } } msg_destroy(sms); octstr_destroy(reply);}void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply){ if (sms->sms.split_parts != NULL) { handle_split(conn, sms, reason); return; } switch (reason) { case SMSCCONN_FAILED_SHUTDOWN: case SMSCCONN_FAILED_TEMPORARILY: list_produce(outgoing_sms, sms); break; default: /* write NACK to store file */ store_save_ack(sms, ack_failed); if (conn) counter_increase(conn->failed); if (reason == SMSCCONN_FAILED_DISCARDED) bb_alog_sms(conn, sms, "DISCARDED SMS"); else bb_alog_sms(conn, sms, "FAILED Send SMS"); /* generate relay confirmancy message */ if (DLR_IS_SMSC_FAIL(sms->sms.dlr_mask) || DLR_IS_FAIL(sms->sms.dlr_mask)) { Msg *dlrmsg; if (reply == NULL) reply = octstr_create(""); octstr_insert_data(reply, 0, "NACK/", 5); dlrmsg = create_dlr_from_msg((conn ? (conn->id?conn->id:conn->name) : NULL), sms, reply, DLR_SMSC_FAIL); if (dlrmsg != NULL) { bb_smscconn_receive(conn, dlrmsg); } } msg_destroy(sms); } octstr_destroy(reply);}long bb_smscconn_receive(SMSCConn *conn, Msg *sms){ char *uf; int rc; Msg *copy; /* * First normalize in smsc level and then on global level. * In outbound direction it's vise versa, hence first global then smsc. */ uf = (conn && conn->unified_prefix) ? octstr_get_cstr(conn->unified_prefix) : NULL; normalize_number(uf, &(sms->sms.sender)); uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL; normalize_number(uf, &(sms->sms.sender)); if (white_list && numhash_find_number(white_list, sms->sms.sender) < 1) { info(0, "Number <%s> is not in white-list, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED - not white-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (white_list_regex && (gw_regex_matches(white_list_regex, sms->sms.sender) == NO_MATCH)) { info(0, "Number <%s> is not in white-list, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED - not white-regex-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (black_list && numhash_find_number(black_list, sms->sms.sender) == 1) { info(0, "Number <%s> is in black-list, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED - black-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (black_list_regex && (gw_regex_matches(black_list_regex, sms->sms.sender) == NO_MATCH)) { info(0, "Number <%s> is not in black-list, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED - black-regex-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (sms->sms.sms_type != report_mo) sms->sms.sms_type = mo; /* write to store (if enabled) */ if (store_save(sms) == -1) return SMSCCONN_FAILED_TEMPORARILY; copy = msg_duplicate(sms); /* * Try to reroute internally to an smsc-id without leaving * actually bearerbox scope. * Scope: internal routing (to smsc-ids) */ if ((rc = route_incoming_to_smsc(conn, copy)) == -1) { /* * Now try to route the message to a specific smsbox * connection based on the existing msg->sms.boxc_id or * the registered receiver numbers for specific smsbox'es. * Scope: external routing (to smsbox connections) */ if (route_incoming_to_boxc(copy) == -1) { warning(0, "incoming messages queue too long, dropping a message."); if (sms->sms.sms_type == report_mo) bb_alog_sms(conn, sms, "DROPPED Received DLR"); else bb_alog_sms(conn, sms, "DROPPED Received SMS"); /* put nack into store-file */ store_save_ack(sms, ack_failed); msg_destroy(copy); msg_destroy(sms); gwthread_sleep(0.1); /* letting the queue go down */ return SMSCCONN_FAILED_QFULL; } } if (sms->sms.sms_type != report_mo) bb_alog_sms(conn, sms, "Receive SMS"); else bb_alog_sms(conn, sms, "DLR SMS"); counter_increase(incoming_sms_counter); if (conn != NULL) counter_increase(conn->received); msg_destroy(sms); return 0;}/*--------------------------------------------------------------------- * Other functions *//* function to route outgoing SMS'es from delay-list * use some nice magics to route them to proper SMSC */static void sms_router(void *arg){ Msg *msg, *newmsg, *startmsg; int ret; list_add_producer(flow_threads); gwthread_wakeup(MAIN_THREAD_ID); newmsg = startmsg = NULL; ret = 0; while(bb_status != BB_DEAD) { if (newmsg == startmsg) { if (ret != 1) { debug("bb.sms", 0, "sms_router: time to sleep"); gwthread_sleep(600.0); /* hopefully someone wakes us up */ debug("bb.sms", 0, "sms_router: list_len = %ld", list_len(outgoing_sms)); } startmsg = list_consume(outgoing_sms); newmsg = NULL; msg = startmsg; } else { newmsg = list_consume(outgoing_sms); msg = newmsg; } /* debug("bb.sms", 0, "sms_router: handling message (%p vs %p)", * newmsg, startmsg); */ if (msg == NULL) break; ret = smsc2_rout(msg); if (ret == -1) { warning(0, "No SMSCes to receive message, discarding it!"); bb_smscconn_send_failed(NULL, msg, SMSCCONN_FAILED_DISCARDED, octstr_create("DISCARDED")); } else if (ret == 1) { newmsg = startmsg = NULL; } } /* router has died, make sure that rest die, too */ smsc_running = 0; list_remove_producer(flow_threads);}/*------------------------------------------------------------- * public functions * */int smsc2_start(Cfg *cfg){ CfgGroup *grp; SMSCConn *conn; Octstr *os; int i; if (smsc_running) return -1; /* create split sms counter */ split_msg_counter = counter_create(); smsc_list = list_create(); gw_rwlock_init_static(&smsc_list_lock); grp = cfg_get_single_group(cfg, octstr_imm("core")); unified_prefix = cfg_get(grp, octstr_imm("unified-prefix")); white_list = black_list = NULL; os = cfg_get(grp, octstr_imm("white-list")); if (os != NULL) { white_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } if ((os = cfg_get(grp, octstr_imm("white-list-regex"))) != NULL) { if ((white_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } os = cfg_get(grp, octstr_imm("black-list")); if (os != NULL) { black_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } if ((os = cfg_get(grp, octstr_imm("black-list-regex"))) != NULL) { if ((black_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } smsc_groups = cfg_get_multi_group(cfg, octstr_imm("smsc")); /* while(groups && (grp = list_extract_first(groups)) != NULL) { conn = smscconn_create(grp, 1); if (conn == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -