wtp_init.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:14k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wtp_init.c - WTP initiator implementation
  3.  *
  4.  * By Aarno Syv鋘en for Wapit Ltd
  5.  */
  6. #include "gwlib/gwlib.h"
  7. #include "wtp_init.h"
  8. #include "wtp_pack.h"
  9. #include "wap.h"
  10. /*****************************************************************************
  11.  * Internal data structures.
  12.  *
  13.  * List of initiator WTP machines
  14.  */
  15. static List *init_machines = NULL;
  16. /*
  17.  * Counter for initiator WTP machine id numbers, to make sure they are unique.
  18.  */
  19. static Counter *init_machine_id_counter = NULL;
  20. /*
  21.  * When we restart an iniator, we must set tidnew flag to avoid excessive tid
  22.  * validations (WTP 8.8.3.2). Only an iniator uses this flag.
  23.  */
  24. static int tidnew = 1;
  25. /*
  26.  * Queue of events to be handled by WTP initiator.
  27.  */
  28. static List *queue = NULL;
  29. /*
  30.  * Give the status of the wtp initiator:
  31.  *
  32.  * limbo
  33.  * not running at all
  34.  * running
  35.  * operating normally
  36.  * terminating
  37.  * waiting for operations to terminate, returning to limbo
  38.  */
  39. static enum { limbo, running, terminating } initiator_run_status = limbo;
  40. static wap_dispatch_func_t *dispatch_to_wdp;
  41. static wap_dispatch_func_t *dispatch_to_wsp;
  42. /***************************************************************************
  43.  *
  44.  * Prototypes for internal functions:
  45.  */
  46. static void main_thread(void *arg);
  47.  
  48. /*
  49.  * Create and destroy an uniniatilised wtp initiator state machine
  50.  */
  51. static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short
  52.                                            tid, int tidnew);
  53. static void init_machine_destroy(void *sm);
  54. static void handle_init_event(WTPInitMachine *machine, WAPEvent *event);
  55. /*
  56.  * Checks whether wtp initiator machines data structure includes a specific 
  57.  * machine.
  58.  * The machine in question is identified with with source and destination
  59.  * address and port and tid. 
  60.  */
  61. static WTPInitMachine *init_machine_find_or_create(WAPEvent *event);
  62. /*
  63.  * Creates TR-Abort.ind event.
  64.  */
  65. static WAPEvent *create_tr_abort_ind(WTPInitMachine *sm, long abort_reason);
  66. /*
  67.  * Creates TR-Invoke.cnf event 
  68.  */
  69. static WAPEvent *create_tr_invoke_cnf(WTPInitMachine *machine);
  70. static int tid_wrapped(unsigned short tid);
  71. /*
  72.  * Create a datagram with an Abort PDU and send it to the WDP layer.
  73.  */
  74. static void send_abort(WTPInitMachine *machine, long type, long reason);
  75. /*
  76.  * Create a datagram with an Ack PDU and send it to the WDP layer.
  77.  */
  78. static void send_ack(WTPInitMachine *machine, long ack_type, int rid_flag);
  79. /*
  80.  * We use RcvTID consistently as a internal tid representation. So newly 
  81.  * created tids are converted. SendTID = RcvTID ^ 0x8000 (WTP 10.4.3) and for 
  82.  * an initiator, GenTID = SendTID (WTP 10.5). 
  83.  */
  84. static unsigned short rcv_tid(unsigned short tid);
  85. static void start_initiator_timer_R(WTPInitMachine *machine); 
  86. static void stop_initiator_timer(Timer *timer);
  87. /**************************************************************************
  88.  *
  89.  * EXTERNAL FUNCTIONS
  90.  */
  91. void wtp_initiator_init(wap_dispatch_func_t *datagram_dispatch,
  92. wap_dispatch_func_t *session_dispatch) 
  93. {
  94.     init_machines = list_create();
  95.     init_machine_id_counter = counter_create();
  96.      
  97.     queue = list_create();
  98.     list_add_producer(queue);
  99.     dispatch_to_wdp = datagram_dispatch;
  100.     dispatch_to_wsp = session_dispatch;
  101.     timers_init();
  102.     gw_assert(initiator_run_status == limbo);
  103.     initiator_run_status = running;
  104.     gwthread_create(main_thread, NULL);
  105. }
  106. void wtp_initiator_shutdown(void) 
  107. {
  108.     gw_assert(initiator_run_status == running);
  109.     initiator_run_status = terminating;
  110.     list_remove_producer(queue);
  111.     gwthread_join_every(main_thread);
  112.     debug("wap.wtp", 0, "wtp_initiator_shutdown: %ld init_machines left",
  113.         list_len(init_machines));
  114.     list_destroy(init_machines, init_machine_destroy);
  115.     list_destroy(queue, wap_event_destroy_item);
  116.     counter_destroy(init_machine_id_counter);
  117.     timers_shutdown();
  118. }
  119. void wtp_initiator_dispatch_event(WAPEvent *event) 
  120. {
  121.     list_produce(queue, event);
  122. }
  123. /**************************************************************************
  124.  *
  125.  * INTERNAL FUNCTIONS:
  126.  */
  127. static void main_thread(void *arg) 
  128. {
  129.     WTPInitMachine *sm;
  130.     WAPEvent *e;
  131.     while (initiator_run_status == running && 
  132.           (e = list_consume(queue)) != NULL) {
  133.         sm = init_machine_find_or_create(e);
  134. if (sm == NULL)
  135.     wap_event_destroy(e);
  136. else
  137.     handle_init_event(sm, e);
  138.     }
  139. }
  140. static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short
  141.                                            tid, int tidnew)
  142. {
  143.      WTPInitMachine *init_machine;
  144.      init_machine = gw_malloc(sizeof(WTPInitMachine)); 
  145.         
  146.      #define ENUM(name) init_machine->name = INITIATOR_NULL_STATE;
  147.      #define INTEGER(name) init_machine->name = 0; 
  148.      #define EVENT(name) init_machine->name = NULL;
  149.      #define TIMER(name) init_machine->name = gwtimer_create(queue); 
  150.      #define ADDRTUPLE(name) init_machine->name = NULL; 
  151.      #define MACHINE(field) field
  152.      #include "wtp_init_machine.def"
  153.      list_append(init_machines, init_machine);
  154.      init_machine->mid = counter_increase(init_machine_id_counter);
  155.      init_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);
  156.      init_machine->tid = tid;
  157.      init_machine->tidnew = tidnew;
  158.      debug("wap.wtp", 0, "WTP: Created WTPInitMachine %p (%ld)", 
  159.    (void *) init_machine, init_machine->mid);
  160.      return init_machine;
  161. }
  162. /*
  163.  * Destroys a WTPInitMachine. Assumes it is safe to do so. Assumes it has 
  164.  * already been deleted from the machines list.
  165.  */
  166. static void init_machine_destroy(void *p)
  167. {
  168.      WTPInitMachine *init_machine;
  169.      init_machine = p;
  170.      debug("wap.wtp", 0, "WTP: Destroying WTPInitMachine %p (%ld)", 
  171.     (void *) init_machine, init_machine->mid);
  172.      list_delete_equal(init_machines, init_machine);
  173.         
  174.      #define ENUM(name) init_machine->name = INITIATOR_NULL_STATE;
  175.      #define INTEGER(name) init_machine->name = 0; 
  176.      #define EVENT(name) wap_event_destroy(init_machine->name); 
  177.      #define TIMER(name) gwtimer_destroy(init_machine->name); 
  178.      #define ADDRTUPLE(name) wap_addr_tuple_destroy(init_machine->name); 
  179.      #define MACHINE(field) field
  180.      #include "wtp_init_machine.def"
  181.      gw_free(init_machine);
  182. }
  183. /*
  184.  * Give the name of an initiator state in a readable form. 
  185.  */
  186. static unsigned char *name_init_state(int s)
  187. {
  188.        switch (s){
  189.        #define INIT_STATE_NAME(state) case state: return #state;
  190.        #define ROW(state, event, condition, action, new_state)
  191.        #include "wtp_init_states.def"
  192.        default:
  193.            return "unknown state";
  194.        }
  195. }
  196. /*
  197.  * Feed an event to a WTP initiator state machine. Handle all errors by do not
  198.  * report them to the caller. WSP indication or conformation is handled by an
  199.  * included state table. Note: Do not put {}s of the else block inside the 
  200.  * macro definition . 
  201.  */
  202. static void handle_init_event(WTPInitMachine *init_machine, WAPEvent *event)
  203. {
  204.      WAPEvent *wsp_event = NULL;
  205.      debug("wap.wtp", 0, "WTP_INIT: initiator machine %ld, state %s,"
  206.            " event %s.", 
  207.    init_machine->mid, 
  208.    name_init_state(init_machine->state), 
  209.    wap_event_name(event->type));
  210.        
  211.      #define INIT_STATE_NAME(state)
  212.      #define ROW(init_state, event_type, condition, action, next_state) 
  213.  if (init_machine->state == init_state && 
  214.      event->type == event_type && 
  215.      (condition)) { 
  216.      action 
  217.      init_machine->state = next_state; 
  218.      debug("wap.wtp", 0, "WTP_INIT %ld: New state %s", 
  219.                    init_machine->mid, #next_state); 
  220.  } else 
  221.       #include "wtp_init_states.def"
  222.  {
  223.      error(1, "WTP_INIT: handle_init_event: unhandled event!");
  224.      debug("wap.wtp.init", 0, "WTP_INIT: handle_init_event:"
  225.                    "Unhandled event was:");
  226.      wap_event_dump(event);
  227.              wap_event_destroy(event);
  228.              return;
  229.  }
  230.       if (event != NULL) {
  231.   wap_event_destroy(event);  
  232.       }
  233.       if (init_machine->state == INITIATOR_NULL_STATE)
  234.         init_machine_destroy(init_machine);      
  235. }
  236. static int is_wanted_init_machine(void *a, void *b) 
  237. {
  238.     struct machine_pattern *pat;
  239.     WTPInitMachine *m;
  240.     m = a;
  241.     pat = b;
  242.     if (m->mid == pat->mid)
  243. return 1;
  244.     if (pat->mid != -1)
  245. return 0;
  246.     return m->tid == pat->tid && 
  247.    wap_addr_tuple_same(m->addr_tuple, pat->tuple);
  248. }
  249. static WTPInitMachine *init_machine_find(WAPAddrTuple *tuple, long tid, 
  250.                                          long mid) 
  251. {
  252.     struct machine_pattern pat;
  253.     WTPInitMachine *m;
  254.     pat.tuple = tuple;
  255.     pat.tid = tid;
  256.     pat.mid = mid;
  257.     m = list_search(init_machines, &pat, is_wanted_init_machine);
  258.     return m;
  259. }
  260. /*
  261.  * Checks whether wtp initiator machines data structure includes a specific 
  262.  * machine. The machine in question is identified with with source and 
  263.  * destination address and port and tid.  First test incoming events 
  264.  * (WTP 10.2) (Exception are tests nro 4 and 5: if we have a memory error, 
  265.  * we panic (nro 4); nro 5 is already checked). If we have an ack with tid 
  266.  * verification flag set and no corresponding transaction, we abort.(case nro 
  267.  * 2). If the event was a normal ack or an abort, it is ignored (error nro 3).
  268.  * In the case of TR-Invoke.req a new machine is created, in the case of 
  269.  * TR-Abort.req we have a serious error. We must create a new tid for a new
  270.  * transaction here, because machines are identified by an address tuple and a
  271.  * tid. This tid is GenTID (WTP 10.4.2), which is used only by the wtp iniator 
  272.  * thread.
  273.  * Note that as internal tid representation, module uses RcvTID (as required
  274.  * by module wtp_pack). So we we turn the first bit of the tid stored by the
  275.  * init machine.
  276.  */
  277. static WTPInitMachine *init_machine_find_or_create(WAPEvent *event)
  278. {
  279.     WTPInitMachine *machine = NULL;
  280.     long mid;
  281.     static long tid = -1; 
  282.     WAPAddrTuple *tuple;
  283.     mid = -1;
  284.     tuple = NULL;
  285.     switch (event->type) {
  286.     case RcvAck:
  287.         tid = event->u.RcvAck.tid;
  288.         tuple = event->u.RcvAck.addr_tuple;
  289.     break;
  290.     case RcvAbort:
  291.         tid = event->u.RcvAbort.tid;
  292.         tuple = event->u.RcvAbort.addr_tuple;
  293.     break;
  294.     case RcvErrorPDU:
  295.         mid = event->u.RcvErrorPDU.tid;
  296.         tid = event->u.RcvErrorPDU.tid;
  297.         tuple = event->u.RcvErrorPDU.addr_tuple;
  298.     break;
  299. /*
  300.  * When we are receiving an invoke requirement, we must create a new trans-
  301.  * action and generate a new tid. This can be wrapped, and should have its 
  302.  * first bit turned.
  303.  */
  304.     case TR_Invoke_Req:
  305. ++tid;
  306.         if (tid_wrapped(tid)) {
  307.     tidnew = 1;
  308.             tid = 0;
  309.         }
  310.                    
  311. tid = rcv_tid(tid);
  312.         tuple = event->u.TR_Invoke_Req.addr_tuple;
  313.         mid = event->u.TR_Invoke_Req.handle;
  314.     break;
  315.     case TR_Abort_Req:
  316.         tid = event->u.TR_Abort_Req.handle;
  317.     break;
  318.     case TimerTO_R:
  319.         mid = event->u.TimerTO_A.handle;
  320.     break;
  321.     default:
  322. error(0, "WTP_INIT: machine_find_or_create: unhandled event");
  323.         wap_event_dump(event);
  324.         return NULL;
  325.     }
  326.     gw_assert(tuple != NULL || mid != -1);
  327.     machine = init_machine_find(tuple, tid, mid);
  328.     if (machine == NULL){
  329. switch (event->type){
  330. case RcvAck:   
  331.    
  332. /* 
  333.  * Case nro 2 If we do not have a tid asked for, we send a negative answer, 
  334.  * i.e. an abort with reason INVALIDTID. 
  335.  */
  336.      if (event->u.RcvAck.tid_ok) {
  337.  dispatch_to_wdp(wtp_pack_abort(PROVIDER, INVALIDTID,
  338.                                                 tid, tuple));
  339.              }
  340. /* Case nro 3, normal ack */
  341.              else
  342.                  info(0, "WTP_INIT: machine_find_or_create: ack "
  343.                      "received, yet having no machine");
  344. break;
  345. /* Case nro 3, abort */
  346.         case RcvAbort:
  347.             info(0, "WTP_INIT: machine_find_or_create: abort "
  348.                  "received, yet having no machine");
  349. break;
  350. case TR_Invoke_Req:
  351.     machine = init_machine_create(tuple, tid, tidnew);
  352.             machine->mid = event->u.TR_Invoke_Req.handle;
  353. break;
  354. case TR_Abort_Req:
  355.             error(0, "WTP_INIT: machine_find_or_create: WSP "
  356.                   "primitive to a wrong WTP machine");
  357. break;
  358. case TimerTO_R:
  359.     error(0, "WTP_INIT: machine_find_or_create: timer "
  360.                        "event without a corresponding machine");
  361.         break;
  362.        
  363.         default:
  364.             error(0, "WTP_INIT: machine_find_or_create: unhandled"
  365.                   "event");
  366.             wap_event_dump(event);
  367.         break; 
  368.         }
  369.    } 
  370.    return machine;
  371. }
  372. /*
  373.  * Creates TR-Invoke.cnf event
  374.  */
  375. static WAPEvent *create_tr_invoke_cnf(WTPInitMachine *init_machine)
  376. {
  377.     WAPEvent *event;
  378.     gw_assert(init_machine != NULL);
  379.     event = wap_event_create(TR_Invoke_Cnf);
  380.     event->u.TR_Invoke_Cnf.handle = init_machine->mid;
  381.     event->u.TR_Invoke_Cnf.addr_tuple = 
  382.         wap_addr_tuple_duplicate(init_machine->addr_tuple);
  383.     return event;
  384. }
  385. /*
  386.  * Creates TR-Abort.ind event from an initiator state machine. In addtion, set
  387.  * the ir_flag on.
  388.  */
  389. static WAPEvent *create_tr_abort_ind(WTPInitMachine *sm, long abort_reason) 
  390. {
  391.     WAPEvent *event;
  392.     event = wap_event_create(TR_Abort_Ind);
  393.     event->u.TR_Abort_Ind.abort_code = abort_reason;
  394.     event->u.TR_Abort_Ind.addr_tuple = 
  395. wap_addr_tuple_duplicate(sm->addr_tuple);
  396.     event->u.TR_Abort_Ind.handle = sm->mid;
  397.     event->u.TR_Abort_Ind.ir_flag = INITIATOR_INDICATION;
  398.     return event;
  399. }
  400. static int tid_wrapped(unsigned short tid)
  401. {
  402.     return tid > (1 << 15);
  403. }
  404. static unsigned short rcv_tid(unsigned short tid)
  405. {
  406.     return tid ^ 0x8000;
  407. }
  408. /*
  409.  * Start retry interval timer (strictly speaking, timer iniatilised with retry
  410.  * interval).
  411.  */
  412. static void start_initiator_timer_R(WTPInitMachine *machine) 
  413. {
  414.     WAPEvent *timer_event;
  415.     int seconds;
  416.     timer_event = wap_event_create(TimerTO_R);
  417.     timer_event->u.TimerTO_R.handle = machine->mid;
  418.     if (machine->u_ack)
  419.         seconds = S_R_WITH_USER_ACK;
  420.     else
  421.         seconds = S_R_WITHOUT_USER_ACK;
  422.     gwtimer_start(machine->timer, seconds, timer_event);
  423. }
  424. static void stop_initiator_timer(Timer *timer)
  425. {
  426.     debug("wap.wtp_init", 0, "stopping timer");
  427.     gw_assert(timer);
  428.     gwtimer_stop(timer);
  429. }
  430. static void send_abort(WTPInitMachine *machine, long type, long reason)
  431. {
  432.     WAPEvent *e;
  433.     e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple);
  434.     dispatch_to_wdp(e);
  435. }
  436. static void send_ack(WTPInitMachine *machine, long ack_type, int rid_flag)
  437. {
  438.     WAPEvent *e;
  439.     e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple);
  440.     dispatch_to_wdp(e);
  441. }