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

📄 wtp_init.c

📁 mms client
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * wtp_init.c - WTP initiator implementation * * By Aarno Syv鋘en for Wapit Ltd */#include "gwlib/gwlib.h"#include "wtp_init.h"#include "wtp_pack.h"#include "wap.h"/***************************************************************************** * Internal data structures. * * List of initiator WTP machines */static List *init_machines = NULL;/* * The tid to use for the next transaction. */static unsigned short gentid = -1;/* * When we restart an iniator, we must set tidnew flag to avoid excessive tid * validations (WTP 8.8.3.2). Only an iniator uses this flag. */static int tidnew = 1;/* * Queue of events to be handled by WTP initiator. */static List *queue = NULL;/* * Give the status of the wtp initiator: * *	limbo *		not running at all *	running *		operating normally *	terminating *		waiting for operations to terminate, returning to limbo */static enum {    limbo, running, terminating} initiator_run_status = limbo;static wap_dispatch_func_t *dispatch_to_wdp;static wap_dispatch_func_t *dispatch_to_wsp;/* * This is a timer 'tick'. All timer values multiplies of this value. */static long init_timer_freq = -1;/*************************************************************************** * * Prototypes for internal functions: */static void main_thread(void *arg);/* * Create and destroy an uniniatilised wtp initiator state machine */static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short tid, int tidnew, long mid, long tcl);static void init_machine_destroy(void *sm);static void handle_init_event(WTPInitMachine *machine, WAPEvent *event);/* * Checks whether wtp initiator machines data structure includes a specific  * machine. * The machine in question is identified with with source and destination * address and port and tid.  */static WTPInitMachine *init_machine_find_or_create(WAPEvent *event);/* * Creates TR-Abort.ind event. */static WAPEvent *create_tr_abort_ind(WTPInitMachine *sm, long abort_reason);/* * Creates TR-Invoke.cnf event  */static WAPEvent *create_tr_invoke_cnf(WTPInitMachine *machine);static int tid_wrapped(unsigned short tid);/* * Create a datagram with an Abort PDU and send it to the WDP layer. */static void send_abort(WTPInitMachine *machine, long type, long reason);/* * Create a datagram with an Ack PDU and send it to the WDP layer. */static void send_ack(WTPInitMachine *machine, long ack_type, int rid_flag);/* * We use RcvTID consistently as a internal tid representation. So newly  * created tids are converted. SendTID = RcvTID ^ 0x8000 (WTP 10.4.3) and for  * an initiator, GenTID = SendTID (WTP 10.5).  */static unsigned short rcv_tid(unsigned short tid);static void start_initiator_timer_R(WTPInitMachine *machine); static void start_initiator_timer_W(WTPInitMachine *machine);static void start_initiator_timer_A(WTPInitMachine *machine);static void stop_initiator_timer(Timer *timer);/* * SAR related functions. */static WAPEvent *assembly_sar_event (WTPInitMachine *machine, int last_psn);static int add_sar_transaction (WTPInitMachine *machine, Octstr *data, int psn);/* static int is_wanted_sar_data (void *a, void *b); */static int process_sar_transaction(WTPInitMachine *machine, WAPEvent **event);static void begin_sar_invoke(WTPInitMachine *init_machine, WAPEvent *event);static void continue_sar_invoke(WTPInitMachine *machine, WAPEvent *event);static void resend_sar_invoke(WTPInitMachine *init_machine, WAPEvent *event);static void sar_info_destroy(void *sar_info);static void sardata_destroy(void *sardata);/************************************************************************** * * EXTERNAL FUNCTIONS */void wtp_initiator_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *session_dispatch, long timer_freq) {    init_machines = list_create();    queue = list_create();    list_add_producer(queue);    dispatch_to_wdp = datagram_dispatch;    dispatch_to_wsp = session_dispatch;    timers_init();    init_timer_freq = timer_freq;    gw_assert(initiator_run_status == limbo);    initiator_run_status = running;    gwthread_create(main_thread, NULL);}void wtp_initiator_shutdown(void) {    gw_assert(initiator_run_status == running);    initiator_run_status = terminating;    list_remove_producer(queue);    gwthread_join_every(main_thread);    debug("wap.wtp", 0, "wtp_initiator_shutdown: %ld init_machines left",          list_len(init_machines));    list_destroy(init_machines, init_machine_destroy);    list_destroy(queue, wap_event_destroy_item);    timers_shutdown();}void wtp_initiator_dispatch_event(WAPEvent *event) {    list_produce(queue, event);}/************************************************************************** * * INTERNAL FUNCTIONS: */static void main_thread(void *arg) {    WTPInitMachine *sm;    WAPEvent *e;    while (initiator_run_status == running &&            (e = list_consume(queue)) != NULL) {        sm = init_machine_find_or_create(e);        if (sm == NULL)            wap_event_destroy(e);        else            handle_init_event(sm, e);    }}static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short tid, int tidnew, long mid, long tcl) {    WTPInitMachine *init_machine;    init_machine = gw_malloc(sizeof(WTPInitMachine)); #define ENUM(name) init_machine->name = INITIATOR_NULL_STATE;#define INTEGER(name) init_machine->name = 0; #define EVENT(name) init_machine->name = NULL;#define TIMER(name) init_machine->name = gwtimer_create(queue); #define ADDRTUPLE(name) init_machine->name = NULL; #define LIST(name) init_machine->name = NULL;#define SARDATA(name) init_machine->name = NULL;#define MACHINE(field) field#include "wtp_init_machine.def"    list_append(init_machines, init_machine);    init_machine->tcl = tcl;    init_machine->mid = mid;    init_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);    init_machine->tid = tid;    init_machine->tidnew = tidnew;    debug("wap.wtp", 0, "WTP: Created WTPInitMachine %p (%ld)",           (void *) init_machine, init_machine->mid);    return init_machine;}/* * Destroys a WTPInitMachine. Assumes it is safe to do so. Assumes it has  * already been deleted from the machines list. */static void init_machine_destroy(void *p) {    WTPInitMachine *init_machine;    init_machine = p;    debug("wap.wtp", 0, "WTP: Destroying WTPInitMachine %p (%ld)",           (void *) init_machine, init_machine->mid);    list_delete_equal(init_machines, init_machine);#define ENUM(name) init_machine->name = INITIATOR_NULL_STATE;#define INTEGER(name) init_machine->name = 0; #define EVENT(name) wap_event_destroy(init_machine->name); #define TIMER(name) gwtimer_destroy(init_machine->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(init_machine->name); #define LIST(name) list_destroy(init_machine->name,sar_info_destroy);#define SARDATA(name) sardata_destroy(init_machine->name);#define MACHINE(field) field#include "wtp_init_machine.def"    gw_free(init_machine);}/* * Give the name of an initiator state in a readable form.  */static unsigned char *name_init_state(int s) {    switch (s) {#define INIT_STATE_NAME(state) case state: return #state;#define ROW(state, event, condition, action, new_state)#include "wtp_init_states.def"        default:            return "unknown state";    }}/* * Feed an event to a WTP initiator state machine. Handle all errors by do not * report them to the caller. WSP indication or conformation is handled by an * included state table. Note: Do not put {}s of the else block inside the  * macro definition .  */static void handle_init_event(WTPInitMachine *init_machine, WAPEvent *event) {    WAPEvent *wsp_event = NULL;    debug("wap.wtp", 0, "WTP_INIT: initiator machine %ld, state %s,"          " event %s.",           init_machine->mid,           name_init_state(init_machine->state),           wap_event_name(event->type));#define INIT_STATE_NAME(state)#define ROW(init_state, event_type, condition, action, next_state) \	 if (init_machine->state == init_state && \	     event->type == event_type && \	     (condition)) { \	     action \	     init_machine->state = next_state; \	     debug("wap.wtp", 0, "WTP_INIT %event->u.RcvAck.tclld: New state %s", \                   init_machine->mid, #next_state); \	 } else #include "wtp_init_states.def"    {        error(1, "WTP_INIT: handle_init_event: unhandled event!");        debug("wap.wtp.init", 0, "WTP_INIT: handle_init_event:"              "Unhandled event was:");        wap_event_dump(event);        wap_event_destroy(event);        return;    }    if (event != NULL) {        wap_event_destroy(event);      }    if (init_machine->state == INITIATOR_NULL_STATE)        init_machine_destroy(init_machine);}static int is_wanted_init_machine(void *a, void *b) {    struct machine_pattern *pat;    WTPInitMachine *m;    m = a;    pat = b;    if (m->mid == pat->mid)        return 1;    if (pat->mid != -1)        return 0;    return m->tid == pat->tid &&     wap_addr_tuple_same(m->addr_tuple, pat->tuple);}static WTPInitMachine *init_machine_find(WAPAddrTuple *tuple, long tid,                                          long mid) {    struct machine_pattern pat;    WTPInitMachine *m;    pat.tuple = tuple;    pat.tid = tid;    pat.mid = mid;    m = list_search(init_machines, &pat, is_wanted_init_machine);    return m;}/* * Checks whether wtp initiator 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 are tests nro 4 and 5: if we have a memory error,  * we panic (nro 4); nro 5 is already checked). If we have an ack with tid  * verification flag set and no corresponding transaction, we abort.(case nro  * 2). If the event was a normal ack or an abort, it is ignored (error nro 3). * In the case of TR-Invoke.req a new machine is created, in the case of  * TR-Abort.req we have a serious error. We must create a new tid for a new * transaction here, because machines are identified by an address tuple and a * tid. This tid is GenTID (WTP 10.4.2), which is used only by the wtp iniator  * thread. * Note that as internal tid representation, module uses RcvTID (as required * by module wtp_pack). So we we turn the first bit of the tid stored by the * init machine. */static WTPInitMachine *init_machine_find_or_create(WAPEvent *event) {    WTPInitMachine *machine = NULL;    long mid;    static long tid = -1;     WAPAddrTuple *tuple;    mid = -1;    tuple = NULL;    switch (event->type) {        case RcvAck:            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:            mid = event->u.RcvErrorPDU.tid;            tid = event->u.RcvErrorPDU.tid;            tuple = event->u.RcvErrorPDU.addr_tuple;            break;        case RcvResult:            tid = event->u.RcvResult.tid;            tuple = event->u.RcvResult.addr_tuple;            break;        case TR_Invoke_Req:            ++gentid;            if (tid_wrapped(gentid)) {                tidnew = 1;                gentid = 0;            }            tid = rcv_tid(gentid);            tuple = event->u.TR_Invoke_Req.addr_tuple;            mid = event->u.TR_Invoke_Req.handle;            break;        case TR_Result_Res:            tid = event->u.TR_Result_Res.handle;            break;        case TR_Abort_Req:            tid = event->u.TR_Abort_Req.handle;            break;        case TimerTO_R:            mid = event->u.TimerTO_R.handle;            break;        case TimerTO_A:            mid = event->u.TimerTO_A.handle;            break;        case TimerTO_W:            mid = event->u.TimerTO_W.handle;            break;        default:            error(0, "WTP_INIT: machine_find_or_create: unhandled event");            wap_event_dump(event);            return NULL;    }    gw_assert(tuple != NULL || mid != -1);    machine = init_machine_find(tuple, tid, mid);    if (machine == NULL) {        switch (event->type) {            case RcvAck:   /*  * Case nro 2 If we do not have a tid asked for, we send a negative answer,  * i.e. an abort with reason INVALIDTID. 

⌨️ 快捷键说明

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