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

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * Macro calls to generate rows of the state table. See the documentation for
  3.  * guidance how to use and update these. 
  4.  *
  5.  * Macros have following arguments:
  6.  *
  7.  * STATE_NAME(name of a wtp machine state)
  8.  *
  9.  * ROW(the name of the current state,
  10.  *     the event feeded to wtp machine,
  11.  *     the condition for the action,
  12.  *     {the action itself},
  13.  *     the state wtp machine will transit)
  14.  *
  15.  * Condition 1 means that the action will be performed unconditionally, action
  16.  * {} means that the event in question will be ignored (of course, the state 
  17.  * of the machine can change). 
  18.  *
  19.  * There are many ROWS generating code for ignoring a certain event (ones hav-
  20.  * ing {} as their action). In these cases the event in question is caused by a
  21.  * duplicate message and the first one has already changed wtp responder mach-
  22.  * ine. In this case ignoring the event is natural.
  23.  *
  24.  * State tables use the phrase "abort transaction" many times. In this imple-
  25.  * mentation this means "clear data structures used for storing transaction 
  26.  * data". This happens in function resp_event_handle, after included state 
  27.  * table code.
  28.  *
  29.  * Commenting the state table is perhaps best done by pointing out how various 
  30.  * services provided by WTP contribute rows to the state table.
  31.  *
  32.  * Normal transaction goes as follows (timers excluded):
  33.  *        - WTP get an invoke pdu from the peer. WTP does TR-Invoke.ind (trans-
  34.  *          mitting to WSP its PDU) and the state changes to INVOKE_RESP_WAIT
  35.  *        - WSP does TR-Invoke.res, telling that it has handled the 
  36.  *          indication. 
  37.  *          The state changes to RESULT_WAIT.
  38.  *        - WSP tells that it has results from the content server, or reply 
  39.  *          pdu to send. It does TR-Result.req. State changes to 
  40.  *          RESULT_RESP_WAIT. 
  41.  *        - WTP gets acknowledgement from the peer. It generates TR_Result.cnf
  42.  *          and state changes to LISTEN. The transaction is over.
  43.  *
  44.  * Retransmission until acknowledgement guarantees reliability of the trans-
  45.  * action, if the peer stays up. It is implemented by using retransmissions 
  46.  * controlled by timers and counters. There are two kind of timers, retrans-
  47.  * mission and acknowledgement timers. (Actually, there is one timer 
  48.  * iniatilised with two intervals. But let us keep the language simple). 
  49.  * These are used in concert with corresponding counters, RCR (retransmission 
  50.  * counter) and AEC (acknowledgement expiration counter). AEC counts expired 
  51.  * acknowledgement intervals.
  52.  *
  53.  * WTP starts an acknowledgement timer when it waits a WSP acknowledgement, 
  54.  * and retransmission timer when it sends something. So when the acknowledge_
  55.  * ment timer expires, the action is to increment AEC, and when the retrans-
  56.  * mission timer expires, the action is to resend a packet. (Note, however, 
  57.  * the chapter concerning user acknowledgement.)
  58.  *
  59.  * WTP ignores invoke pdus having same tid as the current transaction. This 
  60.  * quarantees rejection of the duplicates. Note, however, how reliability is 
  61.  * achieved when WTP is doing tid verification (next chapter).
  62.  *
  63.  * Tid verification is done if tid validation fails (which happens when the 
  64.  * message is a duplicate or when tid wrapping-up could confuse the protocol).
  65.  * In this case, the state changes to TIDOK_WAIT. WSP is indicated only after 
  66.  * an acknowledgement is received. After a negative answer (Abort PDU) the 
  67.  * transaction is teared down. Reliablity is quaranteed by resending, which 
  68.  * happens when WTP receives a resended invoke pdu, when its state TIDOK_WAIT.
  69.  * Abort pdu now means a negative answer to a question "have you a transaction
  70.  * having tid included in the tid verification message". So there is no need 
  71.  * to indicate WSP.
  72.  *
  73.  * Error handling is mostly done before feeding an event to the state machine. 
  74.  * However, when a pdu with an illegal header (header WTP does not understand)
  75.  * is received, this is an special kind of event, because its handling depends
  76.  * of the state. WTP must allways send an abort pdu. If a transaction is 
  77.  * established, it must be teared down. If WSP has been indicated about a 
  78.  * transaction, WTP must do TR-Abort.ind.
  79.  *
  80.  * There is two kind of aborts: by the peer, when it send abort pdu and by the 
  81.  * wsp, when it does a primitive TR-Abort.req. When WSP does an abort, WTP 
  82.  * must send an abort pdu to the peer; when WTP receives an abort, WSP must be
  83.  * indicated (note, however, the special meaning abort pdu has in tid 
  84.  * verification; see the relevant chapter).
  85.  *
  86.  * User acknowledgement means that WTP waits WSP (which in most cases is WTP
  87.  * user) acknowledgement, instead of doing it by itself. This means, that if 
  88.  * user acknowledgement flag is off, WTP sends an ack pdu when acknowledgement
  89.  * timer expires.
  90.  *
  91.  * By Aarno Syv鋘en for WapIT Ltd.
  92.  */
  93. STATE_NAME(LISTEN)
  94. STATE_NAME(TIDOK_WAIT)
  95. STATE_NAME(INVOKE_RESP_WAIT)
  96. STATE_NAME(RESULT_WAIT)
  97. STATE_NAME(RESULT_RESP_WAIT)
  98. STATE_NAME(WAIT_TIMEOUT_STATE)
  99. ROW(LISTEN,
  100.     RcvInvoke,
  101.     (event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) &&
  102.      wtp_tid_is_valid(event, resp_machine) == ok,
  103.     {
  104.      resp_machine->u_ack = event->u.RcvInvoke.up_flag;
  105.      resp_machine->tcl = event->u.RcvInvoke.tcl;
  106.      wsp_event = create_tr_invoke_ind(resp_machine, 
  107.          event->u.RcvInvoke.user_data);
  108.      if (resp_machine->tcl == 1)
  109.          wsp_push_client_dispatch_event(wsp_event);
  110.      else
  111.          wsp_session_dispatch_event(wsp_event);
  112.      start_timer_A(resp_machine); 
  113.      resp_machine->ack_pdu_sent = 0;
  114.     },
  115.     INVOKE_RESP_WAIT)
  116. /*
  117.  * We must here store event fields and wsp indication into the wtp responder 
  118.  * state machine: if tid is valid, we will continue the transaction without a 
  119.  * new event.
  120.  */
  121. ROW(LISTEN,
  122.     RcvInvoke,
  123.     (event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) &&
  124.      (wtp_tid_is_valid(event, resp_machine) == fail || 
  125.      wtp_tid_is_valid(event, resp_machine) == no_cached_tid),
  126.     { 
  127.      send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid);
  128.      
  129.      resp_machine->u_ack = event->u.RcvInvoke.up_flag;
  130.      resp_machine->tcl = event->u.RcvInvoke.tcl;
  131.      resp_machine->invoke_indication = create_tr_invoke_ind(resp_machine, 
  132.                                        event->u.RcvInvoke.user_data);
  133.      debug("wap.wtp", 0, "WTP_STATE: generating invoke indication, tid being" 
  134.            "invalid");
  135.     },
  136.     TIDOK_WAIT)
  137. /*
  138.  * Do not change state when class 0 message is received.
  139.  */
  140. ROW(LISTEN,
  141.     RcvInvoke,
  142.     event->u.RcvInvoke.tcl == 0,
  143.     {
  144.      wsp_event = create_tr_invoke_ind(resp_machine, 
  145.          event->u.RcvInvoke.user_data);
  146.      wsp_session_dispatch_event(wsp_event);
  147.     },
  148.     LISTEN)
  149. /*
  150.  * No user indication here: transaction is not yet started.
  151.  */
  152. ROW(LISTEN,
  153.     RcvErrorPDU,
  154.     1,
  155.     { 
  156.      send_abort(resp_machine, PROVIDER, PROTOERR);
  157.     },
  158.     LISTEN)
  159. /*
  160.  * We must cache the newly accepted tid item, otherwise every tid after a 
  161.  * suspected one will be validated. We use wsp event stored by the responder
  162.  * machine.
  163.  */
  164. ROW(TIDOK_WAIT,
  165.     RcvAck,
  166.     (resp_machine->tcl == 2 || resp_machine->tcl == 1) && 
  167.      event->u.RcvAck.tid_ok == 1,
  168.     { 
  169.      wsp_event = wap_event_duplicate(resp_machine->invoke_indication);
  170.      if (resp_machine->tcl == 1)
  171.          wsp_push_client_dispatch_event(wsp_event);
  172.      else
  173.          wsp_session_dispatch_event(wsp_event);
  174.      
  175.      wtp_tid_set_by_machine(resp_machine, event->u.RcvAck.tid);
  176.      start_timer_A(resp_machine); 
  177.      resp_machine->ack_pdu_sent = 0;
  178.     },
  179.     INVOKE_RESP_WAIT)
  180. /*
  181.  * When we get a negative answer to tid verification, we just abort trans-
  182.  * action. Because wtp machines are destroyed when their state return to 
  183.  * LISTEN and because no transaction is yet started, there is no need to do 
  184.  * anything here.
  185.  */
  186. ROW(TIDOK_WAIT,
  187.     RcvAbort,
  188.     1,
  189.     { },
  190.     LISTEN)
  191. ROW(TIDOK_WAIT,
  192.     RcvInvoke,
  193.     event->u.RcvInvoke.rid == 0,
  194.     { },
  195.     TIDOK_WAIT)
  196. /*
  197.  * Because the phone sends invoke again, previous ack was dropped by the 
  198.  * bearer.
  199.  */
  200. ROW(TIDOK_WAIT,
  201.     RcvInvoke,
  202.     event->u.RcvInvoke.rid == 1,
  203.     { 
  204.      send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid);
  205.     },
  206.     TIDOK_WAIT)
  207. /*
  208.  * No need for wsp indication: the transaction is not yet started.
  209.  */
  210. ROW(TIDOK_WAIT,
  211.     RcvErrorPDU,
  212.     1,
  213.     {
  214.      send_abort(resp_machine, PROVIDER, PROTOERR);
  215.     },
  216.     LISTEN)
  217. ROW(INVOKE_RESP_WAIT,
  218.     RcvInvoke,
  219.     1,
  220.     { },
  221.     INVOKE_RESP_WAIT)
  222. ROW(INVOKE_RESP_WAIT,
  223.     TR_Invoke_Res,
  224.     resp_machine->tcl == 2,
  225.     { 
  226.      start_timer_A(resp_machine); 
  227.      resp_machine->aec = 0;
  228.     },
  229.     RESULT_WAIT)
  230. ROW(INVOKE_RESP_WAIT,
  231.     TR_Invoke_Res,
  232.     resp_machine->tcl == 1,
  233.     {
  234.       send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
  235.       start_timer_W(resp_machine);
  236.     },
  237.     WAIT_TIMEOUT_STATE)
  238. ROW(INVOKE_RESP_WAIT,
  239.     RcvAbort,
  240.     1,
  241.     {
  242.      wsp_event = create_tr_abort_ind(resp_machine, 
  243.          event->u.RcvAbort.abort_reason);
  244.      if (resp_machine->tcl == 1)
  245.          wsp_push_client_dispatch_event(wsp_event);
  246.      else
  247.          wsp_session_dispatch_event(wsp_event);
  248.     },
  249.     LISTEN)
  250. ROW(INVOKE_RESP_WAIT,
  251.     TR_Abort_Req,
  252.     1,
  253.     { 
  254.      send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
  255.     },
  256.     LISTEN)
  257. ROW(INVOKE_RESP_WAIT,
  258.     TR_Result_Req,
  259.     1,
  260.     {
  261.      WAPEvent *result;
  262.      resp_machine->rcr = 0;
  263.      start_timer_R(resp_machine);
  264.      wap_event_destroy(resp_machine->result);
  265.      resp_machine->rid = 0;
  266.      result = wtp_pack_result(resp_machine, event);
  267.      resp_machine->result = wap_event_duplicate(result);
  268.      dispatch_to_wdp(result);
  269.      resp_machine->rid = 1;
  270.     },
  271.     RESULT_RESP_WAIT)
  272. /*
  273.  * Conditions below do not correspond wholly ones found from the spec. (If 
  274.  * they does, user acknowledgement flag would never be used by the protocol, 
  275.  * which cannot be the original intention.) 
  276.  * User acknowledgement flag is used following way: if it is on, WTP does not
  277.  * send an acknowledgement (user acknowledgement in form of TR-Invoke.res or 
  278.  * TR-Result.req instead of provider acknowledgement is awaited); if it is 
  279.  * off, WTP does this. IMHO, specs support this exegesis: there is condition 
  280.  * Uack == False && class == 2 with action send ack pdu. In addition, WTP 
  281.  * 8.3.1 says " When [user acknowledgement] is enabled WTP provider does not
  282.  * respond to a received message until after WTP user has confirmed the 
  283.  * indication service primitive by issuing the response primitive".
  284.  *
  285.  * BTW: CR correcting this shall appear soonish.
  286.  */
  287. ROW(INVOKE_RESP_WAIT,
  288.     TimerTO_A,
  289.     resp_machine->aec < AEC_MAX && resp_machine->u_ack == 1,
  290.     { 
  291.      ++resp_machine->aec;
  292.      start_timer_A(resp_machine);
  293.     },
  294.     INVOKE_RESP_WAIT)
  295. ROW(INVOKE_RESP_WAIT,
  296.     TimerTO_A,
  297.     (resp_machine->aec < AEC_MAX && resp_machine->u_ack == 0),
  298.     { 
  299.      ++resp_machine->aec;
  300.      start_timer_A(resp_machine);
  301.      send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
  302.      if (resp_machine->ack_pdu_sent == 0)
  303.          resp_machine->ack_pdu_sent = 1;
  304.     },
  305.     INVOKE_RESP_WAIT)
  306. /*
  307.  * When a transaction is aborted, WSP must surely know this. One of corrections
  308.  * in MOT_WTP_CR_01. What to do when a counter reaches its maximum value dep-
  309.  * ends on whether we have opened the connection or not. In previous case, we 
  310.  * must go to the state WAIT_TIMEOUT_STATE, for instance to prevent bad incarn-
  311.  * ations.
  312.  */
  313. ROW(INVOKE_RESP_WAIT,
  314.     TimerTO_A,
  315.     resp_machine->aec == AEC_MAX && resp_machine->tcl == 2,
  316.     {
  317.      send_abort(resp_machine, PROVIDER, NORESPONSE);
  318.      wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
  319.      wsp_session_dispatch_event(wsp_event);
  320.     },
  321.     LISTEN)
  322. ROW(INVOKE_RESP_WAIT,
  323.     TimerTO_A,
  324.     resp_machine->aec == AEC_MAX && resp_machine->tcl == 1,
  325.     {
  326.       start_timer_W(resp_machine);
  327.     },
  328.     WAIT_TIMEOUT_STATE)
  329. ROW(INVOKE_RESP_WAIT,
  330.     RcvErrorPDU,
  331.     1,
  332.     {
  333.      send_abort(resp_machine, PROVIDER, PROTOERR);
  334.      
  335.      wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
  336.      if (resp_machine->tcl == 1)
  337.          wsp_push_client_dispatch_event(wsp_event);
  338.      else
  339.          wsp_session_dispatch_event(wsp_event);
  340.     },
  341.     LISTEN)
  342. ROW(RESULT_WAIT,
  343.     TR_Result_Req,
  344.     1,
  345.     {
  346.      WAPEvent *result;
  347.      resp_machine->rcr = 0;
  348.      start_timer_R(resp_machine);
  349.      wap_event_destroy(resp_machine->result);
  350.      resp_machine->rid = 0;
  351.      result = wtp_pack_result(resp_machine, event);
  352.      resp_machine->result = wap_event_duplicate(result);
  353.      dispatch_to_wdp(result);
  354.      resp_machine->rid = 1;
  355.     },
  356.     RESULT_RESP_WAIT)
  357. ROW(RESULT_WAIT,
  358.     RcvAbort,
  359.     1,
  360.     {
  361.      wsp_event = create_tr_abort_ind(resp_machine, 
  362.          event->u.RcvAbort.abort_reason);
  363.      wsp_session_dispatch_event(wsp_event);
  364.     },
  365.     LISTEN)
  366. ROW(RESULT_WAIT,
  367.     RcvInvoke,
  368.     event->u.RcvInvoke.rid == 0,
  369.     { },
  370.     RESULT_WAIT)
  371. ROW(RESULT_WAIT,
  372.     RcvInvoke,
  373.     event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 0,
  374.     { },
  375.     RESULT_WAIT)
  376. ROW(RESULT_WAIT,
  377.     RcvInvoke,
  378.     event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 1,
  379.     {
  380.      send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
  381.     },
  382.     RESULT_WAIT)
  383. ROW(RESULT_WAIT,
  384.     TR_Abort_Req,
  385.     1,
  386.     { 
  387.      send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
  388.     },
  389.     LISTEN)
  390. ROW(RESULT_WAIT,
  391.     RcvErrorPDU,
  392.     1,
  393.     {
  394.      send_abort(resp_machine, PROVIDER, PROTOERR);
  395.      
  396.      wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
  397.      wsp_session_dispatch_event(wsp_event);
  398.     },
  399.     LISTEN)
  400.    
  401. /*
  402.  * This state follows two possible ones: INVOKE_RESP_WAIT & TR-Invoke.res and 
  403.  * INVOKE_RESP_WAIT & TimerTO_A & Class == 2 & Uack == FALSE. Contrary what 
  404.  * spec says, in first case we are now sending first time. We must, too, abort
  405.  * after AEC_MAX timer periods.
  406.  */
  407. ROW(RESULT_WAIT,
  408.     TimerTO_A,
  409.     resp_machine->aec < AEC_MAX,
  410.     { 
  411.      start_timer_A(resp_machine);
  412.      send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
  413.      if (resp_machine->ack_pdu_sent == 0)
  414.         resp_machine->ack_pdu_sent = 1;
  415.      resp_machine->aec++;
  416.     },
  417.     RESULT_WAIT)
  418. ROW(RESULT_WAIT,
  419.     TimerTO_A,
  420.     resp_machine->aec == AEC_MAX,
  421.     {
  422.      send_abort(resp_machine, PROVIDER, NORESPONSE);
  423.      wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
  424.      wsp_session_dispatch_event(wsp_event);
  425.     },
  426.     LISTEN)
  427. /*
  428.  * A duplicate ack(tidok) caused by a heavy load (the original changed state
  429.  * from TIDOK_WAIT). This implements CR-Nokia-WTP-20-March-2000/2.
  430.  */
  431. ROW(RESULT_WAIT,
  432.     RcvAck,
  433.     event->u.RcvAck.tid_ok,
  434.     {},
  435.     RESULT_WAIT)
  436. ROW(RESULT_RESP_WAIT,
  437.     RcvAck,
  438.     1,
  439.     {
  440.      wsp_event = create_tr_result_cnf(resp_machine);
  441.      wsp_session_dispatch_event(wsp_event);
  442.     },
  443.     LISTEN)
  444. /*
  445.  * Specs does not tell what to do, when wtp responder receives invoke pdu and
  446.  * its state is RESULT_RESP_WAIT. This can happen, however: event causing the 
  447.  * transition RESULT_WAIT -> RESULT_RESP_WAIT is TR-Result.req, an internal 
  448.  * responder event. 
  449.  */
  450. ROW(RESULT_RESP_WAIT,
  451.     RcvInvoke,
  452.     1,
  453.     { },
  454.     RESULT_RESP_WAIT)
  455. ROW(RESULT_RESP_WAIT,
  456.     RcvAbort,
  457.     1,
  458.     {
  459.      wsp_event = create_tr_abort_ind(resp_machine, 
  460.          event->u.RcvAbort.abort_reason);
  461.      wsp_session_dispatch_event(wsp_event);
  462.     },
  463.     LISTEN)
  464. ROW(RESULT_RESP_WAIT,
  465.     TR_Abort_Req,
  466.     1,
  467.     { 
  468.      send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
  469.     },
  470.     LISTEN)
  471. ROW(RESULT_RESP_WAIT,
  472.     TimerTO_R,
  473.     resp_machine->rcr < MAX_RCR,
  474.     {
  475.      WAPEvent *resend;
  476.      start_timer_R(resp_machine);
  477.      resend = wap_event_duplicate(resp_machine->result);
  478.      wtp_pack_set_rid(resend, resp_machine->rid);
  479.      dispatch_to_wdp(resend);
  480.      ++resp_machine->rcr;
  481.     },
  482.     RESULT_RESP_WAIT)
  483. ROW(RESULT_RESP_WAIT,
  484.     TimerTO_R,
  485.     resp_machine->rcr == MAX_RCR,
  486.     {
  487.      send_abort(resp_machine, USER, NORESPONSE);
  488.      wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
  489.      wsp_session_dispatch_event(wsp_event);
  490.     },
  491.     LISTEN)
  492. ROW(RESULT_RESP_WAIT,
  493.     RcvErrorPDU,
  494.     1,
  495.     {
  496.      send_abort(resp_machine, PROVIDER, PROTOERR);
  497.       
  498.      wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
  499.      wsp_session_dispatch_event(wsp_event);
  500.     },
  501.     LISTEN)
  502. ROW(WAIT_TIMEOUT_STATE,
  503.     RcvInvoke,
  504.     event->u.RcvInvoke.rid == 0,
  505.     { },
  506.     WAIT_TIMEOUT_STATE)
  507. ROW(WAIT_TIMEOUT_STATE,
  508.     RcvInvoke,
  509.     event->u.RcvInvoke.rid == 1,
  510.     {
  511.      send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid);
  512.     },
  513.     WAIT_TIMEOUT_STATE)
  514. ROW(WAIT_TIMEOUT_STATE,
  515.     RcvErrorPDU,
  516.     1,
  517.     {
  518.      send_abort(resp_machine, PROVIDER, PROTOERR);
  519.       
  520.      wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
  521.      wsp_push_client_dispatch_event(wsp_event);
  522.     },
  523.     LISTEN)
  524. ROW(WAIT_TIMEOUT_STATE,
  525.     RcvAbort,
  526.     1,
  527.     {
  528.      wsp_event = create_tr_abort_ind(resp_machine, PROTOERR);
  529.      wsp_push_client_dispatch_event(wsp_event);
  530.     },
  531.     LISTEN)
  532. /*
  533.  * Waiting to prevent premature incarnations.
  534.  */
  535. ROW(WAIT_TIMEOUT_STATE,
  536.     TimerTO_W,
  537.     1,
  538.     {
  539.      wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE);
  540.      wsp_push_client_dispatch_event(wsp_event); 
  541.     },
  542.     LISTEN)
  543. ROW(WAIT_TIMEOUT_STATE,
  544.     TR_Abort_Req,
  545.     1,
  546.     {
  547.      send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason);
  548.     },
  549.     LISTEN)
  550. #undef ROW
  551. #undef STATE_NAME