Kannel: Open Source WAP and SMS gateway  svn-r5335
wtp_resp_states.def
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 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  * Macro calls to generate rows of the state table. See the documentation for
59  * guidance how to use and update these.
60  *
61  * Macros have following arguments:
62  *
63  * STATE_NAME(name of a wtp machine state)
64  *
65  * ROW(the name of the current state,
66  * the event feeded to wtp machine,
67  * the condition for the action,
68  * {the action itself},
69  * the state wtp machine will transit)
70  *
71  * Condition 1 means that the action will be performed unconditionally, action
72  * {} means that the event in question will be ignored (of course, the state
73  * of the machine can change).
74  *
75  * There are many ROWS generating code for ignoring a certain event (ones hav-
76  * ing {} as their action). In these cases the event in question is caused by a
77  * duplicate message and the first one has already changed wtp responder mach-
78  * ine. In this case ignoring the event is natural.
79  *
80  * State tables use the phrase "abort transaction" many times. In this imple-
81  * mentation this means "clear data structures used for storing transaction
82  * data". This happens in function resp_event_handle, after included state
83  * table code.
84  *
85  * Commenting the state table is perhaps best done by pointing out how various
86  * services provided by WTP contribute rows to the state table.
87  *
88  * Normal transaction goes as follows (timers excluded):
89  * - WTP get an invoke pdu from the peer. WTP does TR-Invoke.ind (trans-
90  * mitting to WSP its PDU) and the state changes to INVOKE_RESP_WAIT
91  * - WSP does TR-Invoke.res, telling that it has handled the
92  * indication.
93  * The state changes to RESULT_WAIT.
94  * - WSP tells that it has results from the content server, or reply
95  * pdu to send. It does TR-Result.req. State changes to
96  * RESULT_RESP_WAIT.
97  * - WTP gets acknowledgement from the peer. It generates TR_Result.cnf
98  * and state changes to LISTEN. The transaction is over.
99  *
100  * Retransmission until acknowledgement guarantees reliability of the trans-
101  * action, if the peer stays up. It is implemented by using retransmissions
102  * controlled by timers and counters. There are two kind of timers, retrans-
103  * mission and acknowledgement timers. (Actually, there is one timer
104  * iniatilised with two intervals. But let us keep the language simple).
105  * These are used in concert with corresponding counters, RCR (retransmission
106  * counter) and AEC (acknowledgement expiration counter). AEC counts expired
107  * acknowledgement intervals.
108  *
109  * WTP starts an acknowledgement timer when it waits a WSP acknowledgement,
110  * and retransmission timer when it sends something. So when the acknowledge_
111  * ment timer expires, the action is to increment AEC, and when the retrans-
112  * mission timer expires, the action is to resend a packet. (Note, however,
113  * the chapter concerning user acknowledgement.)
114  *
115  * WTP ignores invoke pdus having same tid as the current transaction. This
116  * quarantees rejection of the duplicates. Note, however, how reliability is
117  * achieved when WTP is doing tid verification (next chapter).
118  *
119  * Tid verification is done if tid validation fails (which happens when the
120  * message is a duplicate or when tid wrapping-up could confuse the protocol).
121  * In this case, the state changes to TIDOK_WAIT. WSP is indicated only after
122  * an acknowledgement is received. After a negative answer (Abort PDU) the
123  * transaction is teared down. Reliablity is quaranteed by resending, which
124  * happens when WTP receives a resent invoke pdu, when its state TIDOK_WAIT.
125  * Abort pdu now means a negative answer to a question "have you a transaction
126  * having tid included in the tid verification message". So there is no need
127  * to indicate WSP.
128  *
129  * Error handling is mostly done before feeding an event to the state machine.
130  * However, when a pdu with an illegal header (header WTP does not understand)
131  * is received, this is a special kind of event, because its handling depends
132  * of the state. WTP must always send an abort pdu. If a transaction is
133  * established, it must be teared down. If WSP has been indicated about a
134  * transaction, WTP must do TR-Abort.ind.
135  *
136  * There are two kind of aborts: by the peer, when it sends abort pdu and by the
137  * wsp, when it does a primitive TR-Abort.req. When WSP does an abort, WTP
138  * must send an abort pdu to the peer; when WTP receives an abort, WSP must be
139  * indicated (note, however, the special meaning abort pdu has in tid
140  * verification; see the relevant chapter).
141  *
142  * User acknowledgement means that WTP waits WSP (which in most cases is WTP
143  * user) acknowledgement, instead of doing it by itself. This means, that if
144  * user acknowledgement flag is off, WTP sends an ack pdu when acknowledgement
145  * timer expires.
146  *
147  * By Aarno Syvänen for WapIT Ltd.
148  */
149 
150 STATE_NAME(LISTEN)
151 STATE_NAME(TIDOK_WAIT)
152 STATE_NAME(INVOKE_RESP_WAIT)
153 STATE_NAME(RESULT_WAIT)
154 STATE_NAME(RESULT_RESP_WAIT)
155 STATE_NAME(WAIT_TIMEOUT_STATE)
156 
157 ROW(LISTEN,
158  RcvInvoke,
159  (event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) &&
160  wtp_tid_is_valid(event, resp_machine) == ok,
161  {
162  resp_machine->u_ack = event->u.RcvInvoke.up_flag;
163  resp_machine->tcl = event->u.RcvInvoke.tcl;
164 
165  wsp_event = create_tr_invoke_ind(resp_machine,
166  event->u.RcvInvoke.user_data);
167  if (resp_machine->tcl == 1)
168  wsp_push_client_dispatch_event(wsp_event);
169  else
170  wsp_session_dispatch_event(wsp_event);
171 
172  start_timer_A(resp_machine);
173  resp_machine->ack_pdu_sent = 0;
174  },
175  INVOKE_RESP_WAIT)
176 
177 /*
178  * We must here store event fields and wsp indication into the wtp responder
179  * state machine: if tid is valid, we will continue the transaction without a
180  * new event.
181  */
182 ROW(LISTEN,
183  RcvInvoke,
184  (event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) &&
185  (wtp_tid_is_valid(event, resp_machine) == fail ||
186  wtp_tid_is_valid(event, resp_machine) == no_cached_tid),
187  {
188  send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid);
189 
190  resp_machine->u_ack = event->u.RcvInvoke.up_flag;
191  resp_machine->tcl = event->u.RcvInvoke.tcl;
192  resp_machine->invoke_indication = create_tr_invoke_ind(resp_machine,
193  event->u.RcvInvoke.user_data);
194  debug("wap.wtp", 0, "WTP_STATE: generating invoke indication, tid being"
195  "invalid");
196  },
197  TIDOK_WAIT)
198 
199 /*
200  * Do not change state when class 0 message is received.
201  */
202 ROW(LISTEN,
203  RcvInvoke,
204  event->u.RcvInvoke.tcl == 0,
205  {
206  wsp_event = create_tr_invoke_ind(resp_machine,
207  event->u.RcvInvoke.user_data);
208  wsp_session_dispatch_event(wsp_event);
209  },
210  LISTEN)
211 
212 /*
213  * No user indication here: transaction is not yet started.
214  */
215 ROW(LISTEN,
216  RcvErrorPDU,
217  1,
218  {
219  send_abort(resp_machine, PROVIDER, PROTOERR);
220  },
221  LISTEN)
222 
223 /*
224  * Need to control SAR incomplete packets
225  */
226 ROW(LISTEN,
227  TimerTO_W,
228  1,
229  {},
230  LISTEN)
231 
232 /*
233  * We must cache the newly accepted tid item, otherwise every tid after a
234  * suspected one will be validated. We use wsp event stored by the responder
235  * machine.
236  */
237 ROW(TIDOK_WAIT,
238  RcvAck,
239  (resp_machine->tcl == 2 || resp_machine->tcl == 1) &&
240  event->u.RcvAck.tid_ok == 1,
241  {
242  wsp_event = wap_event_duplicate(resp_machine->invoke_indication);
243  if (resp_machine->tcl == 1)
244  wsp_push_client_dispatch_event(wsp_event);
245  else
246  wsp_session_dispatch_event(wsp_event);
247 
248  wtp_tid_set_by_machine(resp_machine, event->u.RcvAck.tid);
249 
250  start_timer_A(resp_machine);
251  resp_machine->ack_pdu_sent = 0;
252  },
253  INVOKE_RESP_WAIT)
254 
255 /*
256  * When we get a negative answer to tid verification, we just abort trans-
257  * action. Because wtp machines are destroyed when their state return to
258  * LISTEN and because no transaction is yet started, there is no need to do
259  * anything here.
260  */
261 ROW(TIDOK_WAIT,
262  RcvAbort,
263  1,
264  { },
265  LISTEN)
266 
267 ROW(TIDOK_WAIT,
268  RcvInvoke,
269  event->u.RcvInvoke.rid == 0,
270  { },
271  TIDOK_WAIT)
272 
273 /*
274  * Because the phone sends invoke again, previous ack was dropped by the
275  * bearer.
276  */
277 ROW(TIDOK_WAIT,
278  RcvInvoke,
279  event->u.RcvInvoke.rid == 1,
280  {
281  send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid);
282  },
283  TIDOK_WAIT)
284 
285 /*
286  * No need for wsp indication: the transaction is not yet started.
287  */
288 ROW(TIDOK_WAIT,
289  RcvErrorPDU,
290  1,
291  {
292  send_abort(resp_machine, PROVIDER, PROTOERR);
293  },
294  LISTEN)
295 
296 ROW(INVOKE_RESP_WAIT,
297  RcvInvoke,
298  1,
299  { },
300  INVOKE_RESP_WAIT)
301 
302 ROW(INVOKE_RESP_WAIT,
303  TR_Invoke_Res,
304  resp_machine->tcl == 2,
305  {
306  start_timer_A(resp_machine);
307  resp_machine->aec = 0;
308  },
309  RESULT_WAIT)
310 
311 ROW(INVOKE_RESP_WAIT,
312  TR_Invoke_Res,
313  resp_machine->tcl == 1,
314  {
315  send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
316  start_timer_W(resp_machine);
317  },
318  WAIT_TIMEOUT_STATE)
319 
320 ROW(INVOKE_RESP_WAIT,
321  RcvAbort,
322  1,
323  {
324  wsp_event = create_tr_abort_ind(resp_machine,
325  event->u.RcvAbort.abort_reason);
326  if (resp_machine->tcl == 1)
327  wsp_push_client_dispatch_event(wsp_event);
328  else
329  wsp_session_dispatch_event(wsp_event);
330  },
331  LISTEN)
332 
333 ROW(INVOKE_RESP_WAIT,
334  TR_Abort_Req,
335  1,
336  {
337  send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
338  },
339  LISTEN)
340 
341 /*
342  * non-SARed
343  */
344 ROW(INVOKE_RESP_WAIT,
345  TR_Result_Req,
346  resp_machine->sar == NULL,
347  {
348  WAPEvent *result;
349 
350  resp_machine->rcr = 0;
351 
352  start_timer_R(resp_machine);
353  wap_event_destroy(resp_machine->result);
354  resp_machine->rid = 0;
355  result = wtp_pack_result(resp_machine, event);
356  resp_machine->result = wap_event_duplicate(result);
357  dispatch_to_wdp(result);
358  resp_machine->rid = 1;
359  },
360  RESULT_RESP_WAIT)
361 
362 /*
363  * SARed
364  */
365 ROW(INVOKE_RESP_WAIT,
366  TR_Result_Req,
367  resp_machine->sar != NULL,
368  {
369  resp_machine->rcr = 0;
370 
371  start_timer_R(resp_machine);
372  wap_event_destroy(resp_machine->result);
373  resp_machine->rid = 0;
374  begin_sar_result(resp_machine, event);
375  },
376  RESULT_RESP_WAIT)
377 
378 /*
379  * Conditions below do not correspond wholly ones found from the spec. (If
380  * they does, user acknowledgement flag would never be used by the protocol,
381  * which cannot be the original intention.)
382  * User acknowledgement flag is used following way: if it is on, WTP does not
383  * send an acknowledgement (user acknowledgement in form of TR-Invoke.res or
384  * TR-Result.req instead of provider acknowledgement is awaited); if it is
385  * off, WTP does this. IMHO, specs support this exegesis: there is condition
386  * Uack == False && class == 2 with action send ack pdu. In addition, WTP
387  * 8.3.1 says " When [user acknowledgement] is enabled WTP provider does not
388  * respond to a received message until after WTP user has confirmed the
389  * indication service primitive by issuing the response primitive".
390  *
391  * BTW: CR correcting this shall appear soonish.
392  */
393 ROW(INVOKE_RESP_WAIT,
394  TimerTO_A,
395  resp_machine->aec < AEC_MAX && resp_machine->u_ack == 1,
396  {
397  ++resp_machine->aec;
398  start_timer_A(resp_machine);
399  },
400  INVOKE_RESP_WAIT)
401 
402 ROW(INVOKE_RESP_WAIT,
403  TimerTO_A,
404  (resp_machine->aec < AEC_MAX && resp_machine->u_ack == 0),
405  {
406  ++resp_machine->aec;
407  start_timer_A(resp_machine);
408  send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
409  if (resp_machine->ack_pdu_sent == 0)
410  resp_machine->ack_pdu_sent = 1;
411  },
412  INVOKE_RESP_WAIT)
413 
414 /*
415  * When a transaction is aborted, WSP must surely know this. One of corrections
416  * in MOT_WTP_CR_01. What to do when a counter reaches its maximum value dep-
417  * ends on whether we have opened the connection or not. In previous case, we
418  * must go to the state WAIT_TIMEOUT_STATE, for instance to prevent bad incarn-
419  * ations.
420  */
421 ROW(INVOKE_RESP_WAIT,
422  TimerTO_A,
423  resp_machine->aec == AEC_MAX && resp_machine->tcl == 2,
424  {
425  send_abort(resp_machine, PROVIDER, NORESPONSE);
426  wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
427  wsp_session_dispatch_event(wsp_event);
428  },
429  LISTEN)
430 
431 ROW(INVOKE_RESP_WAIT,
432  TimerTO_A,
433  resp_machine->aec == AEC_MAX && resp_machine->tcl == 1,
434  {
435  start_timer_W(resp_machine);
436  },
437  WAIT_TIMEOUT_STATE)
438 
439 ROW(INVOKE_RESP_WAIT,
440  RcvErrorPDU,
441  1,
442  {
443  send_abort(resp_machine, PROVIDER, PROTOERR);
444 
445  wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
446  if (resp_machine->tcl == 1)
447  wsp_push_client_dispatch_event(wsp_event);
448  else
449  wsp_session_dispatch_event(wsp_event);
450  },
451  LISTEN)
452 
453 /*
454  * Non-SARed
455  */
456 ROW(RESULT_WAIT,
457  TR_Result_Req,
458  resp_machine->sar == NULL,
459  {
460  WAPEvent *result;
461  resp_machine->rcr = 0;
462 
463  start_timer_R(resp_machine);
464 
465  wap_event_destroy(resp_machine->result);
466  resp_machine->rid = 0;
467  result = wtp_pack_result(resp_machine, event);
468  resp_machine->result = wap_event_duplicate(result);
469  dispatch_to_wdp(result);
470  resp_machine->rid = 1;
471  },
472  RESULT_RESP_WAIT)
473 
474 /*
475  * SARed
476  */
477 ROW(RESULT_WAIT,
478  TR_Result_Req,
479  (resp_machine->sar != NULL) && ((octstr_len(event->u.TR_Result_Req.user_data)-1)/SAR_SEGM_SIZE < 255),
480  {
481  resp_machine->rcr = 0;
482 
483  start_timer_R(resp_machine);
484 
485  wap_event_destroy(resp_machine->result);
486  resp_machine->rid = 0;
487  begin_sar_result(resp_machine, event);
488  },
489  RESULT_RESP_WAIT)
490 
491 ROW(RESULT_WAIT,
492  TR_Result_Req,
493  (resp_machine->sar != NULL) && ((octstr_len(event->u.TR_Result_Req.user_data)-1)/SAR_SEGM_SIZE >= 255),
494  {
495  send_abort(resp_machine, PROVIDER, NOTIMPLEMENTEDESAR);
496  wsp_event = create_tr_abort_ind(resp_machine, NOTIMPLEMENTEDESAR);
497  wsp_session_dispatch_event(wsp_event);
498 
499  wap_event_destroy(resp_machine->result);
500  },
501  LISTEN)
502 
503 ROW(RESULT_WAIT,
504  RcvAbort,
505  1,
506  {
507  wsp_event = create_tr_abort_ind(resp_machine,
508  event->u.RcvAbort.abort_reason);
509  wsp_session_dispatch_event(wsp_event);
510  },
511  LISTEN)
512 
513 ROW(RESULT_WAIT,
514  RcvInvoke,
515  event->u.RcvInvoke.rid == 0,
516  { },
517  RESULT_WAIT)
518 
519 ROW(RESULT_WAIT,
520  RcvInvoke,
521  event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 0,
522  { },
523  RESULT_WAIT)
524 
525 ROW(RESULT_WAIT,
526  RcvInvoke,
527  event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 1,
528  {
529  send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
530  },
531  RESULT_WAIT)
532 
533 ROW(RESULT_WAIT,
534  TR_Abort_Req,
535  1,
536  {
537  send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
538  },
539  LISTEN)
540 
541 ROW(RESULT_WAIT,
542  RcvErrorPDU,
543  1,
544  {
545  send_abort(resp_machine, PROVIDER, PROTOERR);
546 
547  wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
548  wsp_session_dispatch_event(wsp_event);
549  },
550  LISTEN)
551 
552 /*
553  * This state follows two possible ones: INVOKE_RESP_WAIT & TR-Invoke.res and
554  * INVOKE_RESP_WAIT & TimerTO_A & Class == 2 & Uack == FALSE. Contrary what
555  * spec says, in first case we are now sending first time. We must, too, abort
556  * after AEC_MAX timer periods.
557  */
558 ROW(RESULT_WAIT,
559  TimerTO_A,
560  resp_machine->aec < AEC_MAX,
561  {
562  start_timer_A(resp_machine);
563  send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
564  if (resp_machine->ack_pdu_sent == 0)
565  resp_machine->ack_pdu_sent = 1;
566  resp_machine->aec++;
567  },
568  RESULT_WAIT)
569 
570 ROW(RESULT_WAIT,
571  TimerTO_A,
572  resp_machine->aec == AEC_MAX,
573  {
574  send_abort(resp_machine, PROVIDER, NORESPONSE);
575  wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
576  wsp_session_dispatch_event(wsp_event);
577  },
578  LISTEN)
579 
580 /*
581  * A duplicate ack(tidok) caused by a heavy load (the original changed state
582  * from TIDOK_WAIT). This implements CR-Nokia-WTP-20-March-2000/2.
583  */
584 ROW(RESULT_WAIT,
585  RcvAck,
586  event->u.RcvAck.tid_ok,
587  {},
588  RESULT_WAIT)
589 
590 /*
591  * Non-SARed
592  */
593 ROW(RESULT_RESP_WAIT,
594  RcvAck,
595  resp_machine->sar == NULL || event->u.RcvAck.psn == resp_machine->sar->nsegm,
596  {
597  wsp_event = create_tr_result_cnf(resp_machine);
598  wsp_session_dispatch_event(wsp_event);
599  },
600  LISTEN)
601 
602 /*
603  * SARed
604  */
605 ROW(RESULT_RESP_WAIT,
606  RcvAck,
607  resp_machine->sar != NULL && event->u.RcvAck.psn != resp_machine->sar->nsegm,
608  {
609  continue_sar_result(resp_machine, event);
610  },
611  RESULT_RESP_WAIT)
612 
613 ROW(RESULT_RESP_WAIT,
614  RcvNegativeAck,
615  resp_machine->sar != NULL,
616  {
617  resend_sar_result(resp_machine, event);
618  },
619  RESULT_RESP_WAIT)
620 
621 /*
622  * Specs does not tell what to do, when wtp responder receives invoke pdu and
623  * its state is RESULT_RESP_WAIT. This can happen, however: event causing the
624  * transition RESULT_WAIT -> RESULT_RESP_WAIT is TR-Result.req, an internal
625  * responder event.
626  */
627 ROW(RESULT_RESP_WAIT,
628  RcvInvoke,
629  1,
630  { },
631  RESULT_RESP_WAIT)
632 
633 ROW(RESULT_RESP_WAIT,
634  RcvAbort,
635  1,
636  {
637  wsp_event = create_tr_abort_ind(resp_machine,
638  event->u.RcvAbort.abort_reason);
639  wsp_session_dispatch_event(wsp_event);
640  },
641  LISTEN)
642 
643 ROW(RESULT_RESP_WAIT,
644  TR_Abort_Req,
645  1,
646  {
647  send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
648  },
649  LISTEN)
650 
651 ROW(RESULT_RESP_WAIT,
652  TimerTO_R,
653  resp_machine->rcr < MAX_RCR,
654  {
655  WAPEvent *resend;
656 
657  start_timer_R(resp_machine);
658  resend = wap_event_duplicate(resp_machine->result);
659  wtp_pack_set_rid(resend, resp_machine->rid);
660  dispatch_to_wdp(resend);
661  ++resp_machine->rcr;
662  },
663  RESULT_RESP_WAIT)
664 
665 ROW(RESULT_RESP_WAIT,
666  TimerTO_R,
667  resp_machine->rcr == MAX_RCR,
668  {
669  send_abort(resp_machine, PROVIDER, NORESPONSE);
670  wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
671  wsp_session_dispatch_event(wsp_event);
672  },
673  LISTEN)
674 
675 ROW(RESULT_RESP_WAIT,
676  RcvErrorPDU,
677  1,
678  {
679  send_abort(resp_machine, PROVIDER, PROTOERR);
680 
681  wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
682  wsp_session_dispatch_event(wsp_event);
683  },
684  LISTEN)
685 
686 ROW(WAIT_TIMEOUT_STATE,
687  RcvInvoke,
688  event->u.RcvInvoke.rid == 0,
689  { },
690  WAIT_TIMEOUT_STATE)
691 
692 ROW(WAIT_TIMEOUT_STATE,
693  RcvInvoke,
694  event->u.RcvInvoke.rid == 1,
695  {
696  send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
697  },
698  WAIT_TIMEOUT_STATE)
699 
700 ROW(WAIT_TIMEOUT_STATE,
701  RcvErrorPDU,
702  1,
703  {
704  send_abort(resp_machine, PROVIDER, PROTOERR);
705 
706  wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
707  wsp_push_client_dispatch_event(wsp_event);
708  },
709  LISTEN)
710 
711 ROW(WAIT_TIMEOUT_STATE,
712  RcvAbort,
713  1,
714  {
715  wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
716  wsp_push_client_dispatch_event(wsp_event);
717  },
718  LISTEN)
719 
720 /*
721  * Waiting to prevent premature incarnations.
722  */
723 ROW(WAIT_TIMEOUT_STATE,
724  TimerTO_W,
725  1,
726  {
727  wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
728  wsp_push_client_dispatch_event(wsp_event);
729  },
730  LISTEN)
731 
732 ROW(WAIT_TIMEOUT_STATE,
733  TR_Abort_Req,
734  1,
735  {
736  send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
737  },
738  LISTEN)
739 
740 #undef ROW
741 #undef STATE_NAME
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.