Merge "pjproject_bundled: Add MALLOC_DEBUG capability"
[asterisk/asterisk.git] / third-party / pjproject / patches / 0002-r5435-add-pjsip_inv_session-ref_cnt.patch
1 When a transport error occured on an INVITE session
2 the stack calls on_tsx_state_changed with new state
3 PJSIP_INV_STATE_DISCONNECTED and immediately destroys
4 the INVITE session.
5 At the same time this INVITE session could being processed
6 on another thread. This thread could use the session's
7 memory pools which were already freed, so we get segfault.
8
9 This patch adds a reference counter and new functions:
10 pjsip_inv_add_ref and pjsip_inv_dec_ref.
11 The INVITE session is destroyed only when the reference
12 counter has reached zero.
13
14 To avoid race condition an application should call
15 pjsip_inv_add_ref/pjsip_inv_dec_ref.
16
17 Index: pjsip/include/pjsip-ua/sip_inv.h
18 ===================================================================
19 --- a/pjsip/include/pjsip-ua/sip_inv.h  (revision 5434)
20 +++ b/pjsip/include/pjsip-ua/sip_inv.h  (revision 5435)
21 @@ -383,6 +383,11 @@
22   * Other applications that want to use these pools must understand
23   * that the flip-flop pool's lifetimes are synchronized to the
24   * SDP offer-answer negotiation.
25 + *
26 + * The lifetime of this session is controlled by the reference counter in this
27 + * structure, which is manipulated by calling #pjsip_inv_add_ref and
28 + * #pjsip_inv_dec_ref. When the reference counter has reached zero, then
29 + * this session will be destroyed.
30   */
31  struct pjsip_inv_session
32  {
33 @@ -412,6 +417,7 @@
34      struct pjsip_timer *timer;                     /**< Session Timers.    */
35      pj_bool_t           following_fork;            /**< Internal, following
36                                                          forked media?      */
37 +    pj_atomic_t                *ref_cnt;                   /**< Reference counter. */
38  };
39  
40  
41 @@ -631,6 +637,30 @@
42  
43  
44  /**
45 + * Add reference counter to the INVITE session. The reference counter controls
46 + * the life time of the session, ie. when the counter reaches zero, then it 
47 + * will be destroyed.
48 + *
49 + * @param inv       The INVITE session.
50 + * @return          PJ_SUCCESS if the INVITE session reference counter
51 + *                  was increased.
52 + */
53 +PJ_DECL(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv );
54 +
55 +/**
56 + * Decrement reference counter of the INVITE session.
57 + * When the session is no longer used, it will be destroyed and
58 + * caller is informed with PJ_EGONE return status.
59 + *
60 + * @param inv       The INVITE session.
61 + * @return          PJ_SUCCESS if the INVITE session reference counter
62 + *                  was decreased. A status PJ_EGONE will be returned to 
63 + *                  inform that session is destroyed.
64 + */
65 +PJ_DECL(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv );
66 +
67 +
68 +/**
69   * Forcefully terminate and destroy INVITE session, regardless of
70   * the state of the session. Note that this function should only be used
71   * when there is failure in the INVITE session creation. After the
72 Index: pjsip/src/pjsip-ua/sip_inv.c
73 ===================================================================
74 --- a/pjsip/src/pjsip-ua/sip_inv.c      (revision 5434)
75 +++ b/pjsip/src/pjsip-ua/sip_inv.c      (revision 5435)
76 @@ -195,6 +195,65 @@
77  }
78  
79  /*
80 + * Add reference to INVITE session.
81 + */
82 +PJ_DEF(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv )
83 +{
84 +    PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL);
85 +
86 +    pj_atomic_inc(inv->ref_cnt);
87 +
88 +    return PJ_SUCCESS;
89 +}
90 +
91 +static void inv_session_destroy(pjsip_inv_session *inv)
92 +{
93 +    if (inv->last_ack) {
94 +       pjsip_tx_data_dec_ref(inv->last_ack);
95 +       inv->last_ack = NULL;
96 +    }
97 +    if (inv->invite_req) {
98 +       pjsip_tx_data_dec_ref(inv->invite_req);
99 +       inv->invite_req = NULL;
100 +    }
101 +    if (inv->pending_bye) {
102 +       pjsip_tx_data_dec_ref(inv->pending_bye);
103 +       inv->pending_bye = NULL;
104 +    }
105 +    pjsip_100rel_end_session(inv);
106 +    pjsip_timer_end_session(inv);
107 +    pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
108 +
109 +    /* Release the flip-flop pools */
110 +    pj_pool_release(inv->pool_prov);
111 +    inv->pool_prov = NULL;
112 +    pj_pool_release(inv->pool_active);
113 +    inv->pool_active = NULL;
114 +
115 +    pj_atomic_destroy(inv->ref_cnt);
116 +    inv->ref_cnt = NULL;
117 +}
118 +
119 +/*
120 + * Decrease INVITE session reference, destroy it when the reference count
121 + * reaches zero.
122 + */
123 +PJ_DEF(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv )
124 +{
125 +    pj_atomic_value_t ref_cnt;
126 +
127 +    PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL);
128 +
129 +    ref_cnt = pj_atomic_dec_and_get(inv->ref_cnt);
130 +    pj_assert( ref_cnt >= 0);
131 +    if (ref_cnt == 0) {
132 +        inv_session_destroy(inv);
133 +        return PJ_EGONE;
134 +    } 
135 +    return PJ_SUCCESS;    
136 +}
137 +
138 +/*
139   * Set session state.
140   */
141  static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
142 @@ -261,27 +320,7 @@
143      if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
144         prev_state != PJSIP_INV_STATE_DISCONNECTED) 
145      {
146 -       if (inv->last_ack) {
147 -           pjsip_tx_data_dec_ref(inv->last_ack);
148 -           inv->last_ack = NULL;
149 -       }
150 -       if (inv->invite_req) {
151 -           pjsip_tx_data_dec_ref(inv->invite_req);
152 -           inv->invite_req = NULL;
153 -       }
154 -       if (inv->pending_bye) {
155 -           pjsip_tx_data_dec_ref(inv->pending_bye);
156 -           inv->pending_bye = NULL;
157 -       }
158 -       pjsip_100rel_end_session(inv);
159 -       pjsip_timer_end_session(inv);
160 -       pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
161 -
162 -       /* Release the flip-flop pools */
163 -       pj_pool_release(inv->pool_prov);
164 -       inv->pool_prov = NULL;
165 -       pj_pool_release(inv->pool_active);
166 -       inv->pool_active = NULL;
167 +       pjsip_inv_dec_ref(inv);
168      }
169  }
170  
171 @@ -838,6 +877,12 @@
172      inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
173      pj_assert(inv != NULL);
174  
175 +    status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt);
176 +    if (status != PJ_SUCCESS) {
177 +       pjsip_dlg_dec_lock(dlg);
178 +       return status;
179 +    }
180 +
181      inv->pool = dlg->pool;
182      inv->role = PJSIP_ROLE_UAC;
183      inv->state = PJSIP_INV_STATE_NULL;
184 @@ -881,6 +926,7 @@
185      pjsip_100rel_attach(inv);
186  
187      /* Done */
188 +    pjsip_inv_add_ref(inv);
189      *p_inv = inv;
190  
191      pjsip_dlg_dec_lock(dlg);
192 @@ -1471,6 +1517,12 @@
193      inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
194      pj_assert(inv != NULL);
195  
196 +    status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt);
197 +    if (status != PJ_SUCCESS) {
198 +       pjsip_dlg_dec_lock(dlg);
199 +       return status;
200 +    }
201 +
202      inv->pool = dlg->pool;
203      inv->role = PJSIP_ROLE_UAS;
204      inv->state = PJSIP_INV_STATE_NULL;
205 @@ -1540,6 +1592,7 @@
206      }
207  
208      /* Done */
209 +    pjsip_inv_add_ref(inv);
210      pjsip_dlg_dec_lock(dlg);
211      *p_inv = inv;
212