⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wtp_resp.c

📁 The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword b
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ====================================================================  * 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.   */  /* * wtp_resp.c - WTP responder implementation * * Aarno Syv鋘en * Lars Wirzenius */#include "gwlib/gwlib.h"#include "wtp_resp.h"#include "wtp_pack.h"#include "wtp_tid.h"#include "wtp.h"#include "timers.h"#include "wap.h"/*********************************************************************** * Internal data structures. * * List of responder WTP machines. */static List *resp_machines = NULL;/* * Counter for responder WTP machine id numbers, to make sure they are unique. */static Counter *resp_machine_id_counter = NULL;/* * Give the status of wtp responder: * *	limbo *		not running at all *	running *		operating normally *	terminating *		waiting for operations to terminate, returning to limbo */static enum { limbo, running, terminating } resp_run_status = limbo;wap_dispatch_func_t *dispatch_to_wdp;wap_dispatch_func_t *dispatch_to_wsp;wap_dispatch_func_t *dispatch_to_push;/* * Queue of events to be handled by WTP responder. */static List *resp_queue = NULL;/* * Timer 'tick'. All wtp responder timer values are multiplies of this one */static long resp_timer_freq = -1;/***************************************************************************** * * Prototypes of internal functions: * * Create and destroy an uniniatilized wtp responder state machine. */static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid,                                            long tcl);static void resp_machine_destroy(void *sm);/* * Checks whether wtp responser machines data structure includes a specific  * machine. * The machine in question is identified with with source and destination * address and port and tid. If the machine does not exist and the event is  * RcvInvoke, a new machine is created and added in the machines data  * structure.  * First test incoming events (WTP 10.2) (Exception is tests nro 4 and 5: if  * we have a memory error, we panic. Nro 4 is already checked)  If event was  * validated and If the event was RcvAck or RcvAbort, the event is ignored.  * If the event is RcvErrorPDU, new machine is created. */static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event);/* * Feed an event to a WTP responder state machine. Handle all errors by  * itself, do not report them to the caller. WSP indication or confirmation  * is handled by an included state table. */static void resp_event_handle(WTPRespMachine *machine, WAPEvent *event);/* * Print a wtp responder machine state as a string. */static unsigned char *name_resp_state(int name);/* * Find the wtp responder machine from the global list of wtp responder  * structures that corresponds to the five-tuple of source and destination  * addresses and ports and the transaction identifier. Return a pointer to  * the machine, or NULL if not found. */static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid,                                          long mid);static void main_thread(void *);/* * Start acknowledgement interval timer */static void start_timer_A(WTPRespMachine *machine);/* * Start retry interval timer */static void start_timer_R(WTPRespMachine *machine);/* * Start timeout interval timer. */static void start_timer_W(WTPRespMachine *machine);static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data);static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason);static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm);static int erroneous_field_in(WAPEvent *event);static void handle_wrong_version(WAPEvent *event);/* * SAR related functions. */static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn);static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn);/* static int is_wanted_sar_data (void *a, void *b); */static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event);static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event);static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event);static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event);static void sar_info_destroy(void *sar_info);static void sardata_destroy(void *sardata);/* * Create a datagram with an Abort PDU and send it to the WDP layer. */static void send_abort(WTPRespMachine *machine, long type, long reason);/* * Create a datagram with an Ack PDU and send it to the WDP layer. */static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag);/****************************************************************************** * * EXTERNAL FUNCTIONS: * */void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch,                   wap_dispatch_func_t *session_dispatch,                   wap_dispatch_func_t *push_dispatch,                    long timer_freq) {    resp_machines = list_create();    resp_machine_id_counter = counter_create();    resp_queue = list_create();    list_add_producer(resp_queue);    dispatch_to_wdp = datagram_dispatch;    dispatch_to_wsp = session_dispatch;    dispatch_to_push = push_dispatch;    timers_init();    resp_timer_freq = timer_freq;    wtp_tid_cache_init();    gw_assert(resp_run_status == limbo);    resp_run_status = running;    gwthread_create(main_thread, NULL);}void wtp_resp_shutdown(void) {    gw_assert(resp_run_status == running);    resp_run_status = terminating;    list_remove_producer(resp_queue);    gwthread_join_every(main_thread);    debug("wap.wtp", 0, "wtp_resp_shutdown: %ld resp_machines left",     	  list_len(resp_machines));    list_destroy(resp_machines, resp_machine_destroy);    list_destroy(resp_queue, wap_event_destroy_item);    counter_destroy(resp_machine_id_counter);    wtp_tid_cache_shutdown();    timers_shutdown();}void wtp_resp_dispatch_event(WAPEvent *event) {    list_produce(resp_queue, event);}/***************************************************************************** * * INTERNAL FUNCTIONS: * */static void main_thread(void *arg) {    WTPRespMachine *sm;    WAPEvent *e;    while (resp_run_status == running &&            (e = list_consume(resp_queue)) != NULL) {        sm = resp_machine_find_or_create(e);        if (sm == NULL) {            wap_event_destroy(e);        } else {            resp_event_handle(sm, e);        }    }}/* * Give the name of a responder state in a readable form.  */static unsigned char *name_resp_state(int s){       switch (s) {       #define STATE_NAME(state) case state: return #state;       #define ROW(state, event, condition, action, new_state)       #include "wtp_resp_states.def"       default:           return "unknown state";       }}/* * Feed an event to a WTP responder state machine. Handle all errors yourself, * do not report them to the caller. Note: Do not put {}s of the else block  * inside the macro definition.  */static void resp_event_handle(WTPRespMachine *resp_machine, WAPEvent *event){    WAPEvent *wsp_event = NULL;    /*      * We don't feed sar packets into state machine      * until we got the whole message      */    if (process_sar_transaction(resp_machine,&event) == 0) {        debug("wap.wtp", 0, "SAR event received, wait for continue");        /* For removing state machine in case of incomplete sar */        start_timer_W(resp_machine);        if (event != NULL) {            wap_event_destroy(event);          }        return;    }    debug("wap.wtp", 0, "WTP: resp_machine %ld, state %s, event %s.", 	  resp_machine->mid, 	  name_resp_state(resp_machine->state), 	  wap_event_name(event->type));    #define STATE_NAME(state)    #define ROW(wtp_state, event_type, condition, action, next_state) \	 if (resp_machine->state == wtp_state && \	     event->type == event_type && \	     (condition)) { \	     action \	     resp_machine->state = next_state; \	     debug("wap.wtp", 0, "WTP %ld: New state %s", resp_machine->mid,                      #next_state); \	 } else     #include "wtp_resp_states.def"	 {	     error(0, "WTP: handle_event: unhandled event!");	     debug("wap.wtp", 0, "WTP: handle_event: Unhandled event was:");	     wap_event_dump(event);             wap_event_destroy(event);             return;	 }    if (event != NULL) {	wap_event_destroy(event);      }    if (resp_machine->state == LISTEN)     	resp_machine_destroy(resp_machine);}static void handle_wrong_version(WAPEvent *event){           WAPEvent *ab;    if (event->type == RcvInvoke) {        ab = wtp_pack_abort(PROVIDER, WTPVERSIONZERO, event->u.RcvInvoke.tid,                             event->u.RcvInvoke.addr_tuple);        dispatch_to_wdp(ab);    }}/* * Check for features 7 and 9 in WTP 10.2. */static int erroneous_field_in(WAPEvent *event){    return event->type == RcvInvoke && event->u.RcvInvoke.version != 0;}/* * React features 7 and 9 in WTP 10.2, by aborting with an appropiate error  * message. */static void handle_erroneous_field_in(WAPEvent *event){    if (event->type == RcvInvoke) {        if (event->u.RcvInvoke.version != 0) {            debug("wap.wtp_resp", 0, "WTP_RESP: wrong version, aborting"                  "transaction");            handle_wrong_version(event);        }    }}/* * Checks whether wtp machines data structure includes a specific machine. * The machine in question is identified with with source and destination * address and port and tid.  First test incoming events (WTP 10.2) * (Exception is tests nro 4 and 5: if we have a memory error, we panic. Nro 5  * is already checked)  If event was validated and if the machine does not  * exist and the event is RcvInvoke, a new machine is created and added in  * the machines data structure. If the event was RcvAck or RcvAbort, the  * event is ignored (test nro 3). If the event is RcvErrorPDU (test nro 4)  * new machine is created for handling this event. If the event is one of WSP  * primitives, we have an error. */static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event){    WTPRespMachine *resp_machine = NULL;    long tid, mid;    WAPAddrTuple *tuple;    tid = -1;    tuple = NULL;    mid = -1;    switch (event->type) {        case RcvInvoke:            /* check if erroneous fields are given */            if (erroneous_field_in(event)) {                handle_erroneous_field_in(event);                return NULL;            } else {                tid = event->u.RcvInvoke.tid;                tuple = event->u.RcvInvoke.addr_tuple;            }            break;        case RcvSegInvoke:            tid = event->u.RcvSegInvoke.tid;            tuple = event->u.RcvSegInvoke.addr_tuple;            break;        case RcvAck:            tid = event->u.RcvAck.tid;            tuple = event->u.RcvAck.addr_tuple;            break;        case RcvNegativeAck:            tid = event->u.RcvAck.tid;            tuple = event->u.RcvAck.addr_tuple;            break;        case RcvAbort:            tid = event->u.RcvAbort.tid;            tuple = event->u.RcvAbort.addr_tuple;            break;        case RcvErrorPDU:            tid = event->u.RcvErrorPDU.tid;            tuple = event->u.RcvErrorPDU.addr_tuple;            break;        case TR_Invoke_Res:            mid = event->u.TR_Invoke_Res.handle;            break;        case TR_Result_Req:            mid = event->u.TR_Result_Req.handle;            break;        case TR_Abort_Req:            mid = event->u.TR_Abort_Req.handle;            break;        case TimerTO_A:            mid = event->u.TimerTO_A.handle;            break;        case TimerTO_R:            mid = event->u.TimerTO_R.handle;            break;        case TimerTO_W:            mid = event->u.TimerTO_W.handle;            break;        default:            debug("wap.wtp", 0, "WTP: resp_machine_find_or_create:"                  "unhandled event");             wap_event_dump(event);            return NULL;    }    gw_assert(tuple != NULL || mid != -1);    resp_machine = resp_machine_find(tuple, tid, mid);               if (resp_machine == NULL){        switch (event->type) {        /*         * When PDU with an illegal header is received, its tcl-field is          * irrelevant and possibly meaningless). In this case we must create          * a new machine, if there is any. There is a machine for all events          * handled stateful manner.         */        case RcvErrorPDU:            debug("wap.wtp_resp", 0, "an erronous pdu received");            wap_event_dump(event);            resp_machine = resp_machine_create(tuple, tid,                                                event->u.RcvInvoke.tcl);             break;                   case RcvInvoke:            resp_machine = resp_machine_create(tuple, tid,                                                event->u.RcvInvoke.tcl);            /* if SAR requested */            if (!event->u.RcvInvoke.gtr || !event->u.RcvInvoke.ttr) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -