summaryrefslogtreecommitdiff
path: root/third-party/pjproject/patches/0002-r5435-add-pjsip_inv_session-ref_cnt.patch
blob: 12ae6a0285f422121021eac057da4fbc73687d14 (plain)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
When a transport error occured on an INVITE session
the stack calls on_tsx_state_changed with new state
PJSIP_INV_STATE_DISCONNECTED and immediately destroys
the INVITE session.
At the same time this INVITE session could being processed
on another thread. This thread could use the session's
memory pools which were already freed, so we get segfault.

This patch adds a reference counter and new functions:
pjsip_inv_add_ref and pjsip_inv_dec_ref.
The INVITE session is destroyed only when the reference
counter has reached zero.

To avoid race condition an application should call
pjsip_inv_add_ref/pjsip_inv_dec_ref.

Index: pjsip/include/pjsip-ua/sip_inv.h
===================================================================
--- a/pjsip/include/pjsip-ua/sip_inv.h	(revision 5434)
+++ b/pjsip/include/pjsip-ua/sip_inv.h	(revision 5435)
@@ -383,6 +383,11 @@
  * Other applications that want to use these pools must understand
  * that the flip-flop pool's lifetimes are synchronized to the
  * SDP offer-answer negotiation.
+ *
+ * The lifetime of this session is controlled by the reference counter in this
+ * structure, which is manipulated by calling #pjsip_inv_add_ref and
+ * #pjsip_inv_dec_ref. When the reference counter has reached zero, then
+ * this session will be destroyed.
  */
 struct pjsip_inv_session
 {
@@ -412,6 +417,7 @@
     struct pjsip_timer	*timer;			    /**< Session Timers.    */
     pj_bool_t		 following_fork;	    /**< Internal, following
 							 forked media?	    */
+    pj_atomic_t		*ref_cnt;		    /**< Reference counter. */
 };
 
 
@@ -631,6 +637,30 @@
 
 
 /**
+ * Add reference counter to the INVITE session. The reference counter controls
+ * the life time of the session, ie. when the counter reaches zero, then it 
+ * will be destroyed.
+ *
+ * @param inv       The INVITE session.
+ * @return          PJ_SUCCESS if the INVITE session reference counter
+ *                  was increased.
+ */
+PJ_DECL(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv );
+
+/**
+ * Decrement reference counter of the INVITE session.
+ * When the session is no longer used, it will be destroyed and
+ * caller is informed with PJ_EGONE return status.
+ *
+ * @param inv       The INVITE session.
+ * @return          PJ_SUCCESS if the INVITE session reference counter
+ *                  was decreased. A status PJ_EGONE will be returned to 
+ *                  inform that session is destroyed.
+ */
+PJ_DECL(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv );
+
+
+/**
  * Forcefully terminate and destroy INVITE session, regardless of
  * the state of the session. Note that this function should only be used
  * when there is failure in the INVITE session creation. After the
Index: pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- a/pjsip/src/pjsip-ua/sip_inv.c	(revision 5434)
+++ b/pjsip/src/pjsip-ua/sip_inv.c	(revision 5435)
@@ -195,6 +195,65 @@
 }
 
 /*
+ * Add reference to INVITE session.
+ */
+PJ_DEF(pj_status_t) pjsip_inv_add_ref( pjsip_inv_session *inv )
+{
+    PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL);
+
+    pj_atomic_inc(inv->ref_cnt);
+
+    return PJ_SUCCESS;
+}
+
+static void inv_session_destroy(pjsip_inv_session *inv)
+{
+    if (inv->last_ack) {
+	pjsip_tx_data_dec_ref(inv->last_ack);
+	inv->last_ack = NULL;
+    }
+    if (inv->invite_req) {
+	pjsip_tx_data_dec_ref(inv->invite_req);
+	inv->invite_req = NULL;
+    }
+    if (inv->pending_bye) {
+	pjsip_tx_data_dec_ref(inv->pending_bye);
+	inv->pending_bye = NULL;
+    }
+    pjsip_100rel_end_session(inv);
+    pjsip_timer_end_session(inv);
+    pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
+
+    /* Release the flip-flop pools */
+    pj_pool_release(inv->pool_prov);
+    inv->pool_prov = NULL;
+    pj_pool_release(inv->pool_active);
+    inv->pool_active = NULL;
+
+    pj_atomic_destroy(inv->ref_cnt);
+    inv->ref_cnt = NULL;
+}
+
+/*
+ * Decrease INVITE session reference, destroy it when the reference count
+ * reaches zero.
+ */
+PJ_DEF(pj_status_t) pjsip_inv_dec_ref( pjsip_inv_session *inv )
+{
+    pj_atomic_value_t ref_cnt;
+
+    PJ_ASSERT_RETURN(inv && inv->ref_cnt, PJ_EINVAL);
+
+    ref_cnt = pj_atomic_dec_and_get(inv->ref_cnt);
+    pj_assert( ref_cnt >= 0);
+    if (ref_cnt == 0) {
+        inv_session_destroy(inv);
+        return PJ_EGONE;
+    } 
+    return PJ_SUCCESS;    
+}
+
+/*
  * Set session state.
  */
 static void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
@@ -261,27 +320,7 @@
     if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
 	prev_state != PJSIP_INV_STATE_DISCONNECTED) 
     {
-	if (inv->last_ack) {
-	    pjsip_tx_data_dec_ref(inv->last_ack);
-	    inv->last_ack = NULL;
-	}
-	if (inv->invite_req) {
-	    pjsip_tx_data_dec_ref(inv->invite_req);
-	    inv->invite_req = NULL;
-	}
-	if (inv->pending_bye) {
-	    pjsip_tx_data_dec_ref(inv->pending_bye);
-	    inv->pending_bye = NULL;
-	}
-	pjsip_100rel_end_session(inv);
-	pjsip_timer_end_session(inv);
-	pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
-
-	/* Release the flip-flop pools */
-	pj_pool_release(inv->pool_prov);
-	inv->pool_prov = NULL;
-	pj_pool_release(inv->pool_active);
-	inv->pool_active = NULL;
+	pjsip_inv_dec_ref(inv);
     }
 }
 
@@ -838,6 +877,12 @@
     inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
     pj_assert(inv != NULL);
 
+    status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt);
+    if (status != PJ_SUCCESS) {
+	pjsip_dlg_dec_lock(dlg);
+	return status;
+    }
+
     inv->pool = dlg->pool;
     inv->role = PJSIP_ROLE_UAC;
     inv->state = PJSIP_INV_STATE_NULL;
@@ -881,6 +926,7 @@
     pjsip_100rel_attach(inv);
 
     /* Done */
+    pjsip_inv_add_ref(inv);
     *p_inv = inv;
 
     pjsip_dlg_dec_lock(dlg);
@@ -1471,6 +1517,12 @@
     inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
     pj_assert(inv != NULL);
 
+    status = pj_atomic_create(dlg->pool, 0, &inv->ref_cnt);
+    if (status != PJ_SUCCESS) {
+	pjsip_dlg_dec_lock(dlg);
+	return status;
+    }
+
     inv->pool = dlg->pool;
     inv->role = PJSIP_ROLE_UAS;
     inv->state = PJSIP_INV_STATE_NULL;
@@ -1540,6 +1592,7 @@
     }
 
     /* Done */
+    pjsip_inv_add_ref(inv);
     pjsip_dlg_dec_lock(dlg);
     *p_inv = inv;