Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
wtp_resp.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57  /*
58  * wtp_resp.c - WTP responder implementation
59  *
60  * Aarno Syvšnen
61  * Lars Wirzenius
62  */
63 
64 #include "gwlib/gwlib.h"
65 #include "wtp_resp.h"
66 #include "wtp_pack.h"
67 #include "wtp_tid.h"
68 #include "wtp.h"
69 #include "timers.h"
70 #include "wap.h"
71 
72 /***********************************************************************
73  * Internal data structures.
74  *
75  * List of responder WTP machines.
76  */
77 static List *resp_machines = NULL;
78 
79 
80 /*
81  * Counter for responder WTP machine id numbers, to make sure they are unique.
82  */
84 
85 
86 /*
87  * Give the status of wtp responder:
88  *
89  * limbo
90  * not running at all
91  * running
92  * operating normally
93  * terminating
94  * waiting for operations to terminate, returning to limbo
95  */
97 
98 
102 
103 /*
104  * Queue of events to be handled by WTP responder.
105  */
106 static List *resp_queue = NULL;
107 
108 /*
109  * Timer 'tick'. All wtp responder timer values are multiplies of this one
110  */
111 static long resp_timer_freq = -1;
112 
113 /*****************************************************************************
114  *
115  * Prototypes of internal functions:
116  *
117  * Create and destroy an uniniatilized wtp responder state machine.
118  */
119 
120 static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid,
121  long tcl);
122 static void resp_machine_destroy(void *sm);
123 
124 /*
125  * Checks whether wtp responser machines data structure includes a specific
126  * machine.
127  * The machine in question is identified with with source and destination
128  * address and port and tid. If the machine does not exist and the event is
129  * RcvInvoke, a new machine is created and added in the machines data
130  * structure.
131  * First test incoming events (WTP 10.2) (Exception is tests nro 4 and 5: if
132  * we have a memory error, we panic. Nro 4 is already checked) If event was
133  * validated and If the event was RcvAck or RcvAbort, the event is ignored.
134  * If the event is RcvErrorPDU, new machine is created.
135  */
137 
138 
139 /*
140  * Feed an event to a WTP responder state machine. Handle all errors by
141  * itself, do not report them to the caller. WSP indication or confirmation
142  * is handled by an included state table.
143  */
144 static void resp_event_handle(WTPRespMachine *machine, WAPEvent *event);
145 
146 /*
147  * Print a wtp responder machine state as a string.
148  */
149 static char *name_resp_state(int name);
150 
151 /*
152  * Find the wtp responder machine from the global list of wtp responder
153  * structures that corresponds to the five-tuple of source and destination
154  * addresses and ports and the transaction identifier. Return a pointer to
155  * the machine, or NULL if not found.
156  */
157 static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid,
158  long mid);
159 static void main_thread(void *);
160 
161 /*
162  * Start acknowledgement interval timer
163  */
164 static void start_timer_A(WTPRespMachine *machine);
165 
166 /*
167  * Start retry interval timer
168  */
169 static void start_timer_R(WTPRespMachine *machine);
170 
171 /*
172  * Start timeout interval timer.
173  */
174 static void start_timer_W(WTPRespMachine *machine);
175 static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data);
176 static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason);
178 static int erroneous_field_in(WAPEvent *event);
179 static void handle_wrong_version(WAPEvent *event);
180 
181 /*
182  * SAR related functions.
183  */
184 static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn);
185 static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn);
186 /* static int is_wanted_sar_data (void *a, void *b); */
187 static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event);
188 static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event);
189 static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event);
190 static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event);
191 static void sar_info_destroy(void *sar_info);
192 static void sardata_destroy(void *sardata);
193 
194 /*
195  * Create a datagram with an Abort PDU and send it to the WDP layer.
196  */
197 static void send_abort(WTPRespMachine *machine, long type, long reason);
198 
199 /*
200  * Create a datagram with an Ack PDU and send it to the WDP layer.
201  */
202 static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag);
203 
204 
205 /******************************************************************************
206  *
207  * EXTERNAL FUNCTIONS:
208  *
209  */
210 
211 void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch,
212  wap_dispatch_func_t *session_dispatch,
213  wap_dispatch_func_t *push_dispatch,
214  long timer_freq)
215 {
216  resp_machines = gwlist_create();
217  resp_machine_id_counter = counter_create();
218 
219  resp_queue = gwlist_create();
220  gwlist_add_producer(resp_queue);
221 
222  dispatch_to_wdp = datagram_dispatch;
223  dispatch_to_wsp = session_dispatch;
224  dispatch_to_push = push_dispatch;
225 
226  timers_init();
229 
233 }
234 
235 void wtp_resp_shutdown(void)
236 {
239  gwlist_remove_producer(resp_queue);
241 
242  debug("wap.wtp", 0, "wtp_resp_shutdown: %ld resp_machines left",
243  gwlist_len(resp_machines));
244  gwlist_destroy(resp_machines, resp_machine_destroy);
246 
247  counter_destroy(resp_machine_id_counter);
248 
250  timers_shutdown();
251 }
252 
254 {
255  gwlist_produce(resp_queue, event);
256 }
257 
258 
259 /*****************************************************************************
260  *
261  * INTERNAL FUNCTIONS:
262  *
263  */
264 
265 static void main_thread(void *arg)
266 {
267  WTPRespMachine *sm;
268  WAPEvent *e;
269 
270  while (resp_run_status == running &&
271  (e = gwlist_consume(resp_queue)) != NULL) {
272 
274  if (sm == NULL) {
276  } else {
277  resp_event_handle(sm, e);
278  }
279  }
280 }
281 
282 /*
283  * Give the name of a responder state in a readable form.
284  */
285 static char *name_resp_state(int s)
286 {
287  switch (s) {
288  #define STATE_NAME(state) case state: return #state;
289  #define ROW(state, event, condition, action, new_state)
290  #include "wtp_resp_states.def"
291  default:
292  return "unknown state";
293  }
294 }
295 
296 
297 /*
298  * Feed an event to a WTP responder state machine. Handle all errors yourself,
299  * do not report them to the caller. Note: Do not put {}s of the else block
300  * inside the macro definition.
301  */
302 static void resp_event_handle(WTPRespMachine *resp_machine, WAPEvent *event)
303 {
304  WAPEvent *wsp_event = NULL;
305 
306  /*
307  * We don't feed sar packets into state machine
308  * until we got the whole message
309  */
310  if (process_sar_transaction(resp_machine,&event) == 0) {
311  debug("wap.wtp", 0, "SAR event received, wait for continue");
312  /* For removing state machine in case of incomplete sar */
313  start_timer_W(resp_machine);
314  if (event != NULL) {
315  wap_event_destroy(event);
316  }
317  return;
318  }
319 
320  debug("wap.wtp", 0, "WTP: resp_machine %ld, state %s, event %s.",
321  resp_machine->mid,
322  name_resp_state(resp_machine->state),
323  wap_event_name(event->type));
324 
325  #define STATE_NAME(state)
326  #define ROW(wtp_state, event_type, condition, action, next_state) \
327  if (resp_machine->state == wtp_state && \
328  event->type == event_type && \
329  (condition)) { \
330  action \
331  resp_machine->state = next_state; \
332  debug("wap.wtp", 0, "WTP %ld: New state %s", resp_machine->mid, #next_state); \
333  } else
334  #include "wtp_resp_states.def"
335  {
336  error(0, "WTP: handle_event: unhandled event!");
337  debug("wap.wtp", 0, "WTP: handle_event: Unhandled event was:");
338  wap_event_dump(event);
339  wap_event_destroy(event);
340  return;
341  }
342 
343  if (event != NULL) {
344  wap_event_destroy(event);
345  }
346 
347  if (resp_machine->state == LISTEN)
348  resp_machine_destroy(resp_machine);
349 }
350 
351 static void handle_wrong_version(WAPEvent *event)
352 {
353  WAPEvent *ab;
354 
355  if (event->type == RcvInvoke) {
356  ab = wtp_pack_abort(PROVIDER, WTPVERSIONZERO, event->u.RcvInvoke.tid,
357  event->u.RcvInvoke.addr_tuple);
358  dispatch_to_wdp(ab);
359  }
360 }
361 
362 /*
363  * Check for features 7 and 9 in WTP 10.2.
364  */
365 static int erroneous_field_in(WAPEvent *event)
366 {
367  return event->type == RcvInvoke && event->u.RcvInvoke.version != 0;
368 }
369 
370 /*
371  * React features 7 and 9 in WTP 10.2, by aborting with an appropiate error
372  * message.
373  */
375 {
376  if (event->type == RcvInvoke) {
377  if (event->u.RcvInvoke.version != 0) {
378  debug("wap.wtp_resp", 0, "WTP_RESP: wrong version, aborting"
379  "transaction");
380  handle_wrong_version(event);
381  }
382  }
383 }
384 
385 /*
386  * Checks whether wtp machines data structure includes a specific machine.
387  * The machine in question is identified with with source and destination
388  * address and port and tid. First test incoming events (WTP 10.2)
389  * (Exception is tests nro 4 and 5: if we have a memory error, we panic. Nro 5
390  * is already checked) If event was validated and if the machine does not
391  * exist and the event is RcvInvoke, a new machine is created and added in
392  * the machines data structure. If the event was RcvAck or RcvAbort, the
393  * event is ignored (test nro 3). If the event is RcvErrorPDU (test nro 4)
394  * new machine is created for handling this event. If the event is one of WSP
395  * primitives, we have an error.
396  */
398 {
399  WTPRespMachine *resp_machine = NULL;
400  long tid, mid;
401  WAPAddrTuple *tuple;
402 
403  tid = -1;
404  tuple = NULL;
405  mid = -1;
406 
407  switch (event->type) {
408  case RcvInvoke:
409  /* check if erroneous fields are given */
410  if (erroneous_field_in(event)) {
412  return NULL;
413  } else {
414  tid = event->u.RcvInvoke.tid;
415  tuple = event->u.RcvInvoke.addr_tuple;
416  }
417  break;
418 
419  case RcvSegInvoke:
420  tid = event->u.RcvSegInvoke.tid;
421  tuple = event->u.RcvSegInvoke.addr_tuple;
422  break;
423 
424  case RcvAck:
425  tid = event->u.RcvAck.tid;
426  tuple = event->u.RcvAck.addr_tuple;
427  break;
428 
429  case RcvNegativeAck:
430  tid = event->u.RcvAck.tid;
431  tuple = event->u.RcvAck.addr_tuple;
432  break;
433 
434  case RcvAbort:
435  tid = event->u.RcvAbort.tid;
436  tuple = event->u.RcvAbort.addr_tuple;
437  break;
438 
439  case RcvErrorPDU:
440  tid = event->u.RcvErrorPDU.tid;
441  tuple = event->u.RcvErrorPDU.addr_tuple;
442  break;
443 
444  case TR_Invoke_Res:
445  mid = event->u.TR_Invoke_Res.handle;
446  break;
447 
448  case TR_Result_Req:
449  mid = event->u.TR_Result_Req.handle;
450  break;
451 
452  case TR_Abort_Req:
453  mid = event->u.TR_Abort_Req.handle;
454  break;
455 
456  case TimerTO_A:
457  mid = event->u.TimerTO_A.handle;
458  break;
459 
460  case TimerTO_R:
461  mid = event->u.TimerTO_R.handle;
462  break;
463 
464  case TimerTO_W:
465  mid = event->u.TimerTO_W.handle;
466  break;
467 
468  default:
469  debug("wap.wtp", 0, "WTP: resp_machine_find_or_create:"
470  "unhandled event");
471  wap_event_dump(event);
472  return NULL;
473  }
474 
475  gw_assert(tuple != NULL || mid != -1);
476  resp_machine = resp_machine_find(tuple, tid, mid);
477 
478  if (resp_machine == NULL){
479 
480  switch (event->type) {
481 
482  /*
483  * When PDU with an illegal header is received, its tcl-field is
484  * irrelevant and possibly meaningless). In this case we must create
485  * a new machine, if there is any. There is a machine for all events
486  * handled stateful manner.
487  */
488  case RcvErrorPDU:
489  debug("wap.wtp_resp", 0, "an erronous pdu received");
490  wap_event_dump(event);
491  resp_machine = resp_machine_create(tuple, tid,
492  event->u.RcvInvoke.tcl);
493  break;
494 
495  case RcvInvoke:
496  resp_machine = resp_machine_create(tuple, tid,
497  event->u.RcvInvoke.tcl);
498  /* if SAR requested */
499  if (!event->u.RcvInvoke.gtr || !event->u.RcvInvoke.ttr) {
500  resp_machine->sar = gw_malloc(sizeof(WTPSARData));
501  resp_machine->sar->nsegm = 0;
502  resp_machine->sar->csegm = 0;
503  resp_machine->sar->lsegm = 0;
504  resp_machine->sar->data = NULL;
505  }
506 
507  break;
508 
509  case RcvSegInvoke:
510  info(0, "WTP_RESP: resp_machine_find_or_create:"
511  " segmented invoke received, yet having no machine");
512  break;
513 
514  /*
515  * This and the following branch implement test nro 3 in WTP 10.2.
516  */
517  case RcvAck:
518  info(0, "WTP_RESP: resp_machine_find_or_create:"
519  " ack received, yet having no machine");
520  break;
521 
522  case RcvNegativeAck:
523  info(0, "WTP_RESP: resp_machine_find_or_create:"
524  " negative ack received, yet having no machine");
525  break;
526 
527  case RcvAbort:
528  info(0, "WTP_RESP: resp_machine_find_or_create:"
529  " abort received, yet having no machine");
530  break;
531 
532  case TR_Invoke_Res:
533  case TR_Result_Req:
534  case TR_Abort_Req:
535  error(0, "WTP_RESP: resp_machine_find_or_create: WSP primitive to"
536  " a wrong WTP machine");
537  break;
538 
539  case TimerTO_A:
540  case TimerTO_R:
541  case TimerTO_W:
542  error(0, "WTP_RESP: resp_machine_find_or_create: timer event"
543  " without a corresponding machine");
544  break;
545 
546  default:
547  error(0, "WTP_RESP: resp_machine_find_or_create: unhandled event");
548  wap_event_dump(event);
549  break;
550  }
551  } /* if machine == NULL */
552  return resp_machine;
553 }
554 
555 static int is_wanted_resp_machine(void *a, void *b)
556 {
557  machine_pattern *pat;
558  WTPRespMachine *m;
559 
560  m = a;
561  pat = b;
562 
563  if (m->mid == pat->mid)
564  return 1;
565 
566  if (pat->mid != -1)
567  return 0;
568 
569  return m->tid == pat->tid &&
570  wap_addr_tuple_same(m->addr_tuple, pat->tuple);
571 }
572 
573 
575  long mid)
576 {
577  machine_pattern pat;
578  WTPRespMachine *m;
579 
580  pat.tuple = tuple;
581  pat.tid = tid;
582  pat.mid = mid;
583 
584  m = gwlist_search(resp_machines, &pat, is_wanted_resp_machine);
585  return m;
586 }
587 
588 
590  long tcl)
591 {
592  WTPRespMachine *resp_machine;
593 
594  resp_machine = gw_malloc(sizeof(WTPRespMachine));
595 
596  #define ENUM(name) resp_machine->name = LISTEN;
597  #define EVENT(name) resp_machine->name = NULL;
598  #define INTEGER(name) resp_machine->name = 0;
599  #define TIMER(name) resp_machine->name = gwtimer_create(resp_queue);
600  #define ADDRTUPLE(name) resp_machine->name = NULL;
601  #define LIST(name) resp_machine->name = NULL;
602  #define SARDATA(name) resp_machine->name = NULL;
603  #define MACHINE(field) field
604  #include "wtp_resp_machine.def"
605 
606  gwlist_append(resp_machines, resp_machine);
607 
608  resp_machine->mid = counter_increase(resp_machine_id_counter);
609  resp_machine->addr_tuple = wap_addr_tuple_duplicate(tuple);
610  resp_machine->tid = tid;
611  resp_machine->tcl = tcl;
612 
613  debug("wap.wtp", 0, "WTP: Created WTPRespMachine %p (%ld)",
614  (void *) resp_machine, resp_machine->mid);
615 
616  return resp_machine;
617 }
618 
619 
620 /*
621  * Destroys a WTPRespMachine. Assumes it is safe to do so. Assumes it has
622  * already been deleted from the machines list.
623  */
624 static void resp_machine_destroy(void * p)
625 {
626  WTPRespMachine *resp_machine;
627 
628  resp_machine = p;
629  debug("wap.wtp", 0, "WTP: Destroying WTPRespMachine %p (%ld)",
630  (void *) resp_machine, resp_machine->mid);
631 
632  gwlist_delete_equal(resp_machines, resp_machine);
633 
634  #define ENUM(name) resp_machine->name = LISTEN;
635  #define EVENT(name) wap_event_destroy(resp_machine->name);
636  #define INTEGER(name) resp_machine->name = 0;
637  #define TIMER(name) gwtimer_destroy(resp_machine->name);
638  #define ADDRTUPLE(name) wap_addr_tuple_destroy(resp_machine->name);
639  #define LIST(name) gwlist_destroy(resp_machine->name,sar_info_destroy);
640  #define SARDATA(name) sardata_destroy(resp_machine->name);
641  #define MACHINE(field) field
642  #include "wtp_resp_machine.def"
643  gw_free(resp_machine);
644 }
645 
646 /*
647  * Create a TR-Invoke.ind event.
648  */
650 {
651  WAPEvent *event;
652 
653  event = wap_event_create(TR_Invoke_Ind);
654  event->u.TR_Invoke_Ind.ack_type = sm->u_ack;
655  event->u.TR_Invoke_Ind.user_data = octstr_duplicate(user_data);
656  event->u.TR_Invoke_Ind.tcl = sm->tcl;
657  event->u.TR_Invoke_Ind.addr_tuple =
658  wap_addr_tuple_duplicate(sm->addr_tuple);
659  event->u.TR_Invoke_Ind.handle = sm->mid;
660  return event;
661 }
662 
663 
664 /*
665  * Create a TR-Result.cnf event.
666  */
668 {
669  WAPEvent *event;
670 
671  event = wap_event_create(TR_Result_Cnf);
672  event->u.TR_Result_Cnf.addr_tuple =
673  wap_addr_tuple_duplicate(sm->addr_tuple);
674  event->u.TR_Result_Cnf.handle = sm->mid;
675  return event;
676 }
677 
678 /*
679  * Creates TR-Abort.ind event from a responder state machine. In addition, set
680  * the responder indication flag.
681  */
682 static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason) {
683  WAPEvent *event;
684 
685  event = wap_event_create(TR_Abort_Ind);
686  event->u.TR_Abort_Ind.abort_code = abort_reason;
687  event->u.TR_Abort_Ind.addr_tuple =
688  wap_addr_tuple_duplicate(sm->addr_tuple);
689  event->u.TR_Abort_Ind.handle = sm->mid;
690  event->u.TR_Abort_Ind.ir_flag = RESPONDER_INDICATION;
691 
692  return event;
693 }
694 
695 /*
696  * Start acknowledgement interval timer. Multiply time with
697  * resp_timer_freq.
698  */
699 static void start_timer_A(WTPRespMachine *machine)
700 {
701  WAPEvent *timer_event;
702 
703  timer_event = wap_event_create(TimerTO_A);
704  timer_event->u.TimerTO_A.handle = machine->mid;
706  timer_event);
707 }
708 
709 /*
710  * Start retry interval timer. Multiply time with resp_timer_freq.
711  */
712 static void start_timer_R(WTPRespMachine *machine)
713 {
714  WAPEvent *timer_event;
715 
716  timer_event = wap_event_create(TimerTO_R);
717  timer_event->u.TimerTO_R.handle = machine->mid;
719  timer_event);
720 }
721 
722 /*
723  * Start segmentation timeout interval timer. Multiply time with
724  * resp_timer_freq.
725  */
726 static void start_timer_W(WTPRespMachine *machine)
727 {
728  WAPEvent *timer_event;
729 
730  timer_event = wap_event_create(TimerTO_W);
731  timer_event->u.TimerTO_W.handle = machine->mid;
732  gwtimer_start(machine->timer, W_WITH_USER_ACK * resp_timer_freq,
733  timer_event);
734 }
735 
736 static void send_abort(WTPRespMachine *machine, long type, long reason)
737 {
738  WAPEvent *e;
739 
740  e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple);
741  dispatch_to_wdp(e);
742 }
743 
744 static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag)
745 {
746  WAPEvent *e;
747 
748  e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple);
749  dispatch_to_wdp(e);
750 }
751 
752 /*
753  * Process incoming event, checking for WTP SAR
754  */
755 static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event)
756 {
757  WAPEvent *e, *orig_event;
758  int psn;
759 
760  orig_event = *event;
761 
762  if (orig_event->type == RcvInvoke) {
763  if (!orig_event->u.RcvInvoke.ttr || !orig_event->u.RcvInvoke.gtr) { /* SAR */
764  /* Ericcson set TTR flag even if we have the only part */
765  if (orig_event->u.RcvInvoke.ttr == 1) {
766  return 1; /* Not SAR although TTR flag was set */
767  } else {
768  /* save initial event */
769  machine->sar_invoke = wap_event_duplicate(orig_event);
770 
771  /* save data into list with psn = 0 */
772  add_sar_transaction(machine, orig_event->u.RcvInvoke.user_data, 0);
773 
774  if (orig_event->u.RcvInvoke.gtr == 1) { /* Need to acknowledge */
775  e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid,
776  machine->addr_tuple, 0);
777  dispatch_to_wdp(e);
778  }
779  return 0;
780  }
781  } else {
782  return 1; /* Not SAR */
783  }
784  }
785 
786  if (orig_event->type == RcvSegInvoke) {
787  add_sar_transaction(machine, orig_event->u.RcvSegInvoke.user_data,
788  orig_event->u.RcvSegInvoke.psn);
789 
790  if (orig_event->u.RcvSegInvoke.gtr == 1) { /* Need to acknowledge */
791  e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid, machine->addr_tuple,
792  orig_event->u.RcvSegInvoke.psn);
793  dispatch_to_wdp(e);
794  }
795 
796  if (orig_event->u.RcvSegInvoke.ttr == 1) { /* Need to feed to WSP */
797 
798  /* Create assembled event */
799  psn = orig_event->u.RcvSegInvoke.psn;
800  wap_event_destroy(orig_event);
801 
802  *event = assembly_sar_event(machine,psn);
803 
804  gw_assert(event != NULL);
805 
806  return 1;
807  }
808  return 0;
809  }
810 
811  /* Not SAR message */
812  return 1;
813 }
814 
815 static int is_wanted_sar_data(void *a, void *b)
816 {
817  sar_info_t *s;
818  int *i;
819 
820  s = a;
821  i = b;
822 
823  if (*i == s->sar_psn) {
824  return 1;
825  } else {
826  return 0;
827  }
828 }
829 
830 /*
831  * Return 0 if transaction added suscessufully, 1 otherwise.
832  */
833 static int add_sar_transaction(WTPRespMachine *machine, Octstr *data, int psn)
834 {
835  sar_info_t *sar_info;
836 
837  if (machine->sar_info == NULL) {
838  machine->sar_info = gwlist_create();
839  }
840 
841  if (gwlist_search(machine->sar_info, &psn, is_wanted_sar_data) == NULL) {
842  sar_info = gw_malloc(sizeof(sar_info_t));
843  sar_info->sar_psn = psn;
844  sar_info->sar_data = octstr_duplicate(data);
845  gwlist_append(machine->sar_info, sar_info);
846  return 0;
847  } else {
848  debug("wap.wtp", 0, "Duplicated psn found, ignore packet");
849  return 1;
850  }
851 }
852 
853 static WAPEvent *assembly_sar_event(WTPRespMachine *machine, int last_psn)
854 {
855  WAPEvent *e;
856  int i;
857  sar_info_t *sar_info;
858 
859  e = wap_event_duplicate(machine->sar_invoke);
860 
861  for (i = 1; i <= last_psn; i++) {
862  if ((sar_info = gwlist_search(machine->sar_info, &i, is_wanted_sar_data)) != NULL) {
863  octstr_append(e->u.RcvInvoke.user_data,sar_info->sar_data);
864  } else {
865  debug("wap.wtp", 0, "Packet with psn %d not found", i);
866  return e;
867  }
868  }
869 
870  return e;
871 }
872 
873 static void sar_info_destroy(void *p)
874 {
875  sar_info_t *sar_info;
876 
877  sar_info = p;
878 
879  octstr_destroy(sar_info->sar_data);
880  gw_free(sar_info);
881 }
882 
883 static void sardata_destroy(void *p)
884 {
885  WTPSARData * sardata;
886 
887  if (p) {
888  sardata = p;
889  octstr_destroy(sardata->data);
890  gw_free(sardata);
891  }
892 }
893 
894 static void begin_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
895 {
896  WAPEvent *result;
897  WTPSARData *sar;
898  int psn;
899 
900  gw_assert(resp_machine->sar != NULL);
901 
902  sar = resp_machine->sar;
903  sar->data = octstr_duplicate(event->u.TR_Result_Req.user_data);
904  sar->nsegm = (octstr_len(sar->data)-1)/SAR_SEGM_SIZE;
905  sar->tr = sar->lsegm = 0;
906  sar->csegm = -1;
907 
908  debug("wap.wtp", 0, "WTP: begin_sar_result(): data len = %lu",
909  octstr_len(sar->data));
910 
911  for (psn = 0; !sar->tr; psn++) {
912  result = wtp_pack_sar_result(resp_machine, psn);
913  if (sar->tr)
914  resp_machine->result = wap_event_duplicate(result);
915 
916  debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
917  dispatch_to_wdp(result);
918  sar->lsegm = psn;
919  }
920 
921  resp_machine->rid = 1;
922 }
923 
924 static void continue_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
925 {
926  WAPEvent *result;
927  WTPSARData *sar;
928  int psn;
929 
930  gw_assert(resp_machine->sar != NULL && event->type == RcvAck);
931 
932  sar = resp_machine->sar;
933 
934  debug("wap.wtp", 0, "WTP: continue_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
935  sar->lsegm, sar->nsegm, sar->csegm);
936 
937  start_timer_R(resp_machine);
938 
939  if (event->u.RcvAck.psn>sar->csegm) {
940  sar->csegm = event->u.RcvAck.psn;
941  }
942 
943  sar->tr = 0;
944  wap_event_destroy(resp_machine->result);
945  resp_machine->result = NULL;
946 
947  for (psn = sar->csegm + 1; !sar->tr; psn++) {
948  result = wtp_pack_sar_result(resp_machine, psn);
949  if (sar->tr)
950  resp_machine->result = wap_event_duplicate(result);
951 
952  debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u",psn);
953  dispatch_to_wdp(result);
954  sar->lsegm = psn;
955  }
956 }
957 
958 static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
959 {
960  WAPEvent *result;
961  WTPSARData *sar;
962  int psn, i;
963 
964  gw_assert(resp_machine->sar != NULL && event->type == RcvNegativeAck);
965 
966  sar = resp_machine->sar;
967 
968  debug("wap.wtp", 0, "WTP: resend_sar_result(): lsegm=%d, nsegm=%d, csegm=%d",
969  sar->lsegm, sar->nsegm, sar->csegm);
970 
971  start_timer_R(resp_machine);
972 
973  if (event->u.RcvNegativeAck.nmissing) {
974  /* if we have a list of missed packets */
975  for(i = 0; i < event->u.RcvNegativeAck.nmissing; i++) {
976  if ((psn = octstr_get_char(event->u.RcvNegativeAck.missing, i)) >= 0) {
977  result = wtp_pack_sar_result(resp_machine, psn);
978  wtp_pack_set_rid(result, 1);
979  debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
980  dispatch_to_wdp(result);
981  }
982  }
983  } else {
984  /* if we have to resend a whole group */
985  sar->tr = 0;
986  for (psn = sar->csegm+1; !sar->tr; psn++) {
987  result = wtp_pack_sar_result(resp_machine, psn);
988  wtp_pack_set_rid(result, 1);
989  debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn);
990  dispatch_to_wdp(result);
991  }
992  }
993 }
994 
995 
996 
static void sardata_destroy(void *sardata)
Definition: wtp_resp.c:883
static WAPEvent * create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data)
Definition: wtp_resp.c:649
void error(int err, const char *fmt,...)
Definition: log.c:612
WAPEvent * wtp_pack_sar_result(WTPRespMachine *machine, int psn)
Definition: wtp_pack.c:167
void info(int err, const char *fmt,...)
Definition: log.c:636
static WTPRespMachine * resp_machine_create(WAPAddrTuple *tuple, long tid, long tcl)
Definition: wtp_resp.c:589
static void handle_wrong_version(WAPEvent *event)
Definition: wtp_resp.c:351
static int is_wanted_sar_data(void *a, void *b)
Definition: wtp_resp.c:815
void * gwlist_search(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:486
static void send_abort(WTPRespMachine *machine, long type, long reason)
Definition: wtp_resp.c:736
void counter_destroy(Counter *counter)
Definition: counter.c:110
void gwlist_append(List *list, void *item)
Definition: list.c:179
long tid
Definition: wtp.h:190
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
void gwlist_produce(List *list, void *item)
Definition: list.c:411
Octstr * sar_data
Definition: wtp_resp.h:74
long gwlist_len(List *list)
Definition: list.c:166
static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event)
Definition: wtp_resp.c:755
static WTPRespMachine * resp_machine_find_or_create(WAPEvent *event)
Definition: wtp_resp.c:397
void wtp_resp_shutdown(void)
Definition: wtp_resp.c:235
void wtp_pack_set_rid(WAPEvent *dgram, long rid)
Definition: wtp_pack.c:215
static void start_timer_W(WTPRespMachine *machine)
Definition: wtp_resp.c:726
int type
Definition: smsc_cimd2.c:215
wap_dispatch_func_t * dispatch_to_wdp
Definition: wtp_resp.c:99
int csegm
Definition: wtp_resp.h:83
static WTPRespMachine * resp_machine_find(WAPAddrTuple *tuple, long tid, long mid)
Definition: wtp_resp.c:574
void wap_event_dump(WAPEvent *event)
Definition: wap_events.c:181
void gwthread_join_every(gwthread_func_t *func)
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
WAPAddrTuple * wap_addr_tuple_duplicate(WAPAddrTuple *tuple)
Definition: wap_addr.c:125
WAPEvent * wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn)
Definition: wtp_pack.c:263
WAPAddrTuple * tuple
Definition: wtp.h:189
void wtp_tid_cache_init(void)
Definition: wtp_tid.c:102
static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event)
Definition: wtp_resp.c:958
unsigned long mid
Definition: wtp_resp.h:116
static void resp_event_handle(WTPRespMachine *machine, WAPEvent *event)
Definition: wtp_resp.c:302
static Counter * resp_machine_id_counter
Definition: wtp_resp.c:83
#define SAR_SEGM_SIZE
Definition: fakewap.c:221
static void main_thread(void *)
Definition: wtp_resp.c:265
T DUnitdata TR Invoke TR Invoke TR Result TR Abort S Connect S Suspend S Resume S Suspend S Resume S Disconnect S MethodInvoke S MethodInvoke S MethodResult S MethodInvoke S MethodResult S MethodAbort S Push S ConfirmedPush S ConfirmedPush S PushAbort RcvAck
Definition: wap_events.h:532
static WAPEvent * assembly_sar_event(WTPRespMachine *machine, int last_psn)
Definition: wtp_resp.c:853
Counter * counter_create(void)
Definition: counter.c:94
void gwtimer_start(Timer *timer, int interval, WAPEvent *event)
Definition: timers.c:254
void gwlist_remove_producer(List *list)
Definition: list.c:401
static int add_sar_transaction(WTPRespMachine *machine, Octstr *data, int psn)
Definition: wtp_resp.c:833
static void start_timer_R(WTPRespMachine *machine)
Definition: wtp_resp.c:712
static WAPEvent * create_tr_abort_ind(WTPRespMachine *sm, long abort_reason)
Definition: wtp_resp.c:682
void wtp_resp_dispatch_event(WAPEvent *event)
Definition: wtp_resp.c:253
void wap_event_destroy_item(void *event)
Definition: wap_events.c:130
static int is_wanted_resp_machine(void *a, void *b)
Definition: wtp_resp.c:555
int nsegm
Definition: wtp_resp.h:82
#define octstr_duplicate(ostr)
Definition: octstr.h:187
wap_dispatch_func_t * dispatch_to_push
Definition: wtp_resp.c:101
const char * wap_event_name(WAPEventName type)
Definition: wap_events.c:169
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
long mid
Definition: wtp.h:191
Octstr * data
Definition: wtp_resp.h:86
char * name
Definition: smsc_cimd2.c:212
#define wap_event_create(type)
Definition: wap_events.h:107
Definition: wtp.h:124
void timers_shutdown(void)
Definition: timers.c:196
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static void resp_machine_destroy(void *sm)
Definition: wtp_resp.c:624
static long resp_timer_freq
Definition: wtp_resp.c:111
#define gwthread_create(func, arg)
Definition: gwthread.h:90
static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag)
Definition: wtp_resp.c:744
gw_assert(wtls_machine->packet_to_send!=NULL)
static List * resp_queue
Definition: wtp_resp.c:106
void timers_init(void)
Definition: timers.c:184
static char * name_resp_state(int name)
Definition: wtp_resp.c:285
void wtp_tid_cache_shutdown(void)
Definition: wtp_tid.c:107
static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event)
Definition: wtp_resp.c:894
int sar_psn
Definition: wtp_resp.h:73
Definition: wtp_resp.c:96
WAPEvent * wtp_pack_ack(long ack_type, int rid_flag, long tid, WAPAddrTuple *address)
Definition: wtp_pack.c:243
static int erroneous_field_in(WAPEvent *event)
Definition: wtp_resp.c:365
WAPEvent * wap_event_duplicate(WAPEvent *event)
Definition: wap_events.c:135
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
T DUnitdata TR Invoke TR Invoke TR Result TR Abort S Connect S Suspend S Resume S Suspend S Resume S Disconnect S MethodInvoke S MethodInvoke S MethodResult S MethodInvoke S MethodResult S MethodAbort S Push S ConfirmedPush S ConfirmedPush S PushAbort RcvInvoke
Definition: wap_events.h:491
int wap_addr_tuple_same(WAPAddrTuple *a, WAPAddrTuple *b)
Definition: wap_addr.c:118
Definition: octstr.c:118
void * gwlist_consume(List *list)
Definition: list.c:427
int tr
Definition: wtp_resp.h:85
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static WAPEvent * create_tr_result_cnf(WTPRespMachine *sm)
Definition: wtp_resp.c:667
static List * resp_machines
Definition: wtp_resp.c:77
WAPEventName type
Definition: wap_events.h:88
void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *session_dispatch, wap_dispatch_func_t *push_dispatch, long timer_freq)
Definition: wtp_resp.c:211
WAPEvent * wtp_pack_abort(long abort_type, long abort_reason, long tid, WAPAddrTuple *address)
Definition: wtp_pack.c:223
#define gwlist_create()
Definition: list.h:136
static void handle_erroneous_field_in(WAPEvent *event)
Definition: wtp_resp.c:374
static void start_timer_A(WTPRespMachine *machine)
Definition: wtp_resp.c:699
static enum @108 resp_run_status
void gwlist_add_producer(List *list)
Definition: list.c:383
union WAPEvent::@87 u
int lsegm
Definition: wtp_resp.h:84
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
Definition: list.c:102
static void sar_info_destroy(void *sar_info)
Definition: wtp_resp.c:873
void wap_event_destroy(WAPEvent *event)
Definition: wap_events.c:102
void wap_dispatch_func_t(WAPEvent *event)
Definition: wap.h:85
static long timer_freq
Definition: wapbox.c:104
wap_dispatch_func_t * dispatch_to_wsp
Definition: wtp_resp.c:100
static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event)
Definition: wtp_resp.c:924
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.