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

wtp_resp.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  * wtp_resp.c - WTP responder implementation
00059  *
00060  * Aarno Syvänen
00061  * Lars Wirzenius
00062  */
00063 
00064 #include "gwlib/gwlib.h"
00065 #include "wtp_resp.h"
00066 #include "wtp_pack.h"
00067 #include "wtp_tid.h"
00068 #include "wtp.h"
00069 #include "timers.h"
00070 #include "wap.h"
00071 
00072 /***********************************************************************
00073  * Internal data structures.
00074  *
00075  * List of responder WTP machines.
00076  */
00077 static List *resp_machines = NULL;
00078 
00079 
00080 /*
00081  * Counter for responder WTP machine id numbers, to make sure they are unique.
00082  */
00083 static Counter *resp_machine_id_counter = NULL;
00084 
00085 
00086 /*
00087  * Give the status of wtp responder:
00088  *
00089  *  limbo
00090  *      not running at all
00091  *  running
00092  *      operating normally
00093  *  terminating
00094  *      waiting for operations to terminate, returning to limbo
00095  */
00096 static enum { limbo, running, terminating } resp_run_status = limbo;
00097 
00098 
00099 wap_dispatch_func_t *dispatch_to_wdp;
00100 wap_dispatch_func_t *dispatch_to_wsp;
00101 wap_dispatch_func_t *dispatch_to_push;
00102 
00103 /*
00104  * Queue of events to be handled by WTP responder.
00105  */
00106 static List *resp_queue = NULL;
00107 
00108 /*
00109  * Timer 'tick'. All wtp responder timer values are multiplies of this one
00110  */
00111 static long resp_timer_freq = -1;
00112 
00113 /*****************************************************************************
00114  *
00115  * Prototypes of internal functions:
00116  *
00117  * Create and destroy an uniniatilized wtp responder state machine.
00118  */
00119 
00120 static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid, 
00121                                            long tcl);
00122 static void resp_machine_destroy(void *sm);
00123 
00124 /*
00125  * Checks whether wtp responser machines data structure includes a specific 
00126  * machine.
00127  * The machine in question is identified with with source and destination
00128  * address and port and tid. If the machine does not exist and the event is 
00129  * RcvInvoke, a new machine is created and added in the machines data 
00130  * structure. 
00131  * First test incoming events (WTP 10.2) (Exception is tests nro 4 and 5: if 
00132  * we have a memory error, we panic. Nro 4 is already checked)  If event was 
00133  * validated and If the event was RcvAck or RcvAbort, the event is ignored. 
00134  * If the event is RcvErrorPDU, new machine is created.
00135  */
00136 static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event);
00137 
00138 
00139 /*
00140  * Feed an event to a WTP responder state machine. Handle all errors by 
00141  * itself, do not report them to the caller. WSP indication or confirmation 
00142  * is handled by an included state table.
00143  */
00144 static void resp_event_handle(WTPRespMachine *machine, WAPEvent *event);
00145 
00146 /*
00147  * Print a wtp responder machine state as a string.
00148  */
00149 static char *name_resp_state(int name);
00150 
00151 /*
00152  * Find the wtp responder machine from the global list of wtp responder 
00153  * structures that corresponds to the five-tuple of source and destination 
00154  * addresses and ports and the transaction identifier. Return a pointer to 
00155  * the machine, or NULL if not found.
00156  */
00157 static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid, 
00158                                          long mid);
00159 static void main_thread(void *);
00160 
00161 /*
00162  * Start acknowledgement interval timer
00163  */
00164 static void start_timer_A(WTPRespMachine *machine);
00165 
00166 /*
00167  * Start retry interval timer
00168  */
00169 static void start_timer_R(WTPRespMachine *machine);
00170 
00171 /*
00172  * Start timeout interval timer.
00173  */
00174 static void start_timer_W(WTPRespMachine *machine);
00175 static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data);
00176 static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason);
00177 static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm);
00178 static int erroneous_field_in(WAPEvent *event);
00179 static void handle_wrong_version(WAPEvent *event);
00180 
00181 /*
00182  * SAR related functions.
00183  */
00184 static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn);
00185 static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn);
00186 /* static int is_wanted_sar_data (void *a, void *b); */
00187 static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event);
00188 static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event);
00189 static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event);
00190 static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event);
00191 static void sar_info_destroy(void *sar_info);
00192 static void sardata_destroy(void *sardata);
00193 
00194 /*
00195  * Create a datagram with an Abort PDU and send it to the WDP layer.
00196  */
00197 static void send_abort(WTPRespMachine *machine, long type, long reason);
00198 
00199 /*
00200  * Create a datagram with an Ack PDU and send it to the WDP layer.
00201  */
00202 static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag);
00203 
00204 
00205 /******************************************************************************
00206  *
00207  * EXTERNAL FUNCTIONS:
00208  *
00209  */
00210 
00211 void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch,
00212                    wap_dispatch_func_t *session_dispatch,
00213                    wap_dispatch_func_t *push_dispatch, 
00214                    long timer_freq) 
00215 {
00216     resp_machines = gwlist_create();
00217     resp_machine_id_counter = counter_create();
00218 
00219     resp_queue = gwlist_create();
00220     gwlist_add_producer(resp_queue);
00221 
00222     dispatch_to_wdp = datagram_dispatch;
00223     dispatch_to_wsp = session_dispatch;
00224     dispatch_to_push = push_dispatch;
00225 
00226     timers_init();
00227     resp_timer_freq = timer_freq;
00228     wtp_tid_cache_init();
00229 
00230     gw_assert(resp_run_status == limbo);
00231     resp_run_status = running;
00232     gwthread_create(main_thread, NULL);
00233 }
00234 
00235 void wtp_resp_shutdown(void) 
00236 {
00237     gw_assert(resp_run_status == running);
00238     resp_run_status = terminating;
00239     gwlist_remove_producer(resp_queue);
00240     gwthread_join_every(main_thread);
00241 
00242     debug("wap.wtp", 0, "wtp_resp_shutdown: %ld resp_machines left",
00243           gwlist_len(resp_machines));
00244     gwlist_destroy(resp_machines, resp_machine_destroy);
00245     gwlist_destroy(resp_queue, wap_event_destroy_item);
00246 
00247     counter_destroy(resp_machine_id_counter);
00248 
00249     wtp_tid_cache_shutdown();
00250     timers_shutdown();
00251 }
00252 
00253 void wtp_resp_dispatch_event(WAPEvent *event) 
00254 {
00255     gwlist_produce(resp_queue, event);
00256 }
00257 
00258 
00259 /*****************************************************************************
00260  *
00261  * INTERNAL FUNCTIONS:
00262  *
00263  */
00264 
00265 static void main_thread(void *arg) 
00266 {
00267     WTPRespMachine *sm;
00268     WAPEvent *e;
00269 
00270     while (resp_run_status == running && 
00271            (e = gwlist_consume(resp_queue)) != NULL) {
00272 
00273         sm = resp_machine_find_or_create(e);
00274         if (sm == NULL) {
00275             wap_event_destroy(e);
00276         } else {
00277             resp_event_handle(sm, e);
00278         }
00279     }
00280 }
00281 
00282 /*
00283  * Give the name of a responder state in a readable form. 
00284  */
00285 static char *name_resp_state(int s)
00286 {
00287        switch (s) {
00288        #define STATE_NAME(state) case state: return #state;
00289        #define ROW(state, event, condition, action, new_state)
00290        #include "wtp_resp_states.def"
00291        default:
00292            return "unknown state";
00293        }
00294 }
00295 
00296 
00297 /*
00298  * Feed an event to a WTP responder state machine. Handle all errors yourself,
00299  * do not report them to the caller. Note: Do not put {}s of the else block 
00300  * inside the macro definition. 
00301  */
00302 static void resp_event_handle(WTPRespMachine *resp_machine, WAPEvent *event)
00303 {
00304     WAPEvent *wsp_event = NULL;
00305 
00306     /* 
00307      * We don't feed sar packets into state machine 
00308      * until we got the whole message 
00309      */
00310     if (process_sar_transaction(resp_machine,&event) == 0) {
00311         debug("wap.wtp", 0, "SAR event received, wait for continue");
00312         /* For removing state machine in case of incomplete sar */
00313         start_timer_W(resp_machine);
00314         if (event != NULL) {
00315             wap_event_destroy(event);  
00316         }
00317         return;
00318     }
00319 
00320     debug("wap.wtp", 0, "WTP: resp_machine %ld, state %s, event %s.", 
00321       resp_machine->mid, 
00322       name_resp_state(resp_machine->state), 
00323       wap_event_name(event->type));
00324 
00325     #define STATE_NAME(state)
00326     #define ROW(wtp_state, event_type, condition, action, next_state) \
00327      if (resp_machine->state == wtp_state && \
00328          event->type == event_type && \
00329          (condition)) { \
00330          action \
00331          resp_machine->state = next_state; \
00332          debug("wap.wtp", 0, "WTP %ld: New state %s", resp_machine->mid,                      #next_state); \
00333      } else 
00334     #include "wtp_resp_states.def"
00335      {
00336          error(0, "WTP: handle_event: unhandled event!");
00337          debug("wap.wtp", 0, "WTP: handle_event: Unhandled event was:");
00338          wap_event_dump(event);
00339              wap_event_destroy(event);
00340              return;
00341      }
00342 
00343     if (event != NULL) {
00344     wap_event_destroy(event);  
00345     }
00346 
00347     if (resp_machine->state == LISTEN)
00348         resp_machine_destroy(resp_machine);
00349 }
00350 
00351 static void handle_wrong_version(WAPEvent *event)
00352 {       
00353     WAPEvent *ab;
00354 
00355     if (event->type == RcvInvoke) {
00356         ab = wtp_pack_abort(PROVIDER, WTPVERSIONZERO, event->u.RcvInvoke.tid, 
00357                             event->u.RcvInvoke.addr_tuple);
00358         dispatch_to_wdp(ab);
00359     }
00360 }
00361 
00362 /*
00363  * Check for features 7 and 9 in WTP 10.2.
00364  */
00365 static int erroneous_field_in(WAPEvent *event)
00366 {
00367     return event->type == RcvInvoke && event->u.RcvInvoke.version != 0;
00368 }
00369 
00370 /*
00371  * React features 7 and 9 in WTP 10.2, by aborting with an appropiate error 
00372  * message.
00373  */
00374 static void handle_erroneous_field_in(WAPEvent *event)
00375 {
00376     if (event->type == RcvInvoke) {
00377         if (event->u.RcvInvoke.version != 0) {
00378             debug("wap.wtp_resp", 0, "WTP_RESP: wrong version, aborting"
00379                   "transaction");
00380             handle_wrong_version(event);
00381         }
00382     }
00383 }
00384 
00385 /*
00386  * Checks whether wtp machines data structure includes a specific machine.
00387  * The machine in question is identified with with source and destination
00388  * address and port and tid.  First test incoming events (WTP 10.2)
00389  * (Exception is tests nro 4 and 5: if we have a memory error, we panic. Nro 5 
00390  * is already checked)  If event was validated and if the machine does not 
00391  * exist and the event is RcvInvoke, a new machine is created and added in 
00392  * the machines data structure. If the event was RcvAck or RcvAbort, the 
00393  * event is ignored (test nro 3). If the event is RcvErrorPDU (test nro 4) 
00394  * new machine is created for handling this event. If the event is one of WSP 
00395  * primitives, we have an error.
00396  */
00397 static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event)
00398 {
00399     WTPRespMachine *resp_machine = NULL;
00400     long tid, mid;
00401     WAPAddrTuple *tuple;
00402 
00403     tid = -1;
00404     tuple = NULL;
00405     mid = -1;
00406 
00407     switch (event->type) {
00408         case RcvInvoke:
00409             /* check if erroneous fields are given */
00410             if (erroneous_field_in(event)) {
00411                 handle_erroneous_field_in(event);
00412                 return NULL;
00413             } else {
00414                 tid = event->u.RcvInvoke.tid;
00415                 tuple = event->u.RcvInvoke.addr_tuple;
00416             }
00417             break;
00418 
00419         case RcvSegInvoke:
00420             tid = event->u.RcvSegInvoke.tid;
00421             tuple = event->u.RcvSegInvoke.addr_tuple;
00422             break;
00423 
00424         case RcvAck:
00425             tid = event->u.RcvAck.tid;
00426             tuple = event->u.RcvAck.addr_tuple;
00427             break;
00428 
00429         case RcvNegativeAck:
00430             tid = event->u.RcvAck.tid;
00431             tuple = event->u.RcvAck.addr_tuple;
00432             break;
00433 
00434         case RcvAbort:
00435             tid = event->u.RcvAbort.tid;
00436             tuple = event->u.RcvAbort.addr_tuple;
00437             break;
00438 
00439         case RcvErrorPDU:
00440             tid = event->u.RcvErrorPDU.tid;
00441             tuple = event->u.RcvErrorPDU.addr_tuple;
00442             break;
00443 
00444         case TR_Invoke_Res:
00445             mid = event->u.TR_Invoke_Res.handle;
00446             break;
00447 
00448         case TR_Result_Req:
00449             mid = event->u.TR_Result_Req.handle;
00450             break;
00451 
00452         case TR_Abort_Req:
00453             mid = event->u.TR_Abort_Req.handle;
00454             break;
00455 
00456         case TimerTO_A:
00457             mid = event->u.TimerTO_A.handle;
00458             break;
00459 
00460         case TimerTO_R:
00461             mid = event->u.TimerTO_R.handle;
00462             break;
00463 
00464         case TimerTO_W:
00465             mid = event->u.TimerTO_W.handle;
00466             break;
00467 
00468         default:
00469             debug("wap.wtp", 0, "WTP: resp_machine_find_or_create:"
00470                   "unhandled event"); 
00471             wap_event_dump(event);
00472             return NULL;
00473     }
00474 
00475     gw_assert(tuple != NULL || mid != -1);
00476     resp_machine = resp_machine_find(tuple, tid, mid);
00477            
00478     if (resp_machine == NULL){
00479 
00480         switch (event->type) {
00481 
00482         /*
00483          * When PDU with an illegal header is received, its tcl-field is 
00484          * irrelevant and possibly meaningless). In this case we must create 
00485          * a new machine, if there is any. There is a machine for all events 
00486          * handled stateful manner.
00487          */
00488         case RcvErrorPDU:
00489             debug("wap.wtp_resp", 0, "an erronous pdu received");
00490             wap_event_dump(event);
00491             resp_machine = resp_machine_create(tuple, tid, 
00492                                                event->u.RcvInvoke.tcl); 
00493             break;
00494            
00495         case RcvInvoke:
00496             resp_machine = resp_machine_create(tuple, tid, 
00497                                                event->u.RcvInvoke.tcl);
00498             /* if SAR requested */
00499             if (!event->u.RcvInvoke.gtr || !event->u.RcvInvoke.ttr) {
00500                 resp_machine->sar = gw_malloc(sizeof(WTPSARData));
00501                 resp_machine->sar->nsegm = 0;
00502                 resp_machine->sar->csegm = 0;
00503                 resp_machine->sar->lsegm = 0;
00504                 resp_machine->sar->data = NULL;     
00505             }
00506 
00507             break;
00508         
00509         case RcvSegInvoke:
00510             info(0, "WTP_RESP: resp_machine_find_or_create:"
00511                  " segmented invoke received, yet having no machine");
00512             break;
00513 
00514         /*
00515          * This and the following branch implement test nro 3 in WTP 10.2.
00516          */
00517         case RcvAck: 
00518             info(0, "WTP_RESP: resp_machine_find_or_create:"
00519                  " ack received, yet having no machine");
00520             break;
00521 
00522         case RcvNegativeAck: 
00523             info(0, "WTP_RESP: resp_machine_find_or_create:"
00524                  " negative ack received, yet having no machine");
00525             break;
00526 
00527         case RcvAbort: 
00528             info(0, "WTP_RESP: resp_machine_find_or_create:"
00529                  " abort received, yet having no machine");
00530             break;
00531 
00532         case TR_Invoke_Res: 
00533         case TR_Result_Req: 
00534         case TR_Abort_Req:
00535             error(0, "WTP_RESP: resp_machine_find_or_create: WSP primitive to"
00536                   " a wrong WTP machine");
00537             break;
00538 
00539         case TimerTO_A: 
00540         case TimerTO_R: 
00541         case TimerTO_W:
00542             error(0, "WTP_RESP: resp_machine_find_or_create: timer event"
00543                   " without a corresponding machine");
00544             break;
00545                  
00546         default:
00547             error(0, "WTP_RESP: resp_machine_find_or_create: unhandled event");
00548             wap_event_dump(event);
00549             break;
00550         }
00551    } /* if machine == NULL */   
00552    return resp_machine;
00553 }
00554 
00555 static int is_wanted_resp_machine(void *a, void *b) 
00556 {
00557     machine_pattern *pat;
00558     WTPRespMachine *m;
00559     
00560     m = a;
00561     pat = b;
00562 
00563     if (m->mid == pat->mid)
00564     return 1;
00565 
00566     if (pat->mid != -1)
00567     return 0;
00568 
00569     return m->tid == pat->tid && 
00570            wap_addr_tuple_same(m->addr_tuple, pat->tuple);
00571 }
00572 
00573 
00574 static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid, 
00575                                          long mid) 
00576 {
00577     machine_pattern pat;
00578     WTPRespMachine *m;
00579     
00580     pat.tuple = tuple;
00581     pat.tid = tid;
00582     pat.mid = mid;
00583     
00584     m = gwlist_search(resp_machines, &pat, is_wanted_resp_machine);
00585     return m;
00586 }
00587 
00588 
00589 static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid, 
00590                                            long tcl) 
00591 {
00592     WTPRespMachine *resp_machine;
00593     
00594     resp_machine = gw_malloc(sizeof(WTPRespMachine)); 
00595         
00596     #define ENUM(name) resp_machine->name = LISTEN;
00597     #define EVENT(name) resp_machine->name = NULL;
00598     #define INTEGER(name) resp_machine->name = 0; 
00599     #define TIMER(name) resp_machine->name = gwtimer_create(resp_queue); 
00600     #define ADDRTUPLE(name) resp_machine->name = NULL; 
00601     #define LIST(name) resp_machine->name = NULL;
00602     #define SARDATA(name) resp_machine->name = NULL;
00603     #define MACHINE(field) field
00604     #include "wtp_resp_machine.def"
00605 
00606     gwlist_append(resp_machines, resp_machine);
00607 
00608     resp_machine->mid = counter_increase(resp_machine_id_counter);
00609     resp_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);
00610     resp_machine->tid = tid;
00611     resp_machine->tcl = tcl;
00612     
00613     debug("wap.wtp", 0, "WTP: Created WTPRespMachine %p (%ld)", 
00614       (void *) resp_machine, resp_machine->mid);
00615 
00616     return resp_machine;
00617 } 
00618 
00619 
00620 /*
00621  * Destroys a WTPRespMachine. Assumes it is safe to do so. Assumes it has 
00622  * already been deleted from the machines list.
00623  */
00624 static void resp_machine_destroy(void * p)
00625 {
00626     WTPRespMachine *resp_machine;
00627 
00628     resp_machine = p;
00629     debug("wap.wtp", 0, "WTP: Destroying WTPRespMachine %p (%ld)", 
00630       (void *) resp_machine, resp_machine->mid);
00631     
00632     gwlist_delete_equal(resp_machines, resp_machine);
00633         
00634     #define ENUM(name) resp_machine->name = LISTEN;
00635     #define EVENT(name) wap_event_destroy(resp_machine->name);
00636     #define INTEGER(name) resp_machine->name = 0; 
00637     #define TIMER(name) gwtimer_destroy(resp_machine->name); 
00638     #define ADDRTUPLE(name) wap_addr_tuple_destroy(resp_machine->name); 
00639     #define LIST(name) gwlist_destroy(resp_machine->name,sar_info_destroy);
00640     #define SARDATA(name) sardata_destroy(resp_machine->name);
00641     #define MACHINE(field) field
00642     #include "wtp_resp_machine.def"
00643     gw_free(resp_machine);
00644 }
00645 
00646 /*
00647  * Create a TR-Invoke.ind event.
00648  */
00649 static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data) 
00650 {
00651     WAPEvent *event;
00652     
00653     event = wap_event_create(TR_Invoke_Ind);
00654     event->u.TR_Invoke_Ind.ack_type = sm->u_ack;
00655     event->u.TR_Invoke_Ind.user_data = octstr_duplicate(user_data);
00656     event->u.TR_Invoke_Ind.tcl = sm->tcl;
00657     event->u.TR_Invoke_Ind.addr_tuple = 
00658     wap_addr_tuple_duplicate(sm->addr_tuple);
00659     event->u.TR_Invoke_Ind.handle = sm->mid;
00660     return event;
00661 }
00662 
00663 
00664 /*
00665  * Create a TR-Result.cnf event.
00666  */
00667 static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm) 
00668 {
00669     WAPEvent *event;
00670     
00671     event = wap_event_create(TR_Result_Cnf);
00672     event->u.TR_Result_Cnf.addr_tuple = 
00673     wap_addr_tuple_duplicate(sm->addr_tuple);
00674     event->u.TR_Result_Cnf.handle = sm->mid;
00675     return event;
00676 }
00677 
00678 /*
00679  * Creates TR-Abort.ind event from a responder state machine. In addition, set
00680  * the responder indication flag.
00681  */
00682 static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason) {
00683     WAPEvent *event;
00684     
00685     event = wap_event_create(TR_Abort_Ind);
00686     event->u.TR_Abort_Ind.abort_code = abort_reason;
00687     event->u.TR_Abort_Ind.addr_tuple = 
00688     wap_addr_tuple_duplicate(sm->addr_tuple);
00689     event->u.TR_Abort_Ind.handle = sm->mid;
00690     event->u.TR_Abort_Ind.ir_flag = RESPONDER_INDICATION;
00691 
00692     return event;
00693 }
00694 
00695 /*
00696  * Start acknowledgement interval timer. Multiply time with
00697  * resp_timer_freq.
00698  */
00699 static void start_timer_A(WTPRespMachine *machine) 
00700 {
00701     WAPEvent *timer_event;
00702 
00703     timer_event = wap_event_create(TimerTO_A);
00704     timer_event->u.TimerTO_A.handle = machine->mid;
00705     gwtimer_start(machine->timer, L_A_WITH_USER_ACK * resp_timer_freq, 
00706                   timer_event);
00707 }
00708 
00709 /*
00710  * Start retry interval timer. Multiply time with resp_timer_freq.
00711  */
00712 static void start_timer_R(WTPRespMachine *machine) 
00713 {
00714     WAPEvent *timer_event;
00715 
00716     timer_event = wap_event_create(TimerTO_R);
00717     timer_event->u.TimerTO_R.handle = machine->mid;
00718     gwtimer_start(machine->timer, L_R_WITH_USER_ACK * resp_timer_freq, 
00719                   timer_event);
00720 }
00721 
00722 /*
00723  * Start segmentation timeout interval timer. Multiply time with
00724  * resp_timer_freq.
00725  */
00726 static void start_timer_W(WTPRespMachine *machine)
00727 {
00728     WAPEvent *timer_event;
00729 
00730     timer_event = wap_event_create(TimerTO_W);
00731     timer_event->u.TimerTO_W.handle = machine->mid;
00732     gwtimer_start(machine->timer, W_WITH_USER_ACK * resp_timer_freq, 
00733                   timer_event);
00734 }
00735 
00736 static void send_abort(WTPRespMachine *machine, long type, long reason)
00737 {
00738     WAPEvent *e;
00739 
00740     e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple);
00741     dispatch_to_wdp(e);
00742 }
00743 
00744 static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag)
00745 {
00746     WAPEvent *e;
00747 
00748     e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple);
00749     dispatch_to_wdp(e);
00750 }
00751 
00752 /* 
00753  * Process incoming event, checking for WTP SAR 
00754  */
00755 static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event) 
00756 {
00757     WAPEvent *e, *orig_event;
00758     int psn;
00759   
00760     orig_event = *event;
00761 
00762     if (orig_event->type == RcvInvoke) { 
00763         if (!orig_event->u.RcvInvoke.ttr || !orig_event->u.RcvInvoke.gtr) { /* SAR */
00764             /* Ericcson set TTR flag even if we have the only part */
00765             if (orig_event->u.RcvInvoke.ttr == 1) {
00766                 return 1; /* Not SAR although TTR flag was set */
00767             } else {
00768                 /* save initial event */
00769                 machine->sar_invoke = wap_event_duplicate(orig_event);
00770 
00771                 /* save data into list with psn = 0 */
00772                 add_sar_transaction(machine, orig_event->u.RcvInvoke.user_data, 0);
00773 
00774                 if (orig_event->u.RcvInvoke.gtr == 1) { /* Need to acknowledge */
00775                     e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid,
00776                                          machine->addr_tuple, 0);
00777                     dispatch_to_wdp(e);
00778                 }
00779                 return 0;
00780             }
00781         } else {
00782             return 1; /* Not SAR */
00783         } 
00784     }
00785 
00786     if (orig_event->type == RcvSegInvoke) {
00787         add_sar_transaction(machine, orig_event->u.RcvSegInvoke.user_data, 
00788                             orig_event->u.RcvSegInvoke.psn);
00789 
00790         if (orig_event->u.RcvSegInvoke.gtr == 1) { /* Need to acknowledge */
00791             e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid, machine->addr_tuple,
00792                                  orig_event->u.RcvSegInvoke.psn);
00793             dispatch_to_wdp(e);
00794         }
00795 
00796         if (orig_event->u.RcvSegInvoke.ttr == 1) { /* Need to feed to WSP */
00797 
00798             /* Create assembled event */
00799             psn = orig_event->u.RcvSegInvoke.psn;
00800             wap_event_destroy(orig_event);
00801       
00802             *event = assembly_sar_event(machine,psn);
00803 
00804             gw_assert(event != NULL);
00805 
00806             return 1;
00807         }
00808         return 0;
00809     }
00810 
00811     /* Not SAR message */
00812     return 1;
00813 }
00814 
00815 static int is_wanted_sar_data(void *a, void *b)
00816 {
00817     sar_info_t *s;
00818     int *i;
00819 
00820     s = a;
00821     i = b;
00822 
00823     if (*i == s->sar_psn) {
00824         return 1;
00825     } else {
00826         return 0;
00827     }
00828 }
00829 
00830 /* 
00831  * Return 0 if transaction added suscessufully, 1 otherwise.
00832  */
00833 static int add_sar_transaction(WTPRespMachine *machine, Octstr *data, int psn) 
00834 {
00835     sar_info_t *sar_info;
00836 
00837     if (machine->sar_info == NULL) {
00838         machine->sar_info = gwlist_create();
00839     }
00840 
00841     if (gwlist_search(machine->sar_info, &psn, is_wanted_sar_data) == NULL) {
00842         sar_info = gw_malloc(sizeof(sar_info_t));
00843         sar_info->sar_psn = psn;
00844         sar_info->sar_data = octstr_duplicate(data);
00845         gwlist_append(machine->sar_info, sar_info);
00846         return 0;
00847     } else {
00848         debug("wap.wtp", 0, "Duplicated psn found, ignore packet");
00849         return 1;
00850     } 
00851 }
00852 
00853 static WAPEvent *assembly_sar_event(WTPRespMachine *machine, int last_psn) 
00854 {
00855     WAPEvent *e;
00856     int i;
00857     sar_info_t *sar_info;
00858 
00859     e = wap_event_duplicate(machine->sar_invoke);
00860 
00861     for (i = 1; i <= last_psn; i++) {
00862         if ((sar_info = gwlist_search(machine->sar_info, &i, is_wanted_sar_data)) != NULL) {
00863             octstr_append(e->u.RcvInvoke.user_data,sar_info->sar_data);
00864         } else {
00865             debug("wap.wtp", 0, "Packet with psn %d not found", i);
00866             return e;
00867         }
00868     }
00869 
00870     return e;
00871 }
00872 
00873 static void sar_info_destroy(void *p) 
00874 {
00875     sar_info_t *sar_info;
00876 
00877     sar_info = p;
00878   
00879     octstr_destroy(sar_info->sar_data);
00880     gw_free(sar_info);
00881 }
00882 
00883 static void sardata_destroy(void *p) 
00884 {
00885     WTPSARData * sardata;
00886 
00887     if (p) {
00888         sardata = p;
00889         octstr_destroy(sardata->data);
00890         gw_free(sardata);
00891     }
00892 }
00893 
00894 static void begin_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) 
00895 {
00896     WAPEvent *result;
00897     WTPSARData *sar;
00898     int psn;
00899 
00900     gw_assert(resp_machine->sar != NULL);
00901 
00902     sar = resp_machine->sar;
00903     sar->data = octstr_duplicate(event->u.TR_Result_Req.user_data);
00904     sar->nsegm = (octstr_len(sar->data)-1)/SAR_SEGM_SIZE;
00905     sar->tr = sar->lsegm = 0;
00906     sar->csegm = -1;
00907 
00908     debug("wap.wtp", 0, "WTP: begin_sar_result(): data len = %lu", 
00909           octstr_len(sar->data));
00910 
00911     for (psn = 0; !sar->tr; psn++) {
00912         result = wtp_pack_sar_result(resp_machine, psn);
00913         if (sar->tr) 
00914             resp_machine->result = wap_event_duplicate(result);
00915 
00916         debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
00917         dispatch_to_wdp(result);
00918         sar->lsegm = psn;
00919     }
00920 
00921     resp_machine->rid = 1;
00922 }
00923 
00924 static void continue_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) 
00925 {
00926     WAPEvent *result;
00927     WTPSARData *sar;
00928     int psn;
00929 
00930     gw_assert(resp_machine->sar != NULL && event->type == RcvAck);
00931 
00932     sar = resp_machine->sar;
00933 
00934     debug("wap.wtp", 0, "WTP: continue_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
00935           sar->lsegm, sar->nsegm, sar->csegm);
00936 
00937     start_timer_R(resp_machine);
00938 
00939     if (event->u.RcvAck.psn>sar->csegm) {
00940         sar->csegm = event->u.RcvAck.psn;
00941     }
00942 
00943     sar->tr = 0;
00944     wap_event_destroy(resp_machine->result);
00945     resp_machine->result = NULL;
00946 
00947     for (psn = sar->csegm + 1; !sar->tr; psn++) {
00948         result = wtp_pack_sar_result(resp_machine, psn);
00949         if (sar->tr) 
00950             resp_machine->result = wap_event_duplicate(result);
00951 
00952         debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u",psn);
00953         dispatch_to_wdp(result);
00954         sar->lsegm = psn;
00955     }
00956 }
00957 
00958 static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
00959 {
00960     WAPEvent *result;
00961     WTPSARData *sar;
00962     int psn, i;
00963 
00964     gw_assert(resp_machine->sar != NULL && event->type == RcvNegativeAck);
00965 
00966     sar = resp_machine->sar;
00967 
00968     debug("wap.wtp", 0, "WTP: resend_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
00969           sar->lsegm, sar->nsegm, sar->csegm);
00970 
00971     start_timer_R(resp_machine);
00972 
00973     if (event->u.RcvNegativeAck.nmissing) { 
00974         /* if we have a list of missed packets */
00975         for(i = 0; i < event->u.RcvNegativeAck.nmissing; i++) {
00976             if ((psn = octstr_get_char(event->u.RcvNegativeAck.missing, i)) >= 0) {     
00977                 result = wtp_pack_sar_result(resp_machine, psn);
00978                 wtp_pack_set_rid(result, 1);
00979                 debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
00980                 dispatch_to_wdp(result);
00981             }
00982         }
00983     } else { 
00984         /* if we have to resend a whole group */
00985         sar->tr = 0;
00986         for (psn = sar->csegm+1; !sar->tr; psn++) {
00987             result = wtp_pack_sar_result(resp_machine, psn);
00988             wtp_pack_set_rid(result, 1);
00989             debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
00990             dispatch_to_wdp(result);
00991         }
00992     }
00993 }
00994 
00995 
00996 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.