Pjsip状态机

近期在voip skeleton上增加了一个简单的状态机,分别是当前的状态(current state),事件(event),新的状态(new state),操作(action),使用的是list链表的方式管理,实现动态注册状态的处理。在pjsip 事务(transation state machine)状态机使用的是用数组的方式来实现,数组的下标为状态,内容为操作handle。

pjsip的事务状态用枚举定义:

transation状态声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * This enumeration represents transaction state.
 */
typedef enum pjsip_tsx_state_e
{
    PJSIP_TSX_STATE_NULL,   /**< For UAC, before any message is sent.   */
    PJSIP_TSX_STATE_CALLING,    /**< For UAC, just after request is sent.   */
    PJSIP_TSX_STATE_TRYING, /**< For UAS, just after request is received.*/
    PJSIP_TSX_STATE_PROCEEDING, /**< For UAS/UAC, after provisional response.*/
    PJSIP_TSX_STATE_COMPLETED,  /**< For UAS/UAC, after final response.     */
    PJSIP_TSX_STATE_CONFIRMED,  /**< For UAS, after ACK is received.        */
    PJSIP_TSX_STATE_TERMINATED, /**< For UAS/UAC, before it's destroyed.    */
    PJSIP_TSX_STATE_DESTROYED,  /**< For UAS/UAC, will be destroyed now.    */
    PJSIP_TSX_STATE_MAX        /**< Number of states.              */
} pjsip_tsx_state_e;

pjsip状态处理函数的定义:

transation状态处理函数声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static pj_status_t tsx_on_state_null(      pjsip_transaction *tsx,
                              pjsip_event *event);
static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx,
                              pjsip_event *event);
static pj_status_t tsx_on_state_trying(      pjsip_transaction *tsx,
                              pjsip_event *event);
static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
                          pjsip_event *event);
static pj_status_t tsx_on_state_proceeding_uac( pjsip_transaction *tsx,
                          pjsip_event *event);
static pj_status_t tsx_on_state_completed_uas(   pjsip_transaction *tsx,
                          pjsip_event *event);
static pj_status_t tsx_on_state_completed_uac(   pjsip_transaction *tsx,
                          pjsip_event *event);
static pj_status_t tsx_on_state_confirmed(   pjsip_transaction *tsx,
                          pjsip_event *event);
static pj_status_t tsx_on_state_terminated(  pjsip_transaction *tsx,
                          pjsip_event *event);
static pj_status_t tsx_on_state_destroyed(   pjsip_transaction *tsx,
                          pjsip_event *event);

pjsip状态机的注册:

transation 状态注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* State handlers for UAC, indexed by state */
static int  (*tsx_state_handler_uac[PJSIP_TSX_STATE_MAX])(pjsip_transaction *,
                            pjsip_event *) =
{
    &tsx_on_state_null,
    &tsx_on_state_calling,
    NULL,
    &tsx_on_state_proceeding_uac,
    &tsx_on_state_completed_uac,
    &tsx_on_state_confirmed,
    &tsx_on_state_terminated,
    &tsx_on_state_destroyed,
};

/* State handlers for UAS */
static int  (*tsx_state_handler_uas[PJSIP_TSX_STATE_MAX])(pjsip_transaction *,
                            pjsip_event *) =
{
    &tsx_on_state_null,
    NULL,
    &tsx_on_state_trying,
    &tsx_on_state_proceeding_uas,
    &tsx_on_state_completed_uas,
    &tsx_on_state_confirmed,
    &tsx_on_state_terminated,
    &tsx_on_state_destroyed,
};

当相应的事件来临时,就调用相应的处理函数handle和改变自身的状态,如ack来临,或者超时重传:

transation调用相应的处理函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * State Calling is for UAC after it sends request but before any responses
 * is received.
 */
