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

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wsp_push_client.c: Client WSP Push implementation, for testing purposes
  3.  *
  4.  * Aarno Syv鋘en for Wapit Ltd
  5.  */
  6. #include "wsp_push_client.h"
  7. #include "wsp.h"
  8. #include "wtp.h"
  9. #include "wsp_pdu.h"
  10. #include "wsp_headers.h"
  11. #include "wap.h"
  12. /**************************************************************************
  13.  * 
  14.  * Internal data structures:
  15.  *
  16.  * List of client WSP push machines.
  17.  */
  18. static List *push_client_machines = NULL;
  19. /*
  20.  * Counter for client push machine id numbers, to make sure that they are 
  21.  * unique.
  22.  */
  23. static Counter *push_client_machine_id_counter = NULL;
  24. /*
  25.  * Give the status of push client:
  26.  *
  27.  * limbo
  28.  * not running at all
  29.  * running
  30.  * operating normally
  31.  * terminating
  32.  * waiting for operations to terminate, returning to limbo
  33.  */
  34. static enum {limbo, running, terminating } push_client_run_status = limbo;
  35. /*
  36.  * Queue of events to be handled by the push client.
  37.  */
  38. static List *push_client_queue = NULL;
  39. wap_dispatch_func_t *dispatch_to_self;
  40. wap_dispatch_func_t *dispatch_to_wtp_resp;
  41. /*****************************************************************************
  42.  *
  43.  * Prototypes of internal functions:
  44.  *
  45.  * Create and destroy an uniniatilised push client state machine.
  46.  */
  47. static WSPPushClientMachine *push_client_machine_create(long cpid);
  48. static void push_client_machine_destroy(void *a);
  49. /*
  50.  * Checks whether the client push machines list includes a specific machine.
  51.  * Creates it, if the event is TR-Invoke.ind
  52.  */
  53. static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e);
  54. /*
  55.  * Feed an event to the client push state machine. Do not report errors to
  56.  * caller.
  57.  */
  58. static void push_client_event_handle(WSPPushClientMachine *cpm, WAPEvent *e);
  59. /*
  60.  * Print WSP client push machine state as a string.
  61.  */
  62. static unsigned char *name_push_client_state(int name);
  63. static void main_thread(void *);
  64. static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm, 
  65.                                             Octstr *push_body);
  66. static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm, 
  67.                                         long abort_reason);
  68. static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm);
  69. static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm, long reason);
  70. static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm);
  71. /**************************************************************************
  72.  *
  73.  * EXTERNAL FUNCTIONS:
  74.  *
  75.  */
  76. void wsp_push_client_init(wap_dispatch_func_t *dispatch_self, 
  77.                           wap_dispatch_func_t *dispatch_wtp_resp)
  78. {
  79.     push_client_machines = list_create();
  80.     push_client_machine_id_counter = counter_create();
  81.     push_client_queue = list_create();
  82.     list_add_producer(push_client_queue);
  83.     dispatch_to_self = dispatch_self;
  84.     dispatch_to_wtp_resp = dispatch_wtp_resp;
  85.     gw_assert(push_client_run_status == limbo);
  86.     push_client_run_status = running;
  87.     gwthread_create(main_thread, NULL);
  88. }
  89. void wsp_push_client_shutdown(void)
  90. {
  91.     gw_assert(push_client_run_status == running);
  92.     push_client_run_status = terminating;
  93.     list_remove_producer(push_client_queue);
  94.     gwthread_join_every(main_thread);
  95.     debug("wap.wsp", 0, "wsp_push_client_shutdown: %ld push client machines"
  96.           "left", list_len(push_client_machines));
  97.     list_destroy(push_client_machines, push_client_machine_destroy);
  98.     list_destroy(push_client_queue, wap_event_destroy_item);
  99.     counter_destroy(push_client_machine_id_counter);
  100. }
  101. void wsp_push_client_dispatch_event(WAPEvent *e)
  102. {
  103.     list_produce(push_client_queue, e);
  104. }
  105. /***************************************************************************
  106.  *
  107.  * INTERNAL FUNCTIONS:
  108.  *
  109.  */
  110. static void main_thread(void *arg)
  111. {
  112.     WSPPushClientMachine *cpm;
  113.     WAPEvent *e;
  114.     while (push_client_run_status == running &&
  115.             (e = list_consume(push_client_queue)) != NULL) {
  116.          cpm = push_client_machine_find_or_create(e);
  117.          if (cpm == NULL)
  118.      wap_event_destroy(e);
  119.          else
  120.      push_client_event_handle(cpm, e);
  121.     }
  122. }
  123. /*
  124.  * Give the name of a push client machine state in a readable form
  125.  */
  126. static unsigned char *name_push_client_state(int n) {
  127.     switch (n) {
  128.     #define PUSH_CLIENT_STATE_NAME(state) case state : return #state;
  129.     #define ROW(state, event, condition, action, new_state)
  130.     #include "wsp_push_client_states.def"
  131.     default:
  132.         return "unknown state";
  133.     }
  134. }
  135. /*
  136.  * Feed an event to a WSP push client state machine. Do not report errors to
  137.  * the caller.
  138.  */
  139. static void push_client_event_handle(WSPPushClientMachine *cpm, 
  140.                                      WAPEvent *e)
  141. {
  142.     WAPEvent *wtp_event;
  143.     WSP_PDU *pdu = NULL;
  144.     wap_event_assert(e);
  145.     gw_assert(cpm);
  146.     
  147.     if (e->type == TR_Invoke_Ind) {
  148.         pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data);
  149. /*
  150.  * Class 1 tests here
  151.  * Case 4, no session matching address quadruplet, handled by the session mach-
  152.  * ine.
  153.  * Tests from table WSP, page 45. Case 5, a PDU state tables cannot handle.
  154.  */
  155.         if (pdu == NULL || pdu->type != ConfirmedPush) {
  156.     wap_event_destroy(e);
  157.             wtp_event = send_abort_to_responder(cpm, PROTOERR);
  158.             wtp_resp_dispatch_event(wtp_event);
  159.             return;
  160.         }
  161.     }
  162.     debug("wap.wsp", 0, "WSP_PUSH: WSPPushClientMachine %ld, state %s,"
  163.           " event %s", 
  164.           cpm->client_push_id,
  165.           name_push_client_state(cpm->state),
  166.           wap_event_name(e->type));
  167.     #define PUSH_CLIENT_STATE_NAME(state)
  168.     #define ROW(push_state, event_type, condition, action, next_state) 
  169.          if (cpm->state == push_state && 
  170.              e->type == event_type && 
  171.              (condition)) { 
  172.              action 
  173.              cpm->state = next_state; 
  174.              debug("wap.wsp", 0, "WSP_PUSH %ld: new state %s", 
  175.                    cpm->client_push_id, #next_state); 
  176.          } else
  177.     #include "wsp_push_client_states.def"
  178.          {
  179.              error(0, "WSP_PUSH: handle_event: unhandled event!");
  180.              debug("wap.wsp", 0, "Unhandled event was:");
  181.              wap_event_dump(e);
  182.              wap_event_destroy(e);
  183.              return;
  184.          }
  185.     wsp_pdu_destroy(pdu);
  186.     wap_event_destroy(e);
  187.     
  188.     if (cpm->state == PUSH_CLIENT_NULL_STATE)
  189.         push_client_machine_destroy(cpm);
  190. }
  191. static int push_client_machine_has_transid(void *a, void *b)
  192. {
  193.     long transid;
  194.     WSPPushClientMachine *m;
  195.     m = a;
  196.     transid = *(long *)b;
  197.     return m->transaction_id == transid;   
  198. }
  199. static WSPPushClientMachine *push_client_machine_find_using_transid(
  200.            long transid)
  201. {
  202.     WSPPushClientMachine *m;
  203.   
  204.     m = list_search(push_client_machines, &transid, 
  205.                     push_client_machine_has_transid);
  206.     return m;
  207. }
  208. /*
  209.  * Checks client push machines list for a specific machine. Creates it, if the
  210.  * event is TR-Invoke.ind.
  211.  * Client push machine is identified (when searching) by transcation identifi-
  212.  * er. 
  213.  * Note that only WTP responder send its class 1 messages to client push state
  214.  * machine. So, it is no need to specify WTP machine type. 
  215.  */
  216. static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e)
  217. {
  218.     WSPPushClientMachine *cpm;
  219.     long transid;
  220.     cpm = NULL;
  221.     transid = -1;
  222.    
  223.     switch (e->type) {
  224.     case TR_Invoke_Ind:
  225.          transid = e->u.TR_Invoke_Ind.handle;
  226.     break;
  227.     case S_ConfirmedPush_Res:
  228.          transid = e->u.S_ConfirmedPush_Res.client_push_id;
  229.     break;
  230.     case S_PushAbort_Req:
  231.          transid = e->u.S_PushAbort_Req.push_id;
  232.     break;
  233.     case Abort_Event:
  234.     break;
  235.     case TR_Abort_Ind:
  236.          transid = e->u.TR_Abort_Ind.handle;
  237.     break;
  238.     default:
  239.         debug("wap.wsp", 0, "WSP PUSH: push_client_find_or_create: unhandled"
  240.       " event");
  241.         wap_event_dump(e);
  242.         wap_event_destroy(e);
  243.         return NULL;
  244.     }
  245.     gw_assert(transid != -1);
  246.     cpm = push_client_machine_find_using_transid(transid);
  247.     
  248.     if (cpm == NULL) {
  249.         switch (e->type) {
  250.         case TR_Invoke_Ind:
  251.     cpm = push_client_machine_create(transid);
  252. break;
  253.         case S_ConfirmedPush_Res:
  254.         case S_PushAbort_Req:
  255.     error(0, "WSP_PUSH_CLIENT: POT primitive to a nonexisting"
  256.                   "  push client machine");
  257. break;
  258.         case Abort_Event:
  259.     error(0, "WSP_PUSH_CLIENT: internal abort to a nonexisting"
  260.                   " push client machine");
  261. break;
  262.         case TR_Abort_Ind:
  263.     error(0, "WSP_PUSH_CLIENT: WTP abort to a nonexisting push client"
  264.                   " machine");
  265. break;
  266. default:
  267.     error(0, "WSP_PUSH_CLIENT: Cannot handle event type %s",
  268. wap_event_name(e->type));
  269. break;
  270.         }
  271.     }
  272.     return cpm;
  273. }
  274. static WSPPushClientMachine *push_client_machine_create(long transid)
  275. {
  276.     WSPPushClientMachine *m;
  277.     m = gw_malloc(sizeof(WSPPushClientMachine));
  278.     debug("wap.wsp", 0, "WSP_PUSH_CLIENT: Created WSPPushClientMachine %p",
  279.           (void *) m);
  280.     #define INTEGER(name) m->name = 0;
  281.     #define HTTPHEADERS(name) m->name = NULL;
  282.     #define MACHINE(fields) fields
  283.     #include "wsp_push_client_machine.def"
  284.     m->state = PUSH_CLIENT_NULL_STATE;
  285.     m->transaction_id = transid;
  286.     m->client_push_id = counter_increase(push_client_machine_id_counter);
  287.     list_append(push_client_machines, m);
  288.     return m;
  289. }
  290. static void push_client_machine_destroy(void *a) 
  291. {
  292.     WSPPushClientMachine *m;
  293.     m = a;
  294.     debug("wap.wsp", 0, "Destroying WSPPushClientMachine %p", (void *) m);
  295.     list_delete_equal(push_client_machines, m); 
  296.     #define INTEGER(name) m->name = 0;
  297.     #define HTTPHEADERS(name) http_destroy_headers(m->name);  
  298.     #define MACHINE(fields) fields;
  299.     #include "wsp_push_client_machine.def"
  300.     gw_free(m);
  301. }
  302. static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm, 
  303.                                             Octstr *push_body)
  304. {
  305.     WAPEvent *e;
  306.     e = wap_event_create(S_ConfirmedPush_Ind);
  307.     e->u.S_ConfirmedPush_Ind.client_push_id = cpm->client_push_id;
  308.     e->u.S_ConfirmedPush_Ind.push_headers = 
  309.         http_header_duplicate(cpm->push_headers);
  310.     e->u.S_ConfirmedPush_Ind.push_body = octstr_duplicate(push_body);
  311.     return e;
  312. }
  313. static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm, 
  314.                                         long abort_reason)
  315. {
  316.     WAPEvent *e;
  317.     e = wap_event_create(S_PushAbort_Ind);
  318.     e->u.S_PushAbort_Ind.push_id = cpm->client_push_id;
  319.     e->u.S_PushAbort_Ind.reason = abort_reason;
  320.     return e;
  321. }
  322. /*
  323.  * For debugging: create S-ConfirmedPush.res by ourselves. 
  324.  */
  325. static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm)
  326. {
  327.     WAPEvent *e;
  328.     e = wap_event_create(S_ConfirmedPush_Res);
  329.     e->u.S_ConfirmedPush_Res.client_push_id = cpm->client_push_id;
  330.     return e;
  331. }
  332. static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm, 
  333.                                          long reason)
  334. {
  335.     WAPEvent *e;
  336.     e = wap_event_create(TR_Abort_Req);
  337.     e->u.TR_Abort_Req.abort_type = USER;
  338.     e->u.TR_Abort_Req.abort_reason = reason;
  339.     e->u.TR_Abort_Req.handle = cpm->client_push_id;
  340.     return e;
  341. }
  342. static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm)
  343. {
  344.     WAPEvent *e;
  345.     e = wap_event_create(TR_Invoke_Res);
  346.     e->u.TR_Invoke_Res.handle = cpm->transaction_id;
  347.     return e;
  348. }