Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wsp_push_client.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * wsp_push_client.c: Client WSP Push implementation, for testing purposes
00059  *
00060  * Aarno Syvänen for Wapit Ltd
00061  */
00062 
00063 #include "wsp_push_client.h"
00064 #include "wsp.h"
00065 #include "wtp.h"
00066 #include "wsp_pdu.h"
00067 #include "wsp_headers.h"
00068 #include "wap.h"
00069 
00070 /**************************************************************************
00071  * 
00072  * Internal data structures:
00073  *
00074  * List of client WSP push machines.
00075  */
00076 static List *push_client_machines = NULL;
00077 
00078 /*
00079  * Counter for client push machine id numbers, to make sure that they are 
00080  * unique.
00081  */
00082 static Counter *push_client_machine_id_counter = NULL;
00083 
00084 /*
00085  * Give the status of push client:
00086  *
00087  *  limbo
00088  *      not running at all
00089  *  running
00090  *      operating normally
00091  *  terminating
00092  *      waiting for operations to terminate, returning to limbo
00093  */
00094 static enum {limbo, running, terminating } push_client_run_status = limbo;
00095 
00096 /*
00097  * Queue of events to be handled by the push client.
00098  */
00099 static List *push_client_queue = NULL;
00100 
00101 wap_dispatch_func_t *dispatch_to_self;
00102 wap_dispatch_func_t *dispatch_to_wtp_resp;
00103 
00104 /*****************************************************************************
00105  *
00106  * Prototypes of internal functions:
00107  *
00108  * Create and destroy an uniniatilised push client state machine.
00109  */
00110 static WSPPushClientMachine *push_client_machine_create(long cpid);
00111 static void push_client_machine_destroy(void *a);
00112 
00113 /*
00114  * Checks whether the client push machines list includes a specific machine.
00115  * Creates it, if the event is TR-Invoke.ind
00116  */
00117 static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e);
00118 
00119 /*
00120  * Feed an event to the client push state machine. Do not report errors to
00121  * caller.
00122  */
00123 static void push_client_event_handle(WSPPushClientMachine *cpm, WAPEvent *e);
00124 
00125 /*
00126  * Print WSP client push machine state as a string.
00127  */
00128 static unsigned char *name_push_client_state(int name);
00129 static void main_thread(void *);
00130 static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm, 
00131                                             Octstr *push_body);
00132 static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm, 
00133                                         long abort_reason);
00134 static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm);
00135 static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm, long reason);
00136 static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm);
00137 
00138 
00139 /**************************************************************************
00140  *
00141  * EXTERNAL FUNCTIONS:
00142  *
00143  */
00144 
00145 void wsp_push_client_init(wap_dispatch_func_t *dispatch_self, 
00146                           wap_dispatch_func_t *dispatch_wtp_resp)
00147 {
00148     push_client_machines = gwlist_create();
00149     push_client_machine_id_counter = counter_create();
00150 
00151     push_client_queue = gwlist_create();
00152     gwlist_add_producer(push_client_queue);
00153 
00154     dispatch_to_self = dispatch_self;
00155     dispatch_to_wtp_resp = dispatch_wtp_resp;
00156 
00157     gw_assert(push_client_run_status == limbo);
00158     push_client_run_status = running;
00159     gwthread_create(main_thread, NULL);
00160 }
00161 
00162 void wsp_push_client_shutdown(void)
00163 {
00164     gw_assert(push_client_run_status == running);
00165     push_client_run_status = terminating;
00166     gwlist_remove_producer(push_client_queue);
00167     gwthread_join_every(main_thread);
00168 
00169     debug("wap.wsp", 0, "wsp_push_client_shutdown: %ld push client machines"
00170           "left", gwlist_len(push_client_machines));
00171     gwlist_destroy(push_client_machines, push_client_machine_destroy);
00172     gwlist_destroy(push_client_queue, wap_event_destroy_item);
00173 
00174     counter_destroy(push_client_machine_id_counter);
00175 }
00176 
00177 void wsp_push_client_dispatch_event(WAPEvent *e)
00178 {
00179     gwlist_produce(push_client_queue, e);
00180 }
00181 
00182 /***************************************************************************
00183  *
00184  * INTERNAL FUNCTIONS:
00185  *
00186  */
00187 
00188 static void main_thread(void *arg)
00189 {
00190     WSPPushClientMachine *cpm;
00191     WAPEvent *e;
00192 
00193     while (push_client_run_status == running &&
00194             (e = gwlist_consume(push_client_queue)) != NULL) {
00195          cpm = push_client_machine_find_or_create(e);
00196          if (cpm == NULL)
00197          wap_event_destroy(e);
00198          else
00199          push_client_event_handle(cpm, e);
00200     }
00201 }
00202 
00203 /*
00204  * Give the name of a push client machine state in a readable form
00205  */
00206 static unsigned char *name_push_client_state(int n) {
00207 
00208     switch (n) {
00209     #define PUSH_CLIENT_STATE_NAME(state) case state : return (unsigned char *)#state;
00210     #define ROW(state, event, condition, action, new_state)
00211     #include "wsp_push_client_states.def"
00212     default:
00213         return (unsigned char *)"unknown state";
00214     }
00215 }
00216 
00217 /*
00218  * Feed an event to a WSP push client state machine. Do not report errors to
00219  * the caller.
00220  */
00221 static void push_client_event_handle(WSPPushClientMachine *cpm, 
00222                                      WAPEvent *e)
00223 {
00224     WAPEvent *wtp_event;
00225     WSP_PDU *pdu = NULL;
00226 
00227     wap_event_assert(e);
00228     gw_assert(cpm);
00229     
00230     if (e->type == TR_Invoke_Ind) {
00231         pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data);
00232 /*
00233  * Class 1 tests here
00234  * Case 4, no session matching address quadruplet, handled by the session mach-
00235  * ine.
00236  * Tests from table WSP, page 45. Case 5, a PDU state tables cannot handle.
00237  */
00238         if (pdu == NULL || pdu->type != ConfirmedPush) {
00239         wap_event_destroy(e);
00240             wtp_event = send_abort_to_responder(cpm, PROTOERR);
00241             wtp_resp_dispatch_event(wtp_event);
00242             return;
00243         }
00244     }
00245 
00246     debug("wap.wsp", 0, "WSP_PUSH: WSPPushClientMachine %ld, state %s,"
00247           " event %s", 
00248           cpm->client_push_id,
00249           name_push_client_state(cpm->state),
00250           wap_event_name(e->type));
00251     #define PUSH_CLIENT_STATE_NAME(state)
00252     #define ROW(push_state, event_type, condition, action, next_state) \
00253          if (cpm->state == push_state && \
00254              e->type == event_type && \
00255              (condition)) { \
00256              action \
00257              cpm->state = next_state; \
00258              debug("wap.wsp", 0, "WSP_PUSH %ld: new state %s", \
00259                    cpm->client_push_id, #next_state); \
00260          } else
00261     #include "wsp_push_client_states.def"
00262          {
00263              error(0, "WSP_PUSH: handle_event: unhandled event!");
00264              debug("wap.wsp", 0, "Unhandled event was:");
00265              wap_event_dump(e);
00266              wap_event_destroy(e);
00267              return;
00268          }
00269 
00270     wsp_pdu_destroy(pdu);
00271     wap_event_destroy(e);
00272     
00273     if (cpm->state == PUSH_CLIENT_NULL_STATE)
00274         push_client_machine_destroy(cpm);
00275 }
00276 
00277 static int push_client_machine_has_transid(void *a, void *b)
00278 {
00279     long transid;
00280     WSPPushClientMachine *m;
00281 
00282     m = a;
00283     transid = *(long *)b;
00284     return m->transaction_id == transid;   
00285 }
00286 
00287 static WSPPushClientMachine *push_client_machine_find_using_transid(
00288            long transid)
00289 {
00290     WSPPushClientMachine *m;
00291   
00292     m = gwlist_search(push_client_machines, &transid, 
00293                     push_client_machine_has_transid);
00294     return m;
00295 }
00296 
00297 /*
00298  * Checks client push machines list for a specific machine. Creates it, if the
00299  * event is TR-Invoke.ind.
00300  * Client push machine is identified (when searching) by transcation identifi-
00301  * er. 
00302  * Note that only WTP responder send its class 1 messages to client push state
00303  * machine. So, it is no need to specify WTP machine type. 
00304  */
00305 static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e)
00306 {
00307     WSPPushClientMachine *cpm;
00308     long transid;
00309 
00310     cpm = NULL;
00311     transid = -1;
00312    
00313     switch (e->type) {
00314     case TR_Invoke_Ind:
00315          transid = e->u.TR_Invoke_Ind.handle;
00316     break;
00317 
00318     case S_ConfirmedPush_Res:
00319          transid = e->u.S_ConfirmedPush_Res.client_push_id;
00320     break;
00321 
00322     case S_PushAbort_Req:
00323          transid = e->u.S_PushAbort_Req.push_id;
00324     break;
00325 
00326     case Abort_Event:
00327     break;
00328 
00329     case TR_Abort_Ind:
00330          transid = e->u.TR_Abort_Ind.handle;
00331     break;
00332 
00333     default:
00334         debug("wap.wsp", 0, "WSP PUSH: push_client_find_or_create: unhandled"
00335           " event");
00336         wap_event_dump(e);
00337         wap_event_destroy(e);
00338         return NULL;
00339     }
00340 
00341     gw_assert(transid != -1);
00342 
00343     cpm = push_client_machine_find_using_transid(transid);
00344     
00345     if (cpm == NULL) {
00346         switch (e->type) {
00347         case TR_Invoke_Ind:
00348         cpm = push_client_machine_create(transid);
00349     break;
00350 
00351         case S_ConfirmedPush_Res:
00352         case S_PushAbort_Req:
00353         error(0, "WSP_PUSH_CLIENT: POT primitive to a nonexisting"
00354                   "  push client machine");
00355     break;
00356 
00357         case Abort_Event:
00358         error(0, "WSP_PUSH_CLIENT: internal abort to a nonexisting"
00359                   " push client machine");
00360     break;
00361 
00362         case TR_Abort_Ind:
00363         error(0, "WSP_PUSH_CLIENT: WTP abort to a nonexisting push client"
00364                   " machine");
00365     break;
00366 
00367     default:
00368         error(0, "WSP_PUSH_CLIENT: Cannot handle event type %s",
00369         wap_event_name(e->type));
00370     break;
00371         }
00372     }
00373 
00374     return cpm;
00375 }
00376 
00377 static WSPPushClientMachine *push_client_machine_create(long transid)
00378 {
00379     WSPPushClientMachine *m;
00380 
00381     m = gw_malloc(sizeof(WSPPushClientMachine));
00382     debug("wap.wsp", 0, "WSP_PUSH_CLIENT: Created WSPPushClientMachine %p",
00383           (void *) m);
00384 
00385     #define INTEGER(name) m->name = 0;
00386     #define HTTPHEADERS(name) m->name = NULL;
00387     #define MACHINE(fields) fields
00388     #include "wsp_push_client_machine.def"
00389 
00390     m->state = PUSH_CLIENT_NULL_STATE;
00391     m->transaction_id = transid;
00392     m->client_push_id = counter_increase(push_client_machine_id_counter);
00393 
00394     gwlist_append(push_client_machines, m);
00395 
00396     return m;
00397 }
00398 
00399 static void push_client_machine_destroy(void *a) 
00400 {
00401     WSPPushClientMachine *m;
00402 
00403     m = a;
00404     debug("wap.wsp", 0, "Destroying WSPPushClientMachine %p", (void *) m);
00405     gwlist_delete_equal(push_client_machines, m); 
00406 
00407     #define INTEGER(name) m->name = 0;
00408     #define HTTPHEADERS(name) http_destroy_headers(m->name);  
00409     #define MACHINE(fields) fields;
00410     #include "wsp_push_client_machine.def"
00411 
00412     gw_free(m);
00413 }
00414 
00415 
00416 static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm, 
00417                                             Octstr *push_body)
00418 {
00419     WAPEvent *e;
00420 
00421     e = wap_event_create(S_ConfirmedPush_Ind);
00422     e->u.S_ConfirmedPush_Ind.client_push_id = cpm->client_push_id;
00423     e->u.S_ConfirmedPush_Ind.push_headers = 
00424         http_header_duplicate(cpm->push_headers);
00425     e->u.S_ConfirmedPush_Ind.push_body = octstr_duplicate(push_body);
00426 
00427     return e;
00428 }
00429 
00430 static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm, 
00431                                         long abort_reason)
00432 {
00433     WAPEvent *e;
00434 
00435     e = wap_event_create(S_PushAbort_Ind);
00436     e->u.S_PushAbort_Ind.push_id = cpm->client_push_id;
00437     e->u.S_PushAbort_Ind.reason = abort_reason;
00438 
00439     return e;
00440 }
00441 
00442 
00443 /*
00444  * For debugging: create S-ConfirmedPush.res by ourselves. 
00445  */
00446 static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm)
00447 {
00448     WAPEvent *e;
00449 
00450     e = wap_event_create(S_ConfirmedPush_Res);
00451     e->u.S_ConfirmedPush_Res.client_push_id = cpm->client_push_id;
00452 
00453     return e;
00454 }
00455 
00456 static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm, 
00457                                          long reason)
00458 {
00459     WAPEvent *e;
00460 
00461     e = wap_event_create(TR_Abort_Req);
00462     e->u.TR_Abort_Req.abort_type = USER;
00463     e->u.TR_Abort_Req.abort_reason = reason;
00464     e->u.TR_Abort_Req.handle = cpm->client_push_id;
00465 
00466     return e;
00467 }
00468 
00469 
00470 static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm)
00471 {
00472     WAPEvent *e;
00473 
00474     e = wap_event_create(TR_Invoke_Res);
00475     e->u.TR_Invoke_Res.handle = cpm->transaction_id;
00476 
00477     return e;
00478 }
00479 
00480 
00481 
00482 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.