📄 wtp_resp.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. */ /* * 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 + -