static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx,
                       pjsip_event *event )
{
    pj_assert(tsx->state == PJSIP_TSX_STATE_CALLING);
    pj_assert(tsx->role == PJSIP_ROLE_UAC);

    if (event->type == PJSIP_EVENT_TIMER &&
  event->body.timer.entry == &tsx->retransmit_timer)
    {
        pj_status_t status;

  /* Retransmit the request. */
        status = tsx_retransmit( tsx, 1 );
  if (status != PJ_SUCCESS) {
      return status;
  }

    } else if (event->type == PJSIP_EVENT_TIMER &&
         event->body.timer.entry == &tsx->timeout_timer)
    {

  /* Cancel retransmission timer. */
  if (tsx->retransmit_timer.id != 0) {
      pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
      tsx->retransmit_timer.id = 0;
  }
  tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);

  /* Set status code */
  tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);

  /* Inform TU. */
  tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
                       PJSIP_EVENT_TIMER, &tsx->timeout_timer);

  /* Transaction is destroyed */
  //return PJSIP_ETSXDESTROYED;

    } else if (event->type == PJSIP_EVENT_RX_MSG) {
  pjsip_msg *msg;
  int code;

  /* Get message instance */
  msg = event->body.rx_msg.rdata->msg_info.msg;

  /* Better be a response message. */
  if (msg->type != PJSIP_RESPONSE_MSG)
      return PJSIP_ENOTRESPONSEMSG;

  code = msg->line.status.code;

  /* If the response is final, cancel both retransmission and timeout
  * timer.
  */
  if (code >= 200) {
      if (tsx->retransmit_timer.id != 0) {
      pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
      tsx->retransmit_timer.id = 0;
      }

      if (tsx->timeout_timer.id != 0) {
      lock_timer(tsx);
      pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
      tsx->timeout_timer.id = 0;
      unlock_timer(tsx);
      }

  } else {
      /* Cancel retransmit timer (for non-INVITE transaction, the
      * retransmit timer will be rescheduled at T2.
      */
      if (tsx->retransmit_timer.id != 0) {
      pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
      tsx->retransmit_timer.id = 0;
      }

      /* For provisional response, only cancel retransmit when this
      * is an INVITE transaction. For non-INVITE, section 17.1.2.1
      * of RFC 3261 says that:
      *  - retransmit timer is set to T2
      *  - timeout timer F is not deleted.
      */
      if (tsx->method.id == PJSIP_INVITE_METHOD) {

      /* Cancel timeout timer */
      lock_timer(tsx);
      pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
      unlock_timer(tsx);

      } else {
      if (!tsx->is_reliable) {
          tsx->retransmit_timer.id = TIMER_ACTIVE;
          pjsip_endpt_schedule_timer(tsx->endpt,
                         &tsx->retransmit_timer,
                         &t2_timer_val);
      }
      }
  }
  
  tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);


  /* Discard retransmission message if it is not INVITE.
  * The INVITE tdata is needed in case we have to generate ACK for
  * the final response.
  */
  /* Keep last_tx for authorization. */
  //blp: always keep last_tx until transaction is destroyed
  //code = msg->line.status.code;
  //if (tsx->method.id != PJSIP_INVITE_METHOD && code!=401 && code!=407) {
  //    pjsip_tx_data_dec_ref(tsx->last_tx);
  //    tsx->last_tx = NULL;
  //}

  /* Processing is similar to state Proceeding. */
  tsx_on_state_proceeding_uac( tsx, event);

    } else {
  pj_assert(!"Unexpected event");
        return PJ_EBUG;
    }

    return PJ_SUCCESS;
}

pjsip 事务相应状态改变函数:

transation状态改变和改变相应处理函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
 * Set transaction state, and inform TU about the transaction state change.
 */
static void tsx_set_state( pjsip_transaction *tsx,
             pjsip_tsx_state_e state,
             pjsip_event_id_e event_src_type,
                           void *event_src )
{
    pjsip_tsx_state_e prev_state = tsx->state;

    /* New state must be greater than previous state */
    pj_assert(state >= tsx->state);

    PJ_LOG(5, (tsx->obj_name, "State changed from %s to %s, event=%s",
         state_str[tsx->state], state_str[state],
               pjsip_event_str(event_src_type)));
    pj_log_push_indent();

    /* Change state. */
    tsx->state = state;

    /* Update the state handlers. */
    if (tsx->role == PJSIP_ROLE_UAC) {
  tsx->state_handler = tsx_state_handler_uac[state];
    } else {
  tsx->state_handler = tsx_state_handler_uas[state];
    }

    /* Before informing TU about state changed, inform TU about
     * rx event.
     */
    if (event_src_type==PJSIP_EVENT_RX_MSG && tsx->tsx_user) {
  pjsip_rx_data *rdata = (pjsip_rx_data*) event_src;

  pj_assert(rdata != NULL);

  if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG &&
         tsx->tsx_user->on_rx_response)
  {
      (*tsx->tsx_user->on_rx_response)(rdata);
  }

    }

    /* Inform TU about state changed. */
    if (tsx->tsx_user && tsx->tsx_user->on_tsx_state) {
  pjsip_event e;
  PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src,
                 prev_state);
  (*tsx->tsx_user->on_tsx_state)(tsx, &e);
    }


    /* When the transaction is terminated, release transport, and free the
     * saved last transmitted message.
     */
    if (state == PJSIP_TSX_STATE_TERMINATED) {
  pj_time_val timeout = {0, 0};

  /* If we're still waiting for a message to be sent.. */
  if (tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) {
      /* Disassociate ourselves from the outstanding transmit data
      * so that when the send callback is called we will be able
      * to ignore that (otherwise we'll get assertion, see
      * http://trac.pjsip.org/repos/ticket/1033)
      */
      if (tsx->pending_tx) {
      tsx->pending_tx->mod_data[mod_tsx_layer.mod.id] = NULL;
      tsx->pending_tx = NULL;
      }
      tsx->transport_flag &= ~(TSX_HAS_PENDING_TRANSPORT);
  }

  lock_timer(tsx);

  /* Cancel timeout timer. */
  if (tsx->timeout_timer.id != 0) {
      pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
      tsx->timeout_timer.id = 0;
  }

  tsx->timeout_timer.id = TIMER_ACTIVE;
  pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer,
                  &timeout);

  unlock_timer(tsx);

    } else if (state == PJSIP_TSX_STATE_DESTROYED) {

  /* Unregister transaction. */
  mod_tsx_layer_unregister_tsx(tsx);

  /* Destroy transaction. */
  tsx_destroy(tsx);
    }

    pj_log_pop_indent();
}

Comments