blob: 53858dcd5cfb479fc9b69ab9d1271e1034e2d88c [file] [log] [blame]
Benny Prijono268ca612006-02-07 12:34:11 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono268ca612006-02-07 12:34:11 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjsip-ua/sip_inv.h>
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000021#include <pjsip-ua/sip_100rel.h>
Nanang Izzuddin59dffb12009-08-11 12:42:38 +000022#include <pjsip-ua/sip_timer.h>
Benny Prijono268ca612006-02-07 12:34:11 +000023#include <pjsip/sip_module.h>
24#include <pjsip/sip_endpoint.h>
25#include <pjsip/sip_event.h>
26#include <pjsip/sip_transaction.h>
27#include <pjmedia/sdp.h>
28#include <pjmedia/sdp_neg.h>
Benny Prijono95196582006-02-09 00:13:40 +000029#include <pjmedia/errno.h>
Benny Prijono268ca612006-02-07 12:34:11 +000030#include <pj/string.h>
31#include <pj/pool.h>
32#include <pj/assert.h>
Benny Prijono8ad55352006-02-08 11:16:05 +000033#include <pj/os.h>
Benny Prijonoa66c7152006-02-09 01:26:14 +000034#include <pj/log.h>
35
Benny Prijono1f7767b2007-10-03 18:28:49 +000036/*
37 * Note on offer/answer:
38 *
39 * The offer/answer framework in this implementation assumes the occurence
40 * of SDP in a particular request/response according to this table:
41
42 offer answer Note:
43 ========================================================================
44 INVITE X INVITE may contain offer
45 18x/INVITE X X Response may contain offer or answer
46 2xx/INVITE X X Response may contain offer or answer
47 ACK X ACK may contain answer
48
49 PRACK X PRACK can only contain answer
50 2xx/PRACK Response may not have offer nor answer
51
52 UPDATE X UPDATE may only contain offer
53 2xx/UPDATE X Response may only contain answer
54 ========================================================================
55
56 *
57 */
Benny Prijono268ca612006-02-07 12:34:11 +000058
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000059#define THIS_FILE "sip_inv.c"
Benny Prijono268ca612006-02-07 12:34:11 +000060
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000061static const char *inv_state_names[] =
62{
Benny Prijono4be63b52006-11-25 14:50:25 +000063 "NULL",
64 "CALLING",
65 "INCOMING",
66 "EARLY",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000067 "CONNECTING",
Benny Prijonoc5055702007-01-13 23:20:18 +000068 "CONFIRMED",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000069 "DISCONNCTD",
70 "TERMINATED",
71};
72
Benny Prijono1f7767b2007-10-03 18:28:49 +000073/* UPDATE method */
Nanang Izzuddin9b93f862009-08-11 18:21:13 +000074static const pjsip_method pjsip_update_method =
Benny Prijono1f7767b2007-10-03 18:28:49 +000075{
76 PJSIP_OTHER_METHOD,
77 { "UPDATE", 6 }
78};
79
Benny Prijono268ca612006-02-07 12:34:11 +000080/*
81 * Static prototypes.
82 */
83static pj_status_t mod_inv_load(pjsip_endpoint *endpt);
84static pj_status_t mod_inv_unload(void);
85static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata);
86static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata);
87static void mod_inv_on_tsx_state(pjsip_transaction*, pjsip_event*);
88
Benny Prijono8ad55352006-02-08 11:16:05 +000089static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e);
90static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e);
91static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e);
92static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e);
93static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e);
94static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e);
95static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e);
Benny Prijono268ca612006-02-07 12:34:11 +000096
Benny Prijono7d910092007-06-20 04:19:46 +000097static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
98 pjsip_transaction *tsx,
99 pjsip_rx_data *rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +0000100static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv );
101static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
102 const pjmedia_sdp_session *c_sdp);
Benny Prijono7d910092007-06-20 04:19:46 +0000103static pj_status_t process_answer( pjsip_inv_session *inv,
104 int st_code,
105 pjsip_tx_data *tdata,
106 const pjmedia_sdp_session *local_sdp);
107
Benny Prijono8ad55352006-02-08 11:16:05 +0000108static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
Benny Prijono268ca612006-02-07 12:34:11 +0000109{
110 &inv_on_state_null,
111 &inv_on_state_calling,
112 &inv_on_state_incoming,
113 &inv_on_state_early,
114 &inv_on_state_connecting,
115 &inv_on_state_confirmed,
116 &inv_on_state_disconnected,
Benny Prijono268ca612006-02-07 12:34:11 +0000117};
118
119static struct mod_inv
120{
121 pjsip_module mod;
122 pjsip_endpoint *endpt;
123 pjsip_inv_callback cb;
Benny Prijono268ca612006-02-07 12:34:11 +0000124} mod_inv =
125{
126 {
Benny Prijono2f8992b2006-02-25 21:16:36 +0000127 NULL, NULL, /* prev, next. */
128 { "mod-invite", 10 }, /* Name. */
129 -1, /* Id */
130 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
131 &mod_inv_load, /* load() */
132 NULL, /* start() */
133 NULL, /* stop() */
134 &mod_inv_unload, /* unload() */
135 &mod_inv_on_rx_request, /* on_rx_request() */
136 &mod_inv_on_rx_response, /* on_rx_response() */
137 NULL, /* on_tx_request. */
138 NULL, /* on_tx_response() */
139 &mod_inv_on_tsx_state, /* on_tsx_state() */
Benny Prijono268ca612006-02-07 12:34:11 +0000140 }
141};
142
143
Benny Prijonoa66c7152006-02-09 01:26:14 +0000144/* Invite session data to be attached to transaction. */
145struct tsx_inv_data
146{
Benny Prijono8fcb4332008-10-31 18:01:48 +0000147 pjsip_inv_session *inv; /* The invite session */
148 pj_bool_t sdp_done; /* SDP negotiation done for this tsx? */
149 pj_str_t done_tag; /* To tag in RX response with answer */
150 pj_bool_t done_early;/* Negotiation was done for early med? */
Benny Prijonoa66c7152006-02-09 01:26:14 +0000151};
152
Benny Prijono8ad55352006-02-08 11:16:05 +0000153/*
154 * Module load()
155 */
Benny Prijono268ca612006-02-07 12:34:11 +0000156static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
157{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000158 pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},
159 { "UPDATE", 6}};
Benny Prijono56315612006-07-18 14:39:40 +0000160 pj_str_t accepted = { "application/sdp", 15 };
Benny Prijono268ca612006-02-07 12:34:11 +0000161
Benny Prijono1f7767b2007-10-03 18:28:49 +0000162 /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */
Benny Prijono268ca612006-02-07 12:34:11 +0000163 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
164 PJ_ARRAY_SIZE(allowed), allowed);
165
Benny Prijono56315612006-07-18 14:39:40 +0000166 /* Register "application/sdp" in Accept header */
167 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
168 1, &accepted);
169
Benny Prijono268ca612006-02-07 12:34:11 +0000170 return PJ_SUCCESS;
171}
172
Benny Prijono8ad55352006-02-08 11:16:05 +0000173/*
174 * Module unload()
175 */
Benny Prijono268ca612006-02-07 12:34:11 +0000176static pj_status_t mod_inv_unload(void)
177{
178 /* Should remove capability here */
179 return PJ_SUCCESS;
180}
181
Benny Prijono8ad55352006-02-08 11:16:05 +0000182/*
Benny Prijono38998232006-02-08 22:44:25 +0000183 * Set session state.
184 */
185void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
186 pjsip_event *e)
187{
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000188 pjsip_inv_state prev_state = inv->state;
Benny Prijono7d910092007-06-20 04:19:46 +0000189 pj_status_t status;
190
191
192 /* If state is confirmed, check that SDP negotiation is done,
193 * otherwise disconnect the session.
194 */
195 if (state == PJSIP_INV_STATE_CONFIRMED) {
196 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
197 pjsip_tx_data *bye;
198
199 PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
200 "session"));
201
202 status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
203 NULL, &bye);
204 if (status == PJ_SUCCESS && bye)
205 status = pjsip_inv_send_msg(inv, bye);
206
207 return;
208 }
209 }
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000210
211 /* Set state. */
Benny Prijono38998232006-02-08 22:44:25 +0000212 inv->state = state;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000213
214 /* If state is DISCONNECTED, cause code MUST have been set. */
215 pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
216 inv->cause != 0);
217
218 /* Call on_state_changed() callback. */
219 if (mod_inv.cb.on_state_changed && inv->notify)
Benny Prijono38998232006-02-08 22:44:25 +0000220 (*mod_inv.cb.on_state_changed)(inv, e);
221
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000222 /* Only decrement when previous state is not already DISCONNECTED */
223 if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
224 prev_state != PJSIP_INV_STATE_DISCONNECTED)
225 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000226 if (inv->last_ack) {
227 pjsip_tx_data_dec_ref(inv->last_ack);
228 inv->last_ack = NULL;
229 }
Benny Prijono5e51a4e2008-11-27 00:06:46 +0000230 if (inv->invite_req) {
231 pjsip_tx_data_dec_ref(inv->invite_req);
232 inv->invite_req = NULL;
233 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000234 pjsip_100rel_end_session(inv);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000235 pjsip_timer_end_session(inv);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000236 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000237 }
Benny Prijono38998232006-02-08 22:44:25 +0000238}
239
240
241/*
Benny Prijono0b6340c2006-06-13 22:21:23 +0000242 * Set cause code.
243 */
244void inv_set_cause(pjsip_inv_session *inv, int cause_code,
245 const pj_str_t *cause_text)
246{
247 if (cause_code > inv->cause) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000248 inv->cause = (pjsip_status_code) cause_code;
Benny Prijono0b6340c2006-06-13 22:21:23 +0000249 if (cause_text)
250 pj_strdup(inv->pool, &inv->cause_text, cause_text);
251 else if (cause_code/100 == 2)
252 inv->cause_text = pj_str("Normal call clearing");
253 else
254 inv->cause_text = *pjsip_get_status_text(cause_code);
255 }
256}
257
258
Benny Prijono1f7767b2007-10-03 18:28:49 +0000259/*
260 * Check if outgoing request needs to have SDP answer.
261 * This applies for both ACK and PRACK requests.
262 */
Benny Prijono9569a0b2007-10-04 15:35:26 +0000263static const pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv,
264 pjsip_transaction *tsx)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000265{
266 pjmedia_sdp_neg_state neg_state;
Benny Prijono9569a0b2007-10-04 15:35:26 +0000267 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000268 pj_status_t status;
269
270 /* If SDP negotiator is ready, start negotiation. */
271
272 /* Start nego when appropriate. */
273 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
274 PJMEDIA_SDP_NEG_STATE_NULL;
275
276 if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) {
277
278 /* Nothing to do */
279
280 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
281 pjmedia_sdp_neg_has_local_answer(inv->neg) )
282 {
283 struct tsx_inv_data *tsx_inv_data;
Benny Prijonod5f9f422007-11-25 04:40:07 +0000284 struct tsx_inv_data dummy;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000285
Benny Prijonod5f9f422007-11-25 04:40:07 +0000286 /* Get invite session's transaction data.
287 * Note that tsx may be NULL, for example when application sends
288 * delayed ACK request (at this time, the original INVITE
289 * transaction may have been destroyed.
290 */
291 if (tsx) {
292 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
293 } else {
294 tsx_inv_data = &dummy;
295 pj_bzero(&dummy, sizeof(dummy));
296 dummy.inv = inv;
297 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000298
299 status = inv_negotiate_sdp(inv);
300 if (status != PJ_SUCCESS)
301 return NULL;
302
303 /* Mark this transaction has having SDP offer/answer done. */
304 tsx_inv_data->sdp_done = 1;
305
306 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
307
308 } else {
309 /* This remark is only valid for ACK.
310 PJ_LOG(4,(inv->dlg->obj_name,
311 "FYI, the SDP negotiator state (%s) is in a mess "
312 "when sending this ACK/PRACK request",
313 pjmedia_sdp_neg_state_str(neg_state)));
314 */
315 }
316
317 return sdp;
318}
319
Benny Prijono0b6340c2006-06-13 22:21:23 +0000320
321/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000322 * Send ACK for 2xx response.
323 */
Benny Prijonod5f9f422007-11-25 04:40:07 +0000324static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +0000325{
Benny Prijonod5f9f422007-11-25 04:40:07 +0000326 pjsip_rx_data *rdata;
Benny Prijono268ca612006-02-07 12:34:11 +0000327 pj_status_t status;
328
Benny Prijonod5f9f422007-11-25 04:40:07 +0000329 if (e->type == PJSIP_EVENT_TSX_STATE)
330 rdata = e->body.tsx_state.src.rdata;
331 else if (e->type == PJSIP_EVENT_RX_MSG)
332 rdata = e->body.rx_msg.rdata;
333 else {
334 pj_assert(!"Unsupported event type");
335 return PJ_EBUG;
336 }
337
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000338 PJ_LOG(5,(inv->obj_name, "Received %s, sending ACK",
339 pjsip_rx_data_get_info(rdata)));
340
Benny Prijono1f7767b2007-10-03 18:28:49 +0000341 /* Check if we have cached ACK request */
342 if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000343
Benny Prijono1f7767b2007-10-03 18:28:49 +0000344 pjsip_tx_data_add_ref(inv->last_ack);
Benny Prijonod5f9f422007-11-25 04:40:07 +0000345
346 } else if (mod_inv.cb.on_send_ack) {
347 /* If application handles ACK transmission manually, just notify the
348 * callback
349 */
350 PJ_LOG(5,(inv->obj_name, "Received %s, notifying application callback",
351 pjsip_rx_data_get_info(rdata)));
352
353 (*mod_inv.cb.on_send_ack)(inv, rdata);
354 return PJ_SUCCESS;
355
Benny Prijono1f7767b2007-10-03 18:28:49 +0000356 } else {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000357 status = pjsip_inv_create_ack(inv, rdata->msg_info.cseq->cseq,
358 &inv->last_ack);
Benny Prijono268ca612006-02-07 12:34:11 +0000359 }
360
Benny Prijono1f7767b2007-10-03 18:28:49 +0000361 /* Send ACK */
362 status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000363 if (status != PJ_SUCCESS) {
364 /* Better luck next time */
365 pj_assert(!"Unable to send ACK!");
366 return status;
367 }
368
Benny Prijonod5f9f422007-11-25 04:40:07 +0000369
Benny Prijonoe6da48a2008-09-22 14:36:00 +0000370 /* Set state to CONFIRMED (if we're not in CONFIRMED yet).
371 * But don't set it to CONFIRMED if we're already DISCONNECTED
372 * (this may have been a late 200/OK response.
373 */
374 if (inv->state < PJSIP_INV_STATE_CONFIRMED) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000375 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
376 }
377
Benny Prijono268ca612006-02-07 12:34:11 +0000378 return PJ_SUCCESS;
379}
380
Benny Prijono8ad55352006-02-08 11:16:05 +0000381/*
382 * Module on_rx_request()
383 *
384 * This callback is called for these events:
385 * - endpoint receives request which was unhandled by higher priority
386 * modules (e.g. transaction layer, dialog layer).
387 * - dialog distributes incoming request to its usages.
388 */
389static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
390{
391 pjsip_method *method;
Benny Prijono38998232006-02-08 22:44:25 +0000392 pjsip_dialog *dlg;
393 pjsip_inv_session *inv;
Benny Prijono8ad55352006-02-08 11:16:05 +0000394
395 /* Only wants to receive request from a dialog. */
Benny Prijono38998232006-02-08 22:44:25 +0000396 dlg = pjsip_rdata_get_dlg(rdata);
397 if (dlg == NULL)
Benny Prijono8ad55352006-02-08 11:16:05 +0000398 return PJ_FALSE;
399
Benny Prijonoa1e69682007-05-11 15:14:34 +0000400 inv = (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono38998232006-02-08 22:44:25 +0000401
Benny Prijono8ad55352006-02-08 11:16:05 +0000402 /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
403 * If we need to send response, it will be sent in the state
404 * handlers.
405 */
406 method = &rdata->msg_info.msg->line.req.method;
407
Benny Prijono70127222006-07-02 14:53:05 +0000408 if (method->id == PJSIP_INVITE_METHOD) {
409 return PJ_TRUE;
410 }
411
412 /* BYE and CANCEL must have existing invite session */
413 if (method->id == PJSIP_BYE_METHOD ||
414 method->id == PJSIP_CANCEL_METHOD)
Benny Prijono8ad55352006-02-08 11:16:05 +0000415 {
Benny Prijono70127222006-07-02 14:53:05 +0000416 if (inv == NULL)
417 return PJ_FALSE;
418
Benny Prijono8ad55352006-02-08 11:16:05 +0000419 return PJ_TRUE;
420 }
421
Benny Prijono38998232006-02-08 22:44:25 +0000422 /* On receipt ACK request, when state is CONNECTING,
423 * move state to CONFIRMED.
424 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000425 if (method->id == PJSIP_ACK_METHOD && inv) {
Benny Prijono38998232006-02-08 22:44:25 +0000426
Benny Prijonof521eb02006-08-06 23:07:25 +0000427 /* Ignore ACK if pending INVITE transaction has not finished. */
428 if (inv->invite_tsx &&
429 inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
430 {
431 return PJ_TRUE;
432 }
433
Benny Prijono5eff0432006-02-09 14:14:21 +0000434 /* Terminate INVITE transaction, if it's still present. */
435 if (inv->invite_tsx &&
436 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
437 {
Benny Prijono7d910092007-06-20 04:19:46 +0000438 /* Before we terminate INVITE transaction, process the SDP
Benny Prijono59e9e952008-09-21 22:55:43 +0000439 * in the ACK request, if any.
440 * Only do this when invite state is not already disconnected
441 * (http://trac.pjsip.org/repos/ticket/640).
Benny Prijono7d910092007-06-20 04:19:46 +0000442 */
Benny Prijono59e9e952008-09-21 22:55:43 +0000443 if (inv->state < PJSIP_INV_STATE_DISCONNECTED) {
444 inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
445 }
Benny Prijono7d910092007-06-20 04:19:46 +0000446
447 /* Now we can terminate the INVITE transaction */
Benny Prijonof521eb02006-08-06 23:07:25 +0000448 pj_assert(inv->invite_tsx->status_code >= 200);
Benny Prijono5eff0432006-02-09 14:14:21 +0000449 pjsip_tsx_terminate(inv->invite_tsx,
450 inv->invite_tsx->status_code);
451 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000452 if (inv->last_answer) {
453 pjsip_tx_data_dec_ref(inv->last_answer);
454 inv->last_answer = NULL;
455 }
Benny Prijono5eff0432006-02-09 14:14:21 +0000456 }
457
Benny Prijono32ac8fe2006-03-02 21:16:55 +0000458 /* On receipt of ACK, only set state to confirmed when state
459 * is CONNECTING (e.g. we don't want to set the state to confirmed
460 * when we receive ACK retransmission after sending non-2xx!)
461 */
462 if (inv->state == PJSIP_INV_STATE_CONNECTING) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000463 pjsip_event event;
464
465 PJSIP_EVENT_INIT_RX_MSG(event, rdata);
466 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
467 }
Benny Prijono38998232006-02-08 22:44:25 +0000468 }
469
Benny Prijono8ad55352006-02-08 11:16:05 +0000470 return PJ_FALSE;
471}
472
473/*
474 * Module on_rx_response().
475 *
476 * This callback is called for these events:
477 * - dialog distributes incoming 2xx response to INVITE (outside
478 * transaction) to its usages.
479 * - endpoint distributes strayed responses.
480 */
Benny Prijono268ca612006-02-07 12:34:11 +0000481static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
482{
483 pjsip_dialog *dlg;
484 pjsip_inv_session *inv;
485 pjsip_msg *msg = rdata->msg_info.msg;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000486 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +0000487 pjsip_status_code st_code;
Benny Prijono268ca612006-02-07 12:34:11 +0000488
489 dlg = pjsip_rdata_get_dlg(rdata);
490
491 /* Ignore responses outside dialog */
492 if (dlg == NULL)
493 return PJ_FALSE;
494
495 /* Ignore responses not belonging to invite session */
496 inv = pjsip_dlg_get_inv_session(dlg);
497 if (inv == NULL)
498 return PJ_FALSE;
499
500 /* This MAY be retransmission of 2xx response to INVITE.
501 * If it is, we need to send ACK.
502 */
503 if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
Benny Prijono26ff9062006-02-21 23:47:00 +0000504 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
505 inv->invite_tsx == NULL)
506 {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000507 pjsip_event e;
Benny Prijono268ca612006-02-07 12:34:11 +0000508
Benny Prijonod5f9f422007-11-25 04:40:07 +0000509 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
510 inv_send_ack(inv, &e);
Benny Prijono268ca612006-02-07 12:34:11 +0000511 return PJ_TRUE;
512
513 }
514
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000515 /* Pass response to timer session module */
Nanang Izzuddin65add622009-08-11 16:26:20 +0000516 status = pjsip_timer_process_resp(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000517 if (status != PJ_SUCCESS) {
518 pjsip_event e;
519 pjsip_tx_data *tdata;
520
521 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
522 inv_send_ack(inv, &e);
523
Nanang Izzuddin65add622009-08-11 16:26:20 +0000524 status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000525 if (tdata && status == PJ_SUCCESS)
526 pjsip_inv_send_msg(inv, tdata);
527
528 return PJ_TRUE;
529 }
530
Benny Prijono268ca612006-02-07 12:34:11 +0000531 /* No other processing needs to be done here. */
532 return PJ_FALSE;
533}
534
Benny Prijono8ad55352006-02-08 11:16:05 +0000535/*
536 * Module on_tsx_state()
537 *
538 * This callback is called by dialog framework for all transactions
539 * inside the dialog for all its dialog usages.
540 */
Benny Prijono268ca612006-02-07 12:34:11 +0000541static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
542{
543 pjsip_dialog *dlg;
544 pjsip_inv_session *inv;
545
546 dlg = pjsip_tsx_get_dlg(tsx);
547 if (dlg == NULL)
548 return;
549
550 inv = pjsip_dlg_get_inv_session(dlg);
551 if (inv == NULL)
552 return;
553
554 /* Call state handler for the invite session. */
555 (*inv_state_handler[inv->state])(inv, e);
556
557 /* Call on_tsx_state */
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000558 if (mod_inv.cb.on_tsx_state_changed && inv->notify)
Benny Prijono268ca612006-02-07 12:34:11 +0000559 (*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
560
Benny Prijono46249942007-02-19 22:23:14 +0000561 /* Clear invite transaction when tsx is confirmed.
562 * Previously we set invite_tsx to NULL only when transaction has
563 * terminated, but this didn't work when ACK has the same Via branch
564 * value as the INVITE (see http://www.pjsip.org/trac/ticket/113)
565 */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000566 if (tsx->state>=PJSIP_TSX_STATE_CONFIRMED && tsx == inv->invite_tsx) {
Benny Prijono46249942007-02-19 22:23:14 +0000567 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000568 if (inv->last_answer) {
569 pjsip_tx_data_dec_ref(inv->last_answer);
570 inv->last_answer = NULL;
571 }
572 }
Benny Prijono268ca612006-02-07 12:34:11 +0000573}
574
Benny Prijono8ad55352006-02-08 11:16:05 +0000575
576/*
577 * Initialize the invite module.
578 */
Benny Prijono268ca612006-02-07 12:34:11 +0000579PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
Benny Prijono268ca612006-02-07 12:34:11 +0000580 const pjsip_inv_callback *cb)
581{
582 pj_status_t status;
583
584 /* Check arguments. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000585 PJ_ASSERT_RETURN(endpt && cb, PJ_EINVAL);
Benny Prijono268ca612006-02-07 12:34:11 +0000586
587 /* Some callbacks are mandatory */
588 PJ_ASSERT_RETURN(cb->on_state_changed && cb->on_new_session, PJ_EINVAL);
589
590 /* Check if module already registered. */
591 PJ_ASSERT_RETURN(mod_inv.mod.id == -1, PJ_EINVALIDOP);
592
593 /* Copy param. */
594 pj_memcpy(&mod_inv.cb, cb, sizeof(pjsip_inv_callback));
595
596 mod_inv.endpt = endpt;
Benny Prijono268ca612006-02-07 12:34:11 +0000597
598 /* Register the module. */
599 status = pjsip_endpt_register_module(endpt, &mod_inv.mod);
Benny Prijono053f5222006-11-11 16:16:04 +0000600 if (status != PJ_SUCCESS)
601 return status;
Benny Prijono268ca612006-02-07 12:34:11 +0000602
Benny Prijono053f5222006-11-11 16:16:04 +0000603 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +0000604}
605
Benny Prijono8ad55352006-02-08 11:16:05 +0000606/*
607 * Get the instance of invite module.
608 */
Benny Prijono268ca612006-02-07 12:34:11 +0000609PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
610{
611 return &mod_inv.mod;
612}
613
614
Benny Prijono632ce712006-02-09 14:01:40 +0000615
Benny Prijono8ad55352006-02-08 11:16:05 +0000616/*
617 * Return the invite session for the specified dialog.
618 */
Benny Prijono268ca612006-02-07 12:34:11 +0000619PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
620{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000621 return (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono268ca612006-02-07 12:34:11 +0000622}
623
Benny Prijono8ad55352006-02-08 11:16:05 +0000624
Benny Prijono268ca612006-02-07 12:34:11 +0000625/*
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000626 * Get INVITE state name.
627 */
628PJ_DEF(const char *) pjsip_inv_state_name(pjsip_inv_state state)
629{
630 PJ_ASSERT_RETURN(state >= PJSIP_INV_STATE_NULL &&
631 state <= PJSIP_INV_STATE_DISCONNECTED,
632 "??");
633
634 return inv_state_names[state];
635}
636
637/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000638 * Create UAC invite session.
Benny Prijono268ca612006-02-07 12:34:11 +0000639 */
640PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
641 const pjmedia_sdp_session *local_sdp,
642 unsigned options,
643 pjsip_inv_session **p_inv)
644{
645 pjsip_inv_session *inv;
646 pj_status_t status;
647
648 /* Verify arguments. */
649 PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
650
Benny Prijono8eae8382006-08-10 21:44:26 +0000651 /* Must lock dialog first */
652 pjsip_dlg_inc_lock(dlg);
653
Benny Prijono268ca612006-02-07 12:34:11 +0000654 /* Normalize options */
655 if (options & PJSIP_INV_REQUIRE_100REL)
656 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000657 if (options & PJSIP_INV_REQUIRE_TIMER)
658 options |= PJSIP_INV_SUPPORT_TIMER;
659
660 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000661 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +0000662 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000663
664 inv->pool = dlg->pool;
665 inv->role = PJSIP_ROLE_UAC;
666 inv->state = PJSIP_INV_STATE_NULL;
667 inv->dlg = dlg;
668 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000669 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000670 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +0000671
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000672 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +0000673 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000674
Benny Prijono268ca612006-02-07 12:34:11 +0000675 /* Create negotiator if local_sdp is specified. */
676 if (local_sdp) {
677 status = pjmedia_sdp_neg_create_w_local_offer(dlg->pool, local_sdp,
678 &inv->neg);
Benny Prijono8eae8382006-08-10 21:44:26 +0000679 if (status != PJ_SUCCESS) {
680 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000681 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000682 }
Benny Prijono268ca612006-02-07 12:34:11 +0000683 }
684
685 /* Register invite as dialog usage. */
686 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +0000687 if (status != PJ_SUCCESS) {
688 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000689 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000690 }
Benny Prijono268ca612006-02-07 12:34:11 +0000691
692 /* Increment dialog session */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000693 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +0000694
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000695 /* Create 100rel handler */
696 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000697
Benny Prijono268ca612006-02-07 12:34:11 +0000698 /* Done */
699 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000700
Benny Prijono8eae8382006-08-10 21:44:26 +0000701 pjsip_dlg_dec_lock(dlg);
702
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000703 PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
704 dlg->obj_name));
705
Benny Prijono268ca612006-02-07 12:34:11 +0000706 return PJ_SUCCESS;
707}
708
709/*
710 * Verify incoming INVITE request.
711 */
Benny Prijono87a90212008-01-23 20:29:30 +0000712PJ_DEF(pj_status_t) pjsip_inv_verify_request2(pjsip_rx_data *rdata,
713 unsigned *options,
714 const pjmedia_sdp_session *r_sdp,
715 const pjmedia_sdp_session *l_sdp,
716 pjsip_dialog *dlg,
717 pjsip_endpoint *endpt,
718 pjsip_tx_data **p_tdata)
Benny Prijono268ca612006-02-07 12:34:11 +0000719{
720 pjsip_msg *msg;
721 pjsip_allow_hdr *allow;
722 pjsip_supported_hdr *sup_hdr;
723 pjsip_require_hdr *req_hdr;
724 int code = 200;
725 unsigned rem_option = 0;
726 pj_status_t status = PJ_SUCCESS;
727 pjsip_hdr res_hdr_list;
728
729 /* Init return arguments. */
730 if (p_tdata) *p_tdata = NULL;
731
732 /* Verify arguments. */
733 PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);
734
735 /* Normalize options */
736 if (*options & PJSIP_INV_REQUIRE_100REL)
737 *options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000738 if (*options & PJSIP_INV_REQUIRE_TIMER)
739 *options |= PJSIP_INV_SUPPORT_TIMER;
740
741 /* Get the message in rdata */
742 msg = rdata->msg_info.msg;
743
744 /* Must be INVITE request. */
745 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
746 msg->line.req.method.id == PJSIP_INVITE_METHOD,
747 PJ_EINVAL);
748
749 /* If tdata is specified, then either dlg or endpt must be specified */
750 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
751
752 /* Get the endpoint */
753 endpt = endpt ? endpt : dlg->endpt;
754
755 /* Init response header list */
756 pj_list_init(&res_hdr_list);
757
Benny Prijono87a90212008-01-23 20:29:30 +0000758 /* Check the request body, see if it's something that we support,
759 * only when the body hasn't been parsed before.
Benny Prijono268ca612006-02-07 12:34:11 +0000760 */
Benny Prijono87a90212008-01-23 20:29:30 +0000761 if (r_sdp==NULL && msg->body) {
Benny Prijono268ca612006-02-07 12:34:11 +0000762 pjsip_msg_body *body = msg->body;
763 pj_str_t str_application = {"application", 11};
764 pj_str_t str_sdp = { "sdp", 3 };
765 pjmedia_sdp_session *sdp;
766
767 /* Check content type. */
768 if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||
769 pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)
770 {
771 /* Not "application/sdp" */
772 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
773 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
774
775 if (p_tdata) {
776 /* Add Accept header to response */
777 pjsip_accept_hdr *acc;
778
779 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
780 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
781 acc->values[acc->count++] = pj_str("application/sdp");
782 pj_list_push_back(&res_hdr_list, acc);
783 }
784
785 goto on_return;
786 }
787
788 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000789 status = pjmedia_sdp_parse(rdata->tp_info.pool,
790 (char*)body->data, body->len, &sdp);
Benny Prijono268ca612006-02-07 12:34:11 +0000791 if (status == PJ_SUCCESS)
792 status = pjmedia_sdp_validate(sdp);
793
794 if (status != PJ_SUCCESS) {
795 /* Unparseable or invalid SDP */
796 code = PJSIP_SC_BAD_REQUEST;
797
798 if (p_tdata) {
799 /* Add Warning header. */
800 pjsip_warning_hdr *w;
801
802 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
803 pjsip_endpt_name(endpt),
804 status);
805 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
806
807 pj_list_push_back(&res_hdr_list, w);
808 }
809
810 goto on_return;
811 }
812
Benny Prijono87a90212008-01-23 20:29:30 +0000813 r_sdp = sdp;
814 }
815
816 if (r_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +0000817 /* Negotiate with local SDP */
818 if (l_sdp) {
819 pjmedia_sdp_neg *neg;
820
821 /* Local SDP must be valid! */
822 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
823 status);
824
825 /* Create SDP negotiator */
826 status = pjmedia_sdp_neg_create_w_remote_offer(
Benny Prijono87a90212008-01-23 20:29:30 +0000827 rdata->tp_info.pool, l_sdp, r_sdp, &neg);
Benny Prijono268ca612006-02-07 12:34:11 +0000828 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
829
830 /* Negotiate SDP */
831 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
832 if (status != PJ_SUCCESS) {
833
834 /* Incompatible media */
835 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000836
837 if (p_tdata) {
838 pjsip_accept_hdr *acc;
839 pjsip_warning_hdr *w;
840
841 /* Add Warning header. */
842 w = pjsip_warning_hdr_create_from_status(
843 rdata->tp_info.pool,
844 pjsip_endpt_name(endpt), status);
845 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
846
847 pj_list_push_back(&res_hdr_list, w);
848
849 /* Add Accept header to response */
850 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
851 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
852 acc->values[acc->count++] = pj_str("application/sdp");
853 pj_list_push_back(&res_hdr_list, acc);
854
855 }
856
857 goto on_return;
858 }
859 }
860 }
861
862 /* Check supported methods, see if peer supports UPDATE.
863 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
864 * implicitly by sending this INVITE.
865 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000866 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000867 if (allow) {
868 unsigned i;
869 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
870
871 for (i=0; i<allow->count; ++i) {
872 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
873 break;
874 }
875
876 if (i != allow->count) {
877 /* UPDATE is present in Allow */
878 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
879 }
880
881 }
882
883 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000884 sup_hdr = (pjsip_supported_hdr*)
885 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000886 if (sup_hdr) {
887 unsigned i;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000888 const pj_str_t STR_100REL = { "100rel", 6};
889 const pj_str_t STR_TIMER = { "timer", 5};
Benny Prijono268ca612006-02-07 12:34:11 +0000890
891 for (i=0; i<sup_hdr->count; ++i) {
892 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
893 rem_option |= PJSIP_INV_SUPPORT_100REL;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000894 if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000895 rem_option |= PJSIP_INV_SUPPORT_TIMER;
896 }
897 }
898
899 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000900 req_hdr = (pjsip_require_hdr*)
901 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000902 if (req_hdr) {
903 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +0000904 const pj_str_t STR_100REL = { "100rel", 6};
Benny Prijono053f5222006-11-11 16:16:04 +0000905 const pj_str_t STR_REPLACES = { "replaces", 8 };
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000906 const pj_str_t STR_TIMER = { "timer", 5 };
Benny Prijono268ca612006-02-07 12:34:11 +0000907 unsigned unsupp_cnt = 0;
908 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
909
910 for (i=0; i<req_hdr->count; ++i) {
911 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
912 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
913 {
914 rem_option |= PJSIP_INV_REQUIRE_100REL;
915
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000916 } else if ((*options & PJSIP_INV_SUPPORT_TIMER) &&
917 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000918 {
919 rem_option |= PJSIP_INV_REQUIRE_TIMER;
920
Benny Prijono053f5222006-11-11 16:16:04 +0000921 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
922 pj_bool_t supp;
923
924 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
925 NULL, &STR_REPLACES);
926 if (!supp)
927 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
928
Nanang Izzuddin5d5a20e2009-08-06 16:04:20 +0000929 } else if (!pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
930 NULL, &req_hdr->values[i]))
931 {
Benny Prijono268ca612006-02-07 12:34:11 +0000932 /* Unknown/unsupported extension tag! */
933 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
934 }
935 }
936
937 /* Check if there are required tags that we don't support */
938 if (unsupp_cnt) {
939
940 code = PJSIP_SC_BAD_EXTENSION;
941 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
942
943 if (p_tdata) {
944 pjsip_unsupported_hdr *unsupp_hdr;
945 const pjsip_hdr *h;
946
947 /* Add Unsupported header. */
948 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
949 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
950
951 unsupp_hdr->count = unsupp_cnt;
952 for (i=0; i<unsupp_cnt; ++i)
953 unsupp_hdr->values[i] = unsupp_tags[i];
954
955 pj_list_push_back(&res_hdr_list, unsupp_hdr);
956
957 /* Add Supported header. */
958 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
959 NULL);
960 pj_assert(h);
961 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000962 sup_hdr = (pjsip_supported_hdr*)
963 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000964 pj_list_push_back(&res_hdr_list, sup_hdr);
965 }
966 }
967
968 goto on_return;
969 }
970 }
971
972 /* Check if there are local requirements that are not supported
973 * by peer.
974 */
975 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
976 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
Nanang Izzuddin65add622009-08-11 16:26:20 +0000977 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
978 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
Benny Prijono268ca612006-02-07 12:34:11 +0000979 {
980 code = PJSIP_SC_EXTENSION_REQUIRED;
981 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
982
983 if (p_tdata) {
984 const pjsip_hdr *h;
985
986 /* Add Require header. */
987 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
988 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
989
990 if (*options & PJSIP_INV_REQUIRE_100REL)
991 req_hdr->values[req_hdr->count++] = pj_str("100rel");
Benny Prijono268ca612006-02-07 12:34:11 +0000992 if (*options & PJSIP_INV_REQUIRE_TIMER)
993 req_hdr->values[req_hdr->count++] = pj_str("timer");
994
995 pj_list_push_back(&res_hdr_list, req_hdr);
996
997 /* Add Supported header. */
998 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
999 NULL);
1000 pj_assert(h);
1001 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001002 sup_hdr = (pjsip_supported_hdr*)
1003 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001004 pj_list_push_back(&res_hdr_list, sup_hdr);
1005 }
1006
1007 }
1008
1009 goto on_return;
1010 }
1011
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001012 /* If remote Require something that we support, make us Require
1013 * that feature too.
1014 */
1015 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
1016 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
1017 *options |= PJSIP_INV_REQUIRE_100REL;
1018 }
1019 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1020 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1021 *options |= PJSIP_INV_REQUIRE_TIMER;
1022 }
1023
Benny Prijono268ca612006-02-07 12:34:11 +00001024on_return:
1025
1026 /* Create response if necessary */
1027 if (code != 200 && p_tdata) {
1028 pjsip_tx_data *tdata;
1029 const pjsip_hdr *h;
1030
1031 if (dlg) {
1032 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1033 &tdata);
1034 } else {
1035 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1036 &tdata);
1037 }
1038
1039 if (status != PJ_SUCCESS)
1040 return status;
1041
1042 /* Add response headers. */
1043 h = res_hdr_list.next;
1044 while (h != &res_hdr_list) {
1045 pjsip_hdr *cloned;
1046
Benny Prijonoa1e69682007-05-11 15:14:34 +00001047 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001048 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1049
1050 pjsip_msg_add_hdr(tdata->msg, cloned);
1051
1052 h = h->next;
1053 }
1054
1055 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001056
1057 /* Can not return PJ_SUCCESS when response message is produced.
1058 * Ref: PROTOS test ~#2490
1059 */
1060 if (status == PJ_SUCCESS)
1061 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1062
Benny Prijono268ca612006-02-07 12:34:11 +00001063 }
1064
1065 return status;
1066}
1067
Benny Prijono87a90212008-01-23 20:29:30 +00001068
1069/*
1070 * Verify incoming INVITE request.
1071 */
1072PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1073 unsigned *options,
1074 const pjmedia_sdp_session *l_sdp,
1075 pjsip_dialog *dlg,
1076 pjsip_endpoint *endpt,
1077 pjsip_tx_data **p_tdata)
1078{
1079 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1080 endpt, p_tdata);
1081}
1082
Benny Prijono268ca612006-02-07 12:34:11 +00001083/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001084 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001085 */
1086PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1087 pjsip_rx_data *rdata,
1088 const pjmedia_sdp_session *local_sdp,
1089 unsigned options,
1090 pjsip_inv_session **p_inv)
1091{
1092 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001093 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001094 pjsip_msg *msg;
1095 pjmedia_sdp_session *rem_sdp = NULL;
1096 pj_status_t status;
1097
1098 /* Verify arguments. */
1099 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1100
1101 /* Dialog MUST have been initialised. */
1102 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1103
1104 msg = rdata->msg_info.msg;
1105
1106 /* rdata MUST contain INVITE request */
1107 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1108 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1109 PJ_EINVALIDOP);
1110
Benny Prijono8eae8382006-08-10 21:44:26 +00001111 /* Lock dialog */
1112 pjsip_dlg_inc_lock(dlg);
1113
Benny Prijono268ca612006-02-07 12:34:11 +00001114 /* Normalize options */
1115 if (options & PJSIP_INV_REQUIRE_100REL)
1116 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +00001117 if (options & PJSIP_INV_REQUIRE_TIMER)
1118 options |= PJSIP_INV_SUPPORT_TIMER;
1119
1120 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001121 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001122 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001123
1124 inv->pool = dlg->pool;
1125 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001126 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001127 inv->dlg = dlg;
1128 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001129 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001130 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001131
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001132 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001133 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001134
Benny Prijono268ca612006-02-07 12:34:11 +00001135 /* Parse SDP in message body, if present. */
1136 if (msg->body) {
1137 pjsip_msg_body *body = msg->body;
1138
1139 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001140 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001141 &rem_sdp);
1142 if (status == PJ_SUCCESS)
1143 status = pjmedia_sdp_validate(rem_sdp);
1144
Benny Prijono8eae8382006-08-10 21:44:26 +00001145 if (status != PJ_SUCCESS) {
1146 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001147 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001148 }
Benny Prijono268ca612006-02-07 12:34:11 +00001149 }
1150
1151 /* Create negotiator. */
1152 if (rem_sdp) {
1153 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp,
1154 rem_sdp, &inv->neg);
1155
1156 } else if (local_sdp) {
1157 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1158 &inv->neg);
1159 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001160 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001161 }
1162
Benny Prijono8eae8382006-08-10 21:44:26 +00001163 if (status != PJ_SUCCESS) {
1164 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001165 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001166 }
Benny Prijono268ca612006-02-07 12:34:11 +00001167
1168 /* Register invite as dialog usage. */
1169 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001170 if (status != PJ_SUCCESS) {
1171 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001172 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001173 }
Benny Prijono268ca612006-02-07 12:34:11 +00001174
1175 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001176 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001177
1178 /* Save the invite transaction. */
1179 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001180
1181 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001182 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001183 tsx_inv_data->inv = inv;
1184 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001185
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001186 /* Create 100rel handler */
1187 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001188 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001189 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001190
Benny Prijono268ca612006-02-07 12:34:11 +00001191 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001192 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001193 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001194
1195 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1196 dlg->obj_name));
1197
Benny Prijono268ca612006-02-07 12:34:11 +00001198 return PJ_SUCCESS;
1199}
1200
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001201/*
1202 * Forcefully terminate the session.
1203 */
1204PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1205 int st_code,
1206 pj_bool_t notify)
1207{
1208 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1209
1210 /* Lock dialog. */
1211 pjsip_dlg_inc_lock(inv->dlg);
1212
1213 /* Set callback notify flag. */
1214 inv->notify = notify;
1215
1216 /* If there's pending transaction, terminate the transaction.
1217 * This may subsequently set the INVITE session state to
1218 * disconnected.
1219 */
1220 if (inv->invite_tsx &&
1221 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1222 {
1223 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1224
1225 }
1226
1227 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001228 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001229
1230 /* Forcefully terminate the session if state is not DISCONNECTED */
1231 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1232 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1233 }
1234
1235 /* Done.
1236 * The dec_lock() below will actually destroys the dialog if it
1237 * has no other session.
1238 */
1239 pjsip_dlg_dec_lock(inv->dlg);
1240
1241 return PJ_SUCCESS;
1242}
1243
1244
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001245/*
1246 * Restart UAC session, possibly because app or us wants to re-send the
1247 * INVITE request due to 401/407 challenge or 3xx response.
1248 */
1249PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1250 pj_bool_t new_offer)
1251{
1252 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1253
1254 inv->state = PJSIP_INV_STATE_NULL;
1255 inv->invite_tsx = NULL;
1256 if (inv->last_answer) {
1257 pjsip_tx_data_dec_ref(inv->last_answer);
1258 inv->last_answer = NULL;
1259 }
1260
1261 if (new_offer && inv->neg) {
1262 pjmedia_sdp_neg_state neg_state;
1263
1264 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1265 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1266 pjmedia_sdp_neg_cancel_offer(inv->neg);
1267 }
1268 }
1269
1270 return PJ_SUCCESS;
1271}
1272
1273
Benny Prijono268ca612006-02-07 12:34:11 +00001274static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1275{
1276 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001277 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001278}
1279
1280static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1281{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001282 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001283}
1284
Benny Prijono56315612006-07-18 14:39:40 +00001285
1286PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1287 pjmedia_sdp_session *sdp,
1288 pjsip_msg_body **p_body)
1289{
1290 const pj_str_t STR_APPLICATION = { "application", 11};
1291 const pj_str_t STR_SDP = { "sdp", 3 };
1292 pjsip_msg_body *body;
1293
Benny Prijonoa1e69682007-05-11 15:14:34 +00001294 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001295 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1296
1297 body->content_type.type = STR_APPLICATION;
1298 body->content_type.subtype = STR_SDP;
1299 body->data = sdp;
1300 body->len = 0;
1301 body->clone_data = &clone_sdp;
1302 body->print_body = &print_sdp;
1303
1304 *p_body = body;
1305
1306 return PJ_SUCCESS;
1307}
1308
Benny Prijono268ca612006-02-07 12:34:11 +00001309static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1310 const pjmedia_sdp_session *c_sdp)
1311{
1312 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001313 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001314
Benny Prijono56315612006-07-18 14:39:40 +00001315 status = pjsip_create_sdp_body(pool,
1316 pjmedia_sdp_session_clone(pool, c_sdp),
1317 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001318
Benny Prijono56315612006-07-18 14:39:40 +00001319 if (status != PJ_SUCCESS)
1320 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001321
1322 return body;
1323}
1324
1325/*
1326 * Create initial INVITE request.
1327 */
1328PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1329 pjsip_tx_data **p_tdata )
1330{
1331 pjsip_tx_data *tdata;
1332 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001333 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001334 pj_status_t status;
1335
1336 /* Verify arguments. */
1337 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1338
Benny Prijono26ff9062006-02-21 23:47:00 +00001339 /* State MUST be NULL or CONFIRMED. */
1340 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1341 inv->state == PJSIP_INV_STATE_CONFIRMED,
1342 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001343
Benny Prijono64f851e2006-02-23 13:49:28 +00001344 /* Lock dialog. */
1345 pjsip_dlg_inc_lock(inv->dlg);
1346
Benny Prijono268ca612006-02-07 12:34:11 +00001347 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001348 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001349 &tdata);
1350 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001351 goto on_return;
1352
Benny Prijono268ca612006-02-07 12:34:11 +00001353
Benny Prijono26ff9062006-02-21 23:47:00 +00001354 /* If this is the first INVITE, then copy the headers from inv_hdr.
1355 * These are the headers parsed from the request URI when the
1356 * dialog was created.
1357 */
1358 if (inv->state == PJSIP_INV_STATE_NULL) {
1359 hdr = inv->dlg->inv_hdr.next;
1360
1361 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001362 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001363 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1364 hdr = hdr->next;
1365 }
1366 }
1367
1368 /* See if we have SDP to send. */
1369 if (inv->neg) {
1370 pjmedia_sdp_neg_state neg_state;
1371
1372 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1373
1374 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1375 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1376 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1377
1378
1379 } else {
1380 has_sdp = PJ_FALSE;
1381 }
1382
Benny Prijono268ca612006-02-07 12:34:11 +00001383 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001384 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001385 const pjmedia_sdp_session *offer;
1386
1387 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono176a11f2009-04-14 11:14:51 +00001388 if (status != PJ_SUCCESS) {
1389 pjsip_tx_data_dec_ref(tdata);
Benny Prijono64f851e2006-02-23 13:49:28 +00001390 goto on_return;
Benny Prijono176a11f2009-04-14 11:14:51 +00001391 }
Benny Prijono268ca612006-02-07 12:34:11 +00001392
1393 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1394 }
1395
1396 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001397 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001398 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1399 if (hdr) {
1400 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1401 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1402 }
Benny Prijono268ca612006-02-07 12:34:11 +00001403 }
1404
1405 /* Add Supported header */
1406 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1407 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001408 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001409 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1410 }
1411
1412 /* Add Require header. */
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001413 if ((inv->options & PJSIP_INV_REQUIRE_100REL) ||
1414 (inv->options & PJSIP_INV_REQUIRE_TIMER))
1415 {
1416 pjsip_require_hdr *hreq;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001417
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001418 hreq = pjsip_require_hdr_create(tdata->pool);
1419
1420 if (inv->options & PJSIP_INV_REQUIRE_100REL)
1421 hreq->values[hreq->count++] = pj_str("100rel");
1422 if (inv->options & PJSIP_INV_REQUIRE_TIMER)
1423 hreq->values[hreq->count++] = pj_str("timer");
1424
1425 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001426 }
Benny Prijono268ca612006-02-07 12:34:11 +00001427
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001428 status = pjsip_timer_update_req(inv, tdata);
1429 if (status != PJ_SUCCESS)
1430 goto on_return;
1431
Benny Prijono268ca612006-02-07 12:34:11 +00001432 /* Done. */
1433 *p_tdata = tdata;
1434
Benny Prijono64f851e2006-02-23 13:49:28 +00001435
1436on_return:
1437 pjsip_dlg_dec_lock(inv->dlg);
1438 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001439}
1440
1441
1442/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001443 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001444 */
1445static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1446{
1447 pj_status_t status;
1448
1449 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1450 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1451 PJMEDIA_SDPNEG_EINSTATE);
1452
1453 status = pjmedia_sdp_neg_negotiate(inv->pool, inv->neg, 0);
1454
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001455 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1456
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001457 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001458 (*mod_inv.cb.on_media_update)(inv, status);
1459
1460 return status;
1461}
1462
1463/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001464 * Check in incoming message for SDP offer/answer.
1465 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001466static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1467 pjsip_transaction *tsx,
1468 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001469{
1470 struct tsx_inv_data *tsx_inv_data;
1471 static const pj_str_t str_application = { "application", 11 };
1472 static const pj_str_t str_sdp = { "sdp", 3 };
1473 pj_status_t status;
1474 pjsip_msg *msg;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001475 pjmedia_sdp_session *rem_sdp;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001476
1477 /* Check if SDP is present in the message. */
1478
1479 msg = rdata->msg_info.msg;
1480 if (msg->body == NULL) {
1481 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001482 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001483 }
1484
1485 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1486 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1487 {
1488 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001489 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001490 }
1491
Benny Prijono8fcb4332008-10-31 18:01:48 +00001492 /* Get/attach invite session's transaction data */
1493 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1494 if (tsx_inv_data == NULL) {
1495 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1496 tsx_inv_data->inv = inv;
1497 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1498 }
1499
1500 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1501 * EXCEPT if:
1502 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1503 * - the previous negotiation was done on an early media (18x) and
1504 * this response is a final/2xx response, and
1505 * - the 2xx response has different To tag than the 18x response
1506 * (i.e. the request has forked).
1507 *
1508 * The exception above is to add a rudimentary support for early media
1509 * forking (sample case: custom ringback). See this ticket for more
1510 * info: http://trac.pjsip.org/repos/ticket/657
1511 */
1512 if (tsx_inv_data->sdp_done) {
1513 pj_str_t res_tag;
1514
1515 res_tag = rdata->msg_info.to->tag;
1516
1517 /* Allow final response after SDP has been negotiated in early
1518 * media, IF this response is a final response with different
1519 * tag.
1520 */
1521 if (tsx->role == PJSIP_ROLE_UAC &&
1522 rdata->msg_info.msg->line.status.code/100 == 2 &&
1523 tsx_inv_data->done_early &&
1524 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1525 {
1526 const pjmedia_sdp_session *reoffer_sdp = NULL;
1527
1528 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1529 "after SDP negotiation has been done in early "
1530 "media. Renegotiating SDP.."));
1531
1532 /* Retrieve original SDP offer from INVITE request */
1533 reoffer_sdp = (const pjmedia_sdp_session*)
1534 tsx->last_tx->msg->body->data;
1535
1536 /* Feed the original offer to negotiator */
1537 status = pjmedia_sdp_neg_modify_local_offer(inv->pool, inv->neg,
1538 reoffer_sdp);
1539 if (status != PJ_SUCCESS) {
1540 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1541 "forked 2xx response (err=%d)", status));
1542 return status;
1543 }
1544
1545 } else {
1546
1547 if (rdata->msg_info.msg->body) {
1548 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1549 "body is ignored"));
1550 }
1551 return PJ_SUCCESS;
1552 }
1553 }
1554
Benny Prijonoa66c7152006-02-09 01:26:14 +00001555 /* Parse the SDP body. */
1556
Benny Prijonoa1e69682007-05-11 15:14:34 +00001557 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1558 (char*)msg->body->data,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001559 msg->body->len, &rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001560 if (status == PJ_SUCCESS)
Benny Prijono8fcb4332008-10-31 18:01:48 +00001561 status = pjmedia_sdp_validate(rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001562
Benny Prijonoa66c7152006-02-09 01:26:14 +00001563 if (status != PJ_SUCCESS) {
1564 char errmsg[PJ_ERR_MSG_SIZE];
1565 pj_strerror(status, errmsg, sizeof(errmsg));
1566 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1567 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001568 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001569 }
1570
1571 /* The SDP can be an offer or answer, depending on negotiator's state */
1572
1573 if (inv->neg == NULL ||
1574 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1575 {
1576
1577 /* This is an offer. */
1578
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001579 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1580 pjsip_rx_data_get_info(rdata)));
1581
Benny Prijonoa66c7152006-02-09 01:26:14 +00001582 if (inv->neg == NULL) {
1583 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001584 rem_sdp, &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001585 } else {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001586 status=pjmedia_sdp_neg_set_remote_offer(inv->pool, inv->neg,
1587 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001588 }
1589
1590 if (status != PJ_SUCCESS) {
1591 char errmsg[PJ_ERR_MSG_SIZE];
1592 pj_strerror(status, errmsg, sizeof(errmsg));
1593 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1594 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001595 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001596 }
1597
1598 /* Inform application about remote offer. */
1599
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001600 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001601
Benny Prijono8fcb4332008-10-31 18:01:48 +00001602 (*mod_inv.cb.on_rx_offer)(inv, rem_sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001603
1604 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001605
1606 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1607 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1608 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001609 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001610
1611 /* This is an answer.
1612 * Process and negotiate remote answer.
1613 */
1614
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001615 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1616 pjsip_rx_data_get_info(rdata)));
1617
Benny Prijono8fcb4332008-10-31 18:01:48 +00001618 status = pjmedia_sdp_neg_set_remote_answer(inv->pool, inv->neg,
1619 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001620
1621 if (status != PJ_SUCCESS) {
1622 char errmsg[PJ_ERR_MSG_SIZE];
1623 pj_strerror(status, errmsg, sizeof(errmsg));
1624 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1625 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001626 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001627 }
1628
1629 /* Negotiate SDP */
1630
1631 inv_negotiate_sdp(inv);
1632
Benny Prijono8fcb4332008-10-31 18:01:48 +00001633 /* Mark this transaction has having SDP offer/answer done, and
1634 * save the reference to the To tag
1635 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001636
1637 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001638 status_code = rdata->msg_info.msg->line.status.code;
1639 tsx_inv_data->done_early = (status_code/100==1);
1640 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1641 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001642
1643 } else {
1644
1645 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1646 pjsip_rx_data_get_info(rdata),
1647 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1648 }
1649
Benny Prijono26ff9062006-02-21 23:47:00 +00001650 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001651}
1652
1653
Benny Prijono26ff9062006-02-21 23:47:00 +00001654/*
1655 * Process INVITE answer, for both initial and subsequent re-INVITE
1656 */
1657static pj_status_t process_answer( pjsip_inv_session *inv,
1658 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001659 pjsip_tx_data *tdata,
1660 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001661{
1662 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001663 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001664
Benny Prijono64f851e2006-02-23 13:49:28 +00001665 /* If local_sdp is specified, then we MUST NOT have answered the
1666 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001667 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001668 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1669
1670 if (inv->neg == NULL) {
1671 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1672 &inv->neg);
1673 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1674 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1675 {
1676 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
1677 local_sdp);
1678 } else {
1679
1680 /* Can not specify local SDP at this state. */
1681 pj_assert(0);
1682 status = PJMEDIA_SDPNEG_EINSTATE;
1683 }
1684
1685 if (status != PJ_SUCCESS)
1686 return status;
1687
1688 }
1689
1690
1691 /* If SDP negotiator is ready, start negotiation. */
1692 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001693
1694 pjmedia_sdp_neg_state neg_state;
1695
Benny Prijono64f851e2006-02-23 13:49:28 +00001696 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001697 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1698 PJMEDIA_SDP_NEG_STATE_NULL;
1699
1700 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1701
1702 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1703
1704 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1705 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1706 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001707 struct tsx_inv_data *tsx_inv_data;
1708
1709 /* Get invite session's transaction data */
1710 tsx_inv_data = (struct tsx_inv_data*)
1711 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001712
1713 status = inv_negotiate_sdp(inv);
1714 if (status != PJ_SUCCESS)
1715 return status;
1716
Benny Prijono77998ce2007-06-20 10:03:46 +00001717 /* Mark this transaction has having SDP offer/answer done. */
1718 tsx_inv_data->sdp_done = 1;
1719
Benny Prijono26ff9062006-02-21 23:47:00 +00001720 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1721 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001722 }
1723
Benny Prijono64f851e2006-02-23 13:49:28 +00001724 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001725 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001726 *
1727 * Note note:
1728 * - When offer/answer has been completed in reliable 183, we MUST NOT
1729 * send SDP in 2xx response. So if we don't have SDP to send, clear
1730 * the SDP in the message body ONLY if 100rel is active in this
1731 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001732 */
1733 if (sdp) {
1734 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001735 } else {
1736 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1737 tdata->msg->body = NULL;
1738 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001739 }
1740
Benny Prijono26ff9062006-02-21 23:47:00 +00001741
1742 return PJ_SUCCESS;
1743}
1744
Benny Prijonoa66c7152006-02-09 01:26:14 +00001745
1746/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001747 * Create first response to INVITE
1748 */
1749PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1750 pjsip_rx_data *rdata,
1751 int st_code,
1752 const pj_str_t *st_text,
1753 const pjmedia_sdp_session *sdp,
1754 pjsip_tx_data **p_tdata)
1755{
1756 pjsip_tx_data *tdata;
1757 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00001758 pjsip_status_code st_code2;
Benny Prijono64f851e2006-02-23 13:49:28 +00001759
1760 /* Verify arguments. */
1761 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1762
1763 /* Must have INVITE transaction. */
1764 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1765
1766 pjsip_dlg_inc_lock(inv->dlg);
1767
1768 /* Create response */
1769 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1770 &tdata);
1771 if (status != PJ_SUCCESS)
1772 goto on_return;
1773
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001774 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00001775 status = pjsip_timer_process_req(inv, rdata, &st_code2);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001776 if (status != PJ_SUCCESS) {
1777 pj_status_t status2;
1778
Nanang Izzuddin65add622009-08-11 16:26:20 +00001779 status2 = pjsip_dlg_modify_response(inv->dlg, tdata, st_code2, NULL);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001780 if (status2 != PJ_SUCCESS) {
1781 pjsip_tx_data_dec_ref(tdata);
1782 goto on_return;
1783 }
1784 status2 = pjsip_timer_update_resp(inv, tdata);
1785 if (status2 == PJ_SUCCESS)
1786 *p_tdata = tdata;
1787 else
1788 pjsip_tx_data_dec_ref(tdata);
1789
1790 goto on_return;
1791 }
1792
Benny Prijono64f851e2006-02-23 13:49:28 +00001793 /* Process SDP in answer */
1794 status = process_answer(inv, st_code, tdata, sdp);
1795 if (status != PJ_SUCCESS) {
1796 pjsip_tx_data_dec_ref(tdata);
1797 goto on_return;
1798 }
1799
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001800 /* Save this answer */
1801 inv->last_answer = tdata;
1802 pjsip_tx_data_add_ref(inv->last_answer);
1803 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1804 pjsip_tx_data_get_info(inv->last_answer)));
1805
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001806 /* Invoke Session Timers */
1807 pjsip_timer_update_resp(inv, tdata);
1808
Benny Prijono64f851e2006-02-23 13:49:28 +00001809 *p_tdata = tdata;
1810
1811on_return:
1812 pjsip_dlg_dec_lock(inv->dlg);
1813 return status;
1814}
1815
1816
1817/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001818 * Answer initial INVITE
1819 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001820 */
1821PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1822 int st_code,
1823 const pj_str_t *st_text,
1824 const pjmedia_sdp_session *local_sdp,
1825 pjsip_tx_data **p_tdata )
1826{
1827 pjsip_tx_data *last_res;
1828 pj_status_t status;
1829
1830 /* Verify arguments. */
1831 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1832
1833 /* Must have INVITE transaction. */
1834 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1835
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001836 /* Must have created an answer before */
1837 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001838
Benny Prijono64f851e2006-02-23 13:49:28 +00001839 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001840
1841 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001842 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001843 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1844 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001845 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001846
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001847 /* For non-2xx final response, strip message body */
1848 if (st_code >= 300) {
1849 last_res->msg->body = NULL;
1850 }
Benny Prijono268ca612006-02-07 12:34:11 +00001851
Benny Prijono26ff9062006-02-21 23:47:00 +00001852 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001853 status = process_answer(inv, st_code, last_res, local_sdp);
1854 if (status != PJ_SUCCESS) {
1855 pjsip_tx_data_dec_ref(last_res);
1856 goto on_return;
1857 }
Benny Prijono268ca612006-02-07 12:34:11 +00001858
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001859 /* Invoke Session Timers */
1860 pjsip_timer_update_resp(inv, last_res);
Benny Prijono268ca612006-02-07 12:34:11 +00001861
1862 *p_tdata = last_res;
1863
Benny Prijono64f851e2006-02-23 13:49:28 +00001864on_return:
1865 pjsip_dlg_dec_lock(inv->dlg);
1866 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001867}
1868
1869
1870/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001871 * Set SDP answer.
1872 */
1873PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1874 const pjmedia_sdp_session *sdp )
1875{
1876 pj_status_t status;
1877
1878 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1879
1880 pjsip_dlg_inc_lock(inv->dlg);
1881 status = pjmedia_sdp_neg_set_local_answer( inv->pool, inv->neg, sdp);
1882 pjsip_dlg_dec_lock(inv->dlg);
1883
1884 return status;
1885}
1886
1887
1888/*
Benny Prijono268ca612006-02-07 12:34:11 +00001889 * End session.
1890 */
1891PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
1892 int st_code,
1893 const pj_str_t *st_text,
1894 pjsip_tx_data **p_tdata )
1895{
1896 pjsip_tx_data *tdata;
1897 pj_status_t status;
1898
1899 /* Verify arguments. */
1900 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1901
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001902 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001903 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001904
Benny Prijono268ca612006-02-07 12:34:11 +00001905 /* Create appropriate message. */
1906 switch (inv->state) {
1907 case PJSIP_INV_STATE_CALLING:
1908 case PJSIP_INV_STATE_EARLY:
1909 case PJSIP_INV_STATE_INCOMING:
1910
1911 if (inv->role == PJSIP_ROLE_UAC) {
1912
1913 /* For UAC when session has not been confirmed, create CANCEL. */
1914
1915 /* MUST have the original UAC INVITE transaction. */
1916 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
1917
1918 /* But CANCEL should only be called when we have received a
1919 * provisional response. If we haven't received any responses,
1920 * just destroy the transaction.
1921 */
1922 if (inv->invite_tsx->status_code < 100) {
1923
Benny Prijono006a4e82009-04-26 11:30:22 +00001924 /* Do not stop INVITE retransmission, see ticket #506 */
1925 //pjsip_tsx_stop_retransmit(inv->invite_tsx);
Benny Prijono1dc8be02007-05-30 04:26:40 +00001926 inv->cancelling = PJ_TRUE;
1927 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00001928 *p_tdata = NULL;
Benny Prijono006a4e82009-04-26 11:30:22 +00001929 PJ_LOG(4, (inv->obj_name, "Delaying CANCEL since no "
1930 "provisional response is received yet"));
Benny Prijonofccab712006-02-22 22:23:22 +00001931 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001932 }
1933
1934 /* The CSeq here assumes that the dialog is started with an
1935 * INVITE session. This may not be correct; dialog can be
1936 * started as SUBSCRIBE session.
1937 * So fix this!
1938 */
1939 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
1940 inv->invite_tsx->last_tx,
1941 &tdata);
Benny Prijono99b04372009-04-26 11:02:04 +00001942 if (status != PJ_SUCCESS)
1943 return status;
1944
1945 /* Set timeout for the INVITE transaction, in case UAS is not
1946 * able to respond the INVITE with 487 final response. The
1947 * timeout value is 64*T1.
1948 */
1949 pjsip_tsx_set_timeout(inv->invite_tsx, 64 * pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00001950
1951 } else {
1952
1953 /* For UAS, send a final response. */
1954 tdata = inv->invite_tsx->last_tx;
1955 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
1956
Benny Prijono26ff9062006-02-21 23:47:00 +00001957 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
1958 // st_text);
1959 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001960 }
1961 break;
1962
1963 case PJSIP_INV_STATE_CONNECTING:
1964 case PJSIP_INV_STATE_CONFIRMED:
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001965 /* End Session Timer */
1966 pjsip_timer_end_session(inv);
1967
Benny Prijono268ca612006-02-07 12:34:11 +00001968 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001969 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
1970 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001971 break;
1972
1973 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00001974 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001975 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00001976
1977 default:
1978 pj_assert("!Invalid operation!");
1979 return PJ_EINVALIDOP;
1980 }
1981
1982 if (status != PJ_SUCCESS)
1983 return status;
1984
1985
1986 /* Done */
1987
Benny Prijono0606e702007-05-22 12:21:40 +00001988 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00001989 *p_tdata = tdata;
1990
1991 return PJ_SUCCESS;
1992}
1993
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001994/* Following redirection recursion, get next target from the target set and
1995 * notify user.
1996 *
1997 * Returns PJ_FALSE if recursion fails (either because there's no more target
1998 * or user rejects the recursion). If we return PJ_FALSE, caller should
1999 * disconnect the session.
2000 *
2001 * Note:
2002 * the event 'e' argument may be NULL.
2003 */
2004static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
2005 const pj_str_t *reason, pjsip_event *e)
2006{
Benny Prijono08a48b82008-11-27 12:42:07 +00002007 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002008 pjsip_target *target;
2009
2010 /* Won't redirect if the callback is not implemented. */
2011 if (mod_inv.cb.on_redirected == NULL)
2012 return PJ_FALSE;
2013
2014 if (reason == NULL)
2015 reason = pjsip_get_status_text(code);
2016
2017 /* Set status of current target */
2018 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
2019 code, reason);
2020
2021 /* Fetch next target from the target set. We only want to
2022 * process SIP/SIPS URI for now.
2023 */
2024 for (;;) {
2025 target = pjsip_target_set_get_next(&inv->dlg->target_set);
2026 if (target == NULL) {
2027 /* No more target. */
2028 return PJ_FALSE;
2029 }
2030
2031 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
2032 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
2033 {
2034 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
2035 reason = pjsip_get_status_text(code);
2036
2037 /* Mark this target as unusable and fetch next target. */
2038 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
2039 } else {
2040 /* Found a target */
2041 break;
2042 }
2043 }
2044
2045 /* We have target in 'target'. Set this target as current target
2046 * and notify callback.
2047 */
2048 pjsip_target_set_set_current(&inv->dlg->target_set, target);
2049
Benny Prijono08a48b82008-11-27 12:42:07 +00002050 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002051
2052
2053 /* Check what the application wants to do now */
2054 switch (op) {
2055 case PJSIP_REDIRECT_ACCEPT:
2056 case PJSIP_REDIRECT_STOP:
2057 /* Must increment session counter, that's the convention of the
2058 * pjsip_inv_process_redirect().
2059 */
2060 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2061
2062 /* Act on the recursion */
2063 pjsip_inv_process_redirect(inv, op, e);
2064 return PJ_TRUE;
2065
2066 case PJSIP_REDIRECT_PENDING:
2067 /* Increment session so that the dialog/session is not destroyed
2068 * while we're waiting for user confirmation.
2069 */
2070 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2071
2072 /* Also clear the invite_tsx variable, otherwise when this tsx is
2073 * terminated, it will also terminate the session.
2074 */
2075 inv->invite_tsx = NULL;
2076
2077 /* Done. The processing will continue once the application calls
2078 * pjsip_inv_process_redirect().
2079 */
2080 return PJ_TRUE;
2081
2082 case PJSIP_REDIRECT_REJECT:
2083 /* Recursively call this function again to fetch next target, if any.
2084 */
2085 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2086
2087 }
2088
2089 pj_assert(!"Should not reach here");
2090 return PJ_FALSE;
2091}
2092
2093
2094/* Process redirection/recursion */
2095PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2096 pjsip_redirect_op op,
2097 pjsip_event *e)
2098{
2099 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2100 pjsip_event usr_event;
2101 pj_status_t status = PJ_SUCCESS;
2102
2103 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2104
2105 if (e == NULL) {
2106 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2107 e = &usr_event;
2108 }
2109
2110 pjsip_dlg_inc_lock(inv->dlg);
2111
2112 /* Decrement session. That's the convention here to prevent the dialog
2113 * or session from being destroyed while we're waiting for user
2114 * confirmation.
2115 */
2116 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2117
2118 /* See what the application wants to do now */
2119 switch (op) {
2120 case PJSIP_REDIRECT_ACCEPT:
2121 /* User accept the redirection. Reset the session and resend the
2122 * INVITE request.
2123 */
2124 {
2125 pjsip_tx_data *tdata;
2126 pjsip_via_hdr *via;
2127
2128 /* Get the original INVITE request. */
2129 tdata = inv->invite_req;
2130 pjsip_tx_data_add_ref(tdata);
2131
2132 /* Restore strict route set.
2133 * See http://trac.pjsip.org/repos/ticket/492
2134 */
2135 pjsip_restore_strict_route_set(tdata);
2136
2137 /* Set target */
Benny Prijono20da7992008-12-18 16:48:43 +00002138 tdata->msg->line.req.uri = (pjsip_uri*)
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002139 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2140
2141 /* Remove branch param in Via header. */
2142 via = (pjsip_via_hdr*)
2143 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2144 via->branch_param.slen = 0;
2145
2146 /* Must invalidate the message! */
2147 pjsip_tx_data_invalidate_msg(tdata);
2148
2149 /* Reset the session */
2150 pjsip_inv_uac_restart(inv, PJ_FALSE);
2151
2152 /* (re)Send the INVITE request */
2153 status = pjsip_inv_send_msg(inv, tdata);
2154 }
2155 break;
2156
2157 case PJSIP_REDIRECT_STOP:
2158 /* User doesn't want the redirection. Disconnect the session now. */
2159 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2160 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2161
2162 /* Caller should expect that the invite session is gone now, so
2163 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2164 */
2165 break;
2166
2167 case PJSIP_REDIRECT_REJECT:
2168 /* Current target is rejected. Fetch next target if any. */
2169 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2170 inv_set_cause(inv, cancel_code,
2171 pjsip_get_status_text(cancel_code));
2172 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2173
2174 /* Tell caller that the invite session is gone now */
2175 status = PJSIP_ESESSIONTERMINATED;
2176 }
2177 break;
2178
2179
2180 case PJSIP_REDIRECT_PENDING:
2181 pj_assert(!"Should not happen");
2182 break;
2183 }
2184
2185
2186 pjsip_dlg_dec_lock(inv->dlg);
2187
2188 return status;
2189}
2190
Benny Prijono268ca612006-02-07 12:34:11 +00002191
2192/*
2193 * Create re-INVITE.
2194 */
2195PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2196 const pj_str_t *new_contact,
2197 const pjmedia_sdp_session *new_offer,
2198 pjsip_tx_data **p_tdata )
2199{
Benny Prijono26ff9062006-02-21 23:47:00 +00002200 pj_status_t status;
2201 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002202
Benny Prijono26ff9062006-02-21 23:47:00 +00002203 /* Check arguments. */
2204 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2205
2206 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002207 if (inv->invite_tsx!=NULL)
2208 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002209
2210
2211 pjsip_dlg_inc_lock(inv->dlg);
2212
2213 if (new_contact) {
2214 pj_str_t tmp;
2215 const pj_str_t STR_CONTACT = { "Contact", 7 };
2216
2217 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002218 contact_hdr = (pjsip_contact_hdr*)
2219 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002220 tmp.ptr, tmp.slen, NULL);
2221 if (!contact_hdr) {
2222 status = PJSIP_EINVALIDURI;
2223 goto on_return;
2224 }
2225 }
2226
2227
2228 if (new_offer) {
2229 if (!inv->neg) {
2230 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer,
2231 &inv->neg);
2232 if (status != PJ_SUCCESS)
2233 goto on_return;
2234
2235 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2236
2237 case PJMEDIA_SDP_NEG_STATE_NULL:
2238 pj_assert(!"Unexpected SDP neg state NULL");
2239 status = PJ_EBUG;
2240 goto on_return;
2241
2242 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2243 PJ_LOG(4,(inv->obj_name,
2244 "pjsip_inv_reinvite: already have an offer, new "
2245 "offer is ignored"));
2246 break;
2247
2248 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
2249 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
2250 new_offer);
2251 if (status != PJ_SUCCESS)
2252 goto on_return;
2253 break;
2254
2255 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2256 PJ_LOG(4,(inv->obj_name,
2257 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2258 "offer is ignored"));
2259 break;
2260
2261 case PJMEDIA_SDP_NEG_STATE_DONE:
2262 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2263 new_offer);
2264 if (status != PJ_SUCCESS)
2265 goto on_return;
2266 break;
2267 }
2268 }
2269
2270 if (contact_hdr)
2271 inv->dlg->local.contact = contact_hdr;
2272
2273 status = pjsip_inv_invite(inv, p_tdata);
2274
2275on_return:
2276 pjsip_dlg_dec_lock(inv->dlg);
2277 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002278}
2279
2280/*
2281 * Create UPDATE.
2282 */
2283PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2284 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002285 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002286 pjsip_tx_data **p_tdata )
2287{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002288 pjsip_contact_hdr *contact_hdr = NULL;
2289 pjsip_tx_data *tdata = NULL;
2290 pjmedia_sdp_session *sdp_copy;
2291 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002292
Benny Prijono1f7767b2007-10-03 18:28:49 +00002293 /* Verify arguments. */
2294 PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL);
2295
2296 /* Dialog must have been established */
2297 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2298 PJ_EINVALIDOP);
2299
2300 /* Invite session must not have been disconnected */
2301 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2302 PJ_EINVALIDOP);
2303
2304 /* Lock dialog. */
2305 pjsip_dlg_inc_lock(inv->dlg);
2306
2307 /* Process offer */
2308 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2309 PJ_LOG(4,(inv->dlg->obj_name,
2310 "Invalid SDP offer/answer state for UPDATE"));
2311 status = PJ_EINVALIDOP;
2312 goto on_error;
2313 }
2314
Benny Prijono60e31fc2009-04-23 11:50:25 +00002315 /* Notify negotiator about the new offer. This will fix the offer
2316 * with correct SDP origin.
2317 */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002318 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2319 offer);
2320 if (status != PJ_SUCCESS)
2321 goto on_error;
2322
Benny Prijono60e31fc2009-04-23 11:50:25 +00002323 /* Retrieve the "fixed" offer from negotiator */
2324 pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002325
2326 /* Update Contact if required */
2327 if (new_contact) {
2328 pj_str_t tmp;
2329 const pj_str_t STR_CONTACT = { "Contact", 7 };
2330
2331 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2332 contact_hdr = (pjsip_contact_hdr*)
2333 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2334 tmp.ptr, tmp.slen, NULL);
2335 if (!contact_hdr) {
2336 status = PJSIP_EINVALIDURI;
2337 goto on_error;
2338 }
2339
2340 inv->dlg->local.contact = contact_hdr;
2341 }
2342
2343 /* Create request */
2344 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2345 -1, &tdata);
2346 if (status != PJ_SUCCESS)
2347 goto on_error;
2348
2349 /* Attach SDP body */
2350 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2351 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2352
2353 /* Unlock dialog. */
2354 pjsip_dlg_dec_lock(inv->dlg);
2355
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002356 status = pjsip_timer_update_req(inv, tdata);
2357 if (status != PJ_SUCCESS)
2358 goto on_error;
2359
Benny Prijono1f7767b2007-10-03 18:28:49 +00002360 *p_tdata = tdata;
2361
2362 return PJ_SUCCESS;
2363
2364on_error:
2365 if (tdata)
2366 pjsip_tx_data_dec_ref(tdata);
2367
2368 /* Unlock dialog. */
2369 pjsip_dlg_dec_lock(inv->dlg);
2370
2371 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002372}
2373
2374/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002375 * Create an ACK request.
2376 */
2377PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2378 int cseq,
2379 pjsip_tx_data **p_tdata)
2380{
2381 const pjmedia_sdp_session *sdp = NULL;
2382 pj_status_t status;
2383
2384 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2385
2386 /* Lock dialog. */
2387 pjsip_dlg_inc_lock(inv->dlg);
2388
2389 /* Destroy last_ack */
2390 if (inv->last_ack) {
2391 pjsip_tx_data_dec_ref(inv->last_ack);
2392 inv->last_ack = NULL;
2393 }
2394
2395 /* Create new ACK request */
2396 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2397 cseq, &inv->last_ack);
2398 if (status != PJ_SUCCESS) {
2399 pjsip_dlg_dec_lock(inv->dlg);
2400 return status;
2401 }
2402
2403 /* See if we have pending SDP answer to send */
2404 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2405 if (sdp) {
2406 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2407 }
2408
2409 /* Keep this for subsequent response retransmission */
2410 inv->last_ack_cseq = cseq;
2411 pjsip_tx_data_add_ref(inv->last_ack);
2412
2413 /* Done */
2414 *p_tdata = inv->last_ack;
2415
2416 /* Unlock dialog. */
2417 pjsip_dlg_dec_lock(inv->dlg);
2418
2419 return PJ_SUCCESS;
2420}
2421
2422/*
Benny Prijono268ca612006-02-07 12:34:11 +00002423 * Send a request or response message.
2424 */
2425PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002426 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002427{
2428 pj_status_t status;
2429
2430 /* Verify arguments. */
2431 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2432
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002433 PJ_LOG(5,(inv->obj_name, "Sending %s",
2434 pjsip_tx_data_get_info(tdata)));
2435
Benny Prijono268ca612006-02-07 12:34:11 +00002436 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002437 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002438
Benny Prijono64158af2006-04-04 11:06:34 +00002439 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002440
Benny Prijono22e48c92008-03-20 14:40:50 +00002441 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002442 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2443 inv->invite_tsx)
2444 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002445 pjsip_tx_data_dec_ref(tdata);
2446 pjsip_dlg_dec_lock(inv->dlg);
2447 return PJ_EINVALIDOP;
2448 }
2449
2450 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002451 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002452 tsx_inv_data->inv = inv;
2453
Benny Prijono64158af2006-04-04 11:06:34 +00002454 pjsip_dlg_dec_lock(inv->dlg);
2455
2456 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2457 tsx_inv_data);
2458 if (status != PJ_SUCCESS)
2459 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002460
2461 } else {
2462 pjsip_cseq_hdr *cseq;
2463
2464 /* Can only do this to send response to original INVITE
2465 * request.
2466 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002467 PJ_ASSERT_RETURN((cseq=(pjsip_cseq_hdr*)pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL))!=NULL
Benny Prijono64f851e2006-02-23 13:49:28 +00002468 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002469 PJ_EINVALIDOP);
2470
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002471 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002472 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002473 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002474 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002475 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002476 }
2477
Benny Prijono268ca612006-02-07 12:34:11 +00002478 if (status != PJ_SUCCESS)
2479 return status;
2480 }
2481
2482 /* Done (?) */
2483 return PJ_SUCCESS;
2484}
2485
2486
Benny Prijono8ad55352006-02-08 11:16:05 +00002487/*
2488 * Respond to incoming CANCEL request.
2489 */
2490static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2491 pjsip_transaction *cancel_tsx,
2492 pjsip_rx_data *rdata)
2493{
2494 pjsip_tx_data *tdata;
2495 pjsip_transaction *invite_tsx;
2496 pj_str_t key;
2497 pj_status_t status;
2498
2499 /* See if we have matching INVITE server transaction: */
2500
2501 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002502 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002503 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2504
2505 if (invite_tsx == NULL) {
2506
2507 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002508 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002509 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002510 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002511 &tdata);
2512
2513 } else {
2514 /* Always answer CANCEL will 200 (OK) regardless of
2515 * the state of the INVITE transaction.
2516 */
2517 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2518 &tdata);
2519 }
2520
2521 /* See if we have created the response successfully. */
2522 if (status != PJ_SUCCESS) return;
2523
2524 /* Send the CANCEL response */
2525 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2526 if (status != PJ_SUCCESS) return;
2527
2528
2529 /* See if we need to terminate the UAS INVITE transaction
2530 * with 487 (Request Terminated) response.
2531 */
2532 if (invite_tsx && invite_tsx->status_code < 200) {
2533
2534 pj_assert(invite_tsx->last_tx != NULL);
2535
2536 tdata = invite_tsx->last_tx;
2537
2538 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002539 if (status == PJ_SUCCESS) {
2540 /* Remove the message body */
2541 tdata->msg->body = NULL;
Benny Prijono1e08e4f2009-05-13 08:57:38 +00002542 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
2543 status = pjsip_100rel_tx_response(inv, tdata);
2544 } else {
2545 status = pjsip_dlg_send_response(inv->dlg, invite_tsx,
2546 tdata);
2547 }
Benny Prijonofc8bb142007-11-08 09:56:50 +00002548 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002549 }
2550
2551 if (invite_tsx)
2552 pj_mutex_unlock(invite_tsx->mutex);
2553}
2554
2555
2556/*
2557 * Respond to incoming BYE request.
2558 */
2559static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2560 pjsip_transaction *bye_tsx,
2561 pjsip_rx_data *rdata,
2562 pjsip_event *e )
2563{
2564 pj_status_t status;
2565 pjsip_tx_data *tdata;
2566
2567 /* Respond BYE with 200: */
2568
2569 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2570 if (status != PJ_SUCCESS) return;
2571
2572 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2573 if (status != PJ_SUCCESS) return;
2574
2575 /* Terminate session: */
2576
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002577 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002578 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002579 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002580 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002581}
2582
2583/*
Benny Prijono38998232006-02-08 22:44:25 +00002584 * Respond to BYE request.
2585 */
2586static void inv_handle_bye_response( pjsip_inv_session *inv,
2587 pjsip_transaction *tsx,
2588 pjsip_rx_data *rdata,
2589 pjsip_event *e )
2590{
2591 pj_status_t status;
2592
2593 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002594 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002595 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2596 return;
2597 }
2598
2599 /* Handle 401/407 challenge. */
2600 if (tsx->status_code == 401 || tsx->status_code == 407) {
2601
2602 pjsip_tx_data *tdata;
2603
2604 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2605 rdata,
2606 tsx->last_tx,
2607 &tdata);
2608
2609 if (status != PJ_SUCCESS) {
2610
2611 /* Does not have proper credentials.
2612 * End the session anyway.
2613 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002614 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002615 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2616
2617 } else {
2618 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002619 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002620 }
2621
2622 } else {
2623
2624 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002625 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002626 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2627 }
2628
2629}
2630
2631/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002632 * Respond to incoming UPDATE request.
2633 */
2634static void inv_respond_incoming_update(pjsip_inv_session *inv,
2635 pjsip_rx_data *rdata)
2636{
2637 pjmedia_sdp_neg_state neg_state;
2638 pj_status_t status;
2639 pjsip_tx_data *tdata = NULL;
Nanang Izzuddin65add622009-08-11 16:26:20 +00002640 pjsip_status_code st_code;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002641
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002642 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00002643 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002644 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00002645 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002646 NULL, &tdata);
2647 goto on_return;
2648 }
2649
Benny Prijono1f7767b2007-10-03 18:28:49 +00002650 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2651
2652 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2653 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2654 status = pjsip_dlg_create_response(inv->dlg, rdata,
2655 PJSIP_SC_REQUEST_PENDING, NULL,
2656 &tdata);
2657 }
2658 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2659 * receive UPDATE while we haven't sent answer.
2660 */
2661 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2662 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2663 status = pjsip_dlg_create_response(inv->dlg, rdata,
2664 PJSIP_SC_INTERNAL_SERVER_ERROR,
2665 NULL, &tdata);
2666
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002667 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2668 * This is a valid scenario according to session-timer draft.
2669 */
2670 } else if (rdata->msg_info.msg->body == NULL) {
2671
2672 status = pjsip_dlg_create_response(inv->dlg, rdata,
2673 200, NULL, &tdata);
2674
Benny Prijono1f7767b2007-10-03 18:28:49 +00002675 } else {
2676 /* We receive new offer from remote */
2677 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2678
2679 /* Application MUST have supplied the answer by now.
2680 * If so, negotiate the SDP.
2681 */
2682 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2683 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2684 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2685 {
2686 /* Negotiation has failed */
2687 status = pjsip_dlg_create_response(inv->dlg, rdata,
2688 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2689 NULL, &tdata);
2690 } else {
2691 /* New media has been negotiated successfully, send 200/OK */
2692 status = pjsip_dlg_create_response(inv->dlg, rdata,
2693 PJSIP_SC_OK, NULL, &tdata);
2694 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002695 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002696 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2697 if (status == PJ_SUCCESS)
2698 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2699 }
2700 }
2701 }
2702
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002703on_return:
2704 /* Invoke Session Timers */
2705 if (status == PJ_SUCCESS)
2706 status = pjsip_timer_update_resp(inv, tdata);
2707
Benny Prijono1f7767b2007-10-03 18:28:49 +00002708 if (status != PJ_SUCCESS) {
2709 if (tdata != NULL) {
2710 pjsip_tx_data_dec_ref(tdata);
2711 tdata = NULL;
2712 }
2713 return;
2714 }
2715
2716 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2717}
2718
2719
2720/*
2721 * Handle incoming response to UAC UPDATE request.
2722 */
2723static void inv_handle_update_response( pjsip_inv_session *inv,
2724 pjsip_event *e)
2725{
2726 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2727 struct tsx_inv_data *tsx_inv_data = NULL;
2728 pj_status_t status = -1;
2729
Benny Prijono48ab2b72007-11-08 09:24:30 +00002730 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002731 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono48ab2b72007-11-08 09:24:30 +00002732 (tsx->status_code == 401 || tsx->status_code == 407)) {
2733
2734 pjsip_tx_data *tdata;
2735
2736 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2737 e->body.tsx_state.src.rdata,
2738 tsx->last_tx,
2739 &tdata);
2740
2741 if (status != PJ_SUCCESS) {
2742
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002743 /* Somehow failed. Probably it's not a good idea to terminate
2744 * the session since this is just a request within dialog. And
2745 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002746 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002747 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002748 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2749 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002750 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002751
2752 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002753 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002754 status = pjsip_inv_send_msg(inv, tdata);
2755 }
2756
2757 /* Process 2xx response */
2758 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002759 tsx->status_code/100 == 2 &&
2760 e->body.tsx_state.src.rdata->msg_info.msg->body)
2761 {
2762 status = inv_check_sdp_in_incoming_msg(inv, tsx,
2763 e->body.tsx_state.src.rdata);
2764
2765 } else {
2766 /* Get/attach invite session's transaction data */
2767 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2768 if (tsx_inv_data == NULL) {
2769 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2770 tsx_inv_data->inv = inv;
2771 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2772 }
2773 }
2774
2775 /* Otherwise if we don't get successful response, cancel
2776 * our negotiator.
2777 */
2778 if (status != PJ_SUCCESS &&
2779 pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
2780 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2781 {
2782 pjmedia_sdp_neg_cancel_offer(inv->neg);
2783
2784 /* Prevent from us cancelling different offer! */
2785 tsx_inv_data->sdp_done = PJ_TRUE;
2786 }
2787}
2788
2789
2790/*
2791 * Handle incoming reliable response.
2792 */
2793static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2794 pjsip_rx_data *rdata)
2795{
2796 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002797 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002798 pj_status_t status;
2799
2800 /* Create PRACK */
2801 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2802 if (status != PJ_SUCCESS)
2803 return;
2804
2805 /* See if we need to attach SDP answer on the PRACK request */
2806 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2807 if (sdp) {
2808 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2809 }
2810
2811 /* Send PRACK (must be using 100rel module!) */
2812 pjsip_100rel_send_prack(inv, tdata);
2813}
2814
2815
2816/*
2817 * Handle incoming PRACK.
2818 */
2819static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2820 pjsip_rx_data *rdata)
2821{
2822 pj_status_t status;
2823
2824 /* Run through 100rel module to see if we can accept this
2825 * PRACK request. The 100rel will send 200/OK to PRACK request.
2826 */
2827 status = pjsip_100rel_on_rx_prack(inv, rdata);
2828 if (status != PJ_SUCCESS)
2829 return;
2830
2831 /* Now check for SDP answer in the PRACK request */
2832 if (rdata->msg_info.msg->body) {
2833 status = inv_check_sdp_in_incoming_msg(inv,
2834 pjsip_rdata_get_tsx(rdata), rdata);
2835 } else {
2836 /* No SDP body */
2837 status = -1;
2838 }
2839
2840 /* If SDP negotiation has been successful, also mark the
2841 * SDP negotiation flag in the invite transaction to be
2842 * done too.
2843 */
2844 if (status == PJ_SUCCESS && inv->invite_tsx) {
2845 struct tsx_inv_data *tsx_inv_data;
2846
2847 /* Get/attach invite session's transaction data */
2848 tsx_inv_data = (struct tsx_inv_data*)
2849 inv->invite_tsx->mod_data[mod_inv.mod.id];
2850 if (tsx_inv_data == NULL) {
2851 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2852 struct tsx_inv_data);
2853 tsx_inv_data->inv = inv;
2854 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2855 }
2856
2857 tsx_inv_data->sdp_done = PJ_TRUE;
2858 }
2859}
2860
2861
2862/*
Benny Prijono8ad55352006-02-08 11:16:05 +00002863 * State NULL is before anything is sent/received.
2864 */
2865static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002866{
2867 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2868 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2869
2870 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2871
2872 if (tsx->method.id == PJSIP_INVITE_METHOD) {
2873
Benny Prijono64f851e2006-02-23 13:49:28 +00002874 /* Keep the initial INVITE transaction. */
2875 if (inv->invite_tsx == NULL)
2876 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00002877
Benny Prijono64f851e2006-02-23 13:49:28 +00002878 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00002879
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002880 /* Save the original INVITE request, if on_redirected() callback
2881 * is implemented. We may need to resend the INVITE if we receive
2882 * redirection response.
2883 */
2884 if (mod_inv.cb.on_redirected) {
2885 if (inv->invite_req) {
2886 pjsip_tx_data_dec_ref(inv->invite_req);
2887 inv->invite_req = NULL;
2888 }
2889 inv->invite_req = tsx->last_tx;
2890 pjsip_tx_data_add_ref(inv->invite_req);
2891 }
2892
Benny Prijono268ca612006-02-07 12:34:11 +00002893 switch (tsx->state) {
2894 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002895 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002896 break;
2897 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002898 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002899 break;
2900 }
2901
2902 } else {
2903 switch (tsx->state) {
2904 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002905 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002906 break;
Benny Prijono38998232006-02-08 22:44:25 +00002907 case PJSIP_TSX_STATE_PROCEEDING:
2908 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
2909 if (tsx->status_code > 100)
2910 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
2911 break;
Benny Prijono2285e7e2008-12-17 14:28:18 +00002912 case PJSIP_TSX_STATE_TERMINATED:
2913 /* there is a failure in sending response. */
2914 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2915 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2916 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002917 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002918 inv_on_state_incoming(inv, e);
2919 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002920 }
2921 }
2922
2923 } else {
2924 pj_assert(!"Unexpected transaction type");
2925 }
2926}
2927
Benny Prijono8ad55352006-02-08 11:16:05 +00002928/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002929 * Generic UAC transaction handler:
2930 * - resend request on 401 or 407 response.
2931 * - terminate dialog on 408 and 481 response.
2932 */
2933static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
2934 pjsip_event *e)
2935{
2936 /* RFC 3261 Section 12.2.1.2:
2937 * If the response for a request within a dialog is a 481
2938 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
2939 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
2940 * no response at all is received for the request (the client
2941 * transaction would inform the TU about the timeout.)
2942 *
2943 * For INVITE initiated dialogs, terminating the dialog consists of
2944 * sending a BYE.
2945 *
2946 * Note:
2947 * according to X, this should terminate dialog usage only, not the
2948 * dialog.
2949 */
2950 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2951
2952 pj_assert(tsx->role == PJSIP_UAC_ROLE);
2953
2954 /* Note that 481 response to CANCEL does not terminate dialog usage,
2955 * but only the transaction.
2956 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00002957 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
2958 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002959 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00002960 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
2961 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
2962 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002963 {
2964 pjsip_tx_data *bye;
2965 pj_status_t status;
2966
2967 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2968 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2969
2970 /* Send BYE */
2971 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2972 -1, &bye);
2973 if (status == PJ_SUCCESS) {
2974 pjsip_inv_send_msg(inv, bye);
2975 }
2976
2977 return PJ_TRUE; /* Handled */
2978
2979 }
2980 /* Handle 401/407 challenge. */
2981 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2982 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
2983 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
2984 {
2985
2986 pjsip_tx_data *tdata;
2987 pj_status_t status;
2988
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002989 if (tsx->method.id == PJSIP_INVITE_METHOD)
2990 inv->invite_tsx = NULL;
2991
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002992 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2993 e->body.tsx_state.src.rdata,
2994 tsx->last_tx, &tdata);
2995
2996 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002997 /* Somehow failed. Probably it's not a good idea to terminate
2998 * the session since this is just a request within dialog. And
2999 * even if we terminate we should send BYE.
3000 */
3001 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003002 inv_set_cause(inv, PJSIP_SC_OK, NULL);
3003 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003004 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003005
3006 } else {
3007 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003008 status = pjsip_inv_send_msg(inv, tdata);
3009 }
3010
3011 return PJ_TRUE; /* Handled */
3012
3013 } else {
3014 return PJ_FALSE; /* Unhandled */
3015 }
3016}
3017
3018
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003019/* Handle call rejection, especially with regard to processing call
3020 * redirection. We need to handle the following scenarios:
3021 * - 3xx response is received -- see if on_redirected() callback is
3022 * implemented. If so, add the Contact URIs in the response to the
3023 * target set and notify user.
3024 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
3025 * if so fetch the next target if any and notify the on_redirected()
3026 * callback.
3027 * - for other cases -- disconnect the session.
3028 */
3029static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
3030{
3031 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3032 pj_status_t status;
3033
3034 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
3035
3036 if (mod_inv.cb.on_redirected == NULL) {
3037
3038 /* Redirection callback is not implemented, disconnect the
3039 * call.
3040 */
3041 goto terminate_session;
3042
3043 } else {
3044 const pjsip_msg *res_msg;
3045
3046 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
3047
3048 /* Gather all Contact URI's in the response and add them
3049 * to target set. The function will take care of removing
3050 * duplicate URI's.
3051 */
3052 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
3053 inv->dlg->pool, res_msg);
3054
3055 /* Recurse to alternate targets if application allows us */
3056 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3057 {
3058 /* Recursion fails, terminate session now */
3059 goto terminate_session;
3060 }
3061
3062 /* Done */
3063 }
3064
3065 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
3066 !inv->cancelling)
3067 {
3068
3069 /* Handle authentication failure:
3070 * Resend the request with Authorization header.
3071 */
3072 pjsip_tx_data *tdata;
3073
3074 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
3075 e->body.tsx_state.src.rdata,
3076 tsx->last_tx,
3077 &tdata);
3078
3079 if (status != PJ_SUCCESS) {
3080
3081 /* Does not have proper credentials. If we are currently
3082 * recursing, try the next target. Otherwise end the session.
3083 */
3084 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3085 {
3086 /* Recursion fails, terminate session now */
3087 goto terminate_session;
3088 }
3089
3090 } else {
3091
3092 /* Restart session. */
3093 pjsip_inv_uac_restart(inv, PJ_FALSE);
3094
3095 /* Send the request. */
3096 status = pjsip_inv_send_msg(inv, tdata);
3097 }
3098
3099 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3100 /* Global error */
3101 goto terminate_session;
3102
3103 } else {
3104 /* See if we have alternate target to try */
3105 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3106 /* Recursion fails, terminate session now */
3107 goto terminate_session;
3108 }
3109 }
3110 return;
3111
3112terminate_session:
3113 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3114 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3115}
3116
3117
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003118/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003119 * State CALLING is after sending initial INVITE request but before
3120 * any response (with tag) is received.
3121 */
3122static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003123{
3124 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3125 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003126 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003127
3128 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3129
Benny Prijono8ad55352006-02-08 11:16:05 +00003130 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003131
3132 switch (tsx->state) {
3133
Benny Prijono64f851e2006-02-23 13:49:28 +00003134 case PJSIP_TSX_STATE_CALLING:
3135 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3136 break;
3137
Benny Prijono268ca612006-02-07 12:34:11 +00003138 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003139 if (inv->pending_cancel) {
3140 pjsip_tx_data *cancel;
3141
3142 inv->pending_cancel = PJ_FALSE;
3143
3144 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3145 if (status == PJ_SUCCESS && cancel)
3146 status = pjsip_inv_send_msg(inv, cancel);
3147 }
3148
Benny Prijono268ca612006-02-07 12:34:11 +00003149 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003150
Benny Prijono8ad55352006-02-08 11:16:05 +00003151 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003152
3153 inv_check_sdp_in_incoming_msg(inv, tsx,
3154 e->body.tsx_state.src.rdata);
3155
Benny Prijono1f7767b2007-10-03 18:28:49 +00003156 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3157 inv_handle_incoming_reliable_response(
3158 inv, e->body.tsx_state.src.rdata);
3159 }
3160
Benny Prijono268ca612006-02-07 12:34:11 +00003161 } else {
3162 /* Ignore 100 (Trying) response, as it doesn't change
3163 * session state. It only ceases retransmissions.
3164 */
3165 }
3166 break;
3167
3168 case PJSIP_TSX_STATE_COMPLETED:
3169 if (tsx->status_code/100 == 2) {
3170
3171 /* This should not happen.
3172 * When transaction receives 2xx, it should be terminated
3173 */
3174 pj_assert(0);
Benny Prijono8ad55352006-02-08 11:16:05 +00003175 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003176
3177 inv_check_sdp_in_incoming_msg(inv, tsx,
3178 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003179
3180 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003181 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003182 }
3183 break;
3184
3185 case PJSIP_TSX_STATE_TERMINATED:
3186 /* INVITE transaction can be terminated either because UAC
3187 * transaction received 2xx response or because of transport
3188 * error.
3189 */
3190 if (tsx->status_code/100 == 2) {
3191 /* This must be receipt of 2xx response */
3192
3193 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003194 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003195
Benny Prijonoa66c7152006-02-09 01:26:14 +00003196 inv_check_sdp_in_incoming_msg(inv, tsx,
3197 e->body.tsx_state.src.rdata);
3198
Benny Prijono268ca612006-02-07 12:34:11 +00003199 /* Send ACK */
3200 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3201
Benny Prijonod5f9f422007-11-25 04:40:07 +00003202 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003203
Benny Prijono268ca612006-02-07 12:34:11 +00003204 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003205 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003206 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003207 }
3208 break;
3209
Benny Prijono34a404e2006-02-09 14:38:30 +00003210 default:
3211 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003212 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003213
Benny Prijono1f7767b2007-10-03 18:28:49 +00003214 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003215 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003216 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003217 * Transaction Does Not Exist), 408, or when it's timed out. In these
3218 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003219 * Note that 481 response to CANCEL does not terminate dialog usage,
3220 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003221 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003222 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3223 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003224 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3225 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003226 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003227 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003228 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003229 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3230 }
Benny Prijono268ca612006-02-07 12:34:11 +00003231 }
3232}
3233
Benny Prijono8ad55352006-02-08 11:16:05 +00003234/*
3235 * State INCOMING is after we received the request, but before
3236 * responses with tag are sent.
3237 */
3238static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003239{
3240 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3241 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3242
3243 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3244
Benny Prijono8ad55352006-02-08 11:16:05 +00003245 if (tsx == inv->invite_tsx) {
3246
3247 /*
3248 * Handle the INVITE state transition.
3249 */
3250
Benny Prijono268ca612006-02-07 12:34:11 +00003251 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003252
Benny Prijono64f851e2006-02-23 13:49:28 +00003253 case PJSIP_TSX_STATE_TRYING:
3254 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3255 break;
3256
Benny Prijono268ca612006-02-07 12:34:11 +00003257 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003258 /*
3259 * Transaction sent provisional response.
3260 */
Benny Prijono268ca612006-02-07 12:34:11 +00003261 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003262 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003263 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003264
Benny Prijono268ca612006-02-07 12:34:11 +00003265 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003266 /*
3267 * Transaction sent final response.
3268 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003269 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003270 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003271 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003272 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003273 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003274 }
Benny Prijono268ca612006-02-07 12:34:11 +00003275 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003276
Benny Prijono268ca612006-02-07 12:34:11 +00003277 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003278 /*
3279 * This happens on transport error (e.g. failed to send
3280 * response)
3281 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003282 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003283 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003284 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003285
Benny Prijono268ca612006-02-07 12:34:11 +00003286 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003287 pj_assert(!"Unexpected INVITE state");
3288 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003289 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003290
3291 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3292 tsx->role == PJSIP_ROLE_UAS &&
3293 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3294 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3295 {
3296
3297 /*
3298 * Handle incoming CANCEL request.
3299 */
3300
3301 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3302
Benny Prijono268ca612006-02-07 12:34:11 +00003303 }
3304}
3305
Benny Prijono8ad55352006-02-08 11:16:05 +00003306/*
3307 * State EARLY is for both UAS and UAC, after response with To tag
3308 * is sent/received.
3309 */
3310static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003311{
3312 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3313 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3314
3315 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3316
Benny Prijono8ad55352006-02-08 11:16:05 +00003317 if (tsx == inv->invite_tsx) {
3318
3319 /*
3320 * Handle the INVITE state progress.
3321 */
Benny Prijono268ca612006-02-07 12:34:11 +00003322
3323 switch (tsx->state) {
3324
3325 case PJSIP_TSX_STATE_PROCEEDING:
3326 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003327 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003328
3329 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3330 inv_check_sdp_in_incoming_msg(inv, tsx,
3331 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003332
3333 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3334 inv_handle_incoming_reliable_response(
3335 inv, e->body.tsx_state.src.rdata);
3336 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003337 }
Benny Prijono268ca612006-02-07 12:34:11 +00003338 break;
3339
3340 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003341 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003342 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003343 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3344 inv_check_sdp_in_incoming_msg(inv, tsx,
3345 e->body.tsx_state.src.rdata);
3346 }
3347
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003348 } else if (tsx->role == PJSIP_ROLE_UAC) {
3349
3350 handle_uac_call_rejection(inv, e);
3351
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003352 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003353 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003354 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003355 }
Benny Prijono268ca612006-02-07 12:34:11 +00003356 break;
3357
Benny Prijonof3195072006-02-14 21:15:30 +00003358 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003359 /* For some reason can go here (maybe when ACK for 2xx has
3360 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003361
Benny Prijono268ca612006-02-07 12:34:11 +00003362 case PJSIP_TSX_STATE_TERMINATED:
3363 /* INVITE transaction can be terminated either because UAC
3364 * transaction received 2xx response or because of transport
3365 * error.
3366 */
3367 if (tsx->status_code/100 == 2) {
3368
3369 /* This must be receipt of 2xx response */
3370
3371 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003372 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003373
Benny Prijonoa66c7152006-02-09 01:26:14 +00003374 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3375 inv_check_sdp_in_incoming_msg(inv, tsx,
3376 e->body.tsx_state.src.rdata);
3377 }
3378
Benny Prijono268ca612006-02-07 12:34:11 +00003379 /* if UAC, send ACK and move state to confirmed. */
3380 if (tsx->role == PJSIP_ROLE_UAC) {
3381 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3382
Benny Prijonod5f9f422007-11-25 04:40:07 +00003383 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003384 }
3385
3386 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003387 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003388 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003389 }
3390 break;
3391
3392 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003393 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003394 }
3395
Benny Prijono8ad55352006-02-08 11:16:05 +00003396 } else if (inv->role == PJSIP_ROLE_UAS &&
3397 tsx->role == PJSIP_ROLE_UAS &&
3398 tsx->method.id == PJSIP_CANCEL_METHOD &&
3399 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3400 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3401 {
Benny Prijono268ca612006-02-07 12:34:11 +00003402
Benny Prijono8ad55352006-02-08 11:16:05 +00003403 /*
3404 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003405 */
3406
Benny Prijono8ad55352006-02-08 11:16:05 +00003407 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3408
Benny Prijono1f7767b2007-10-03 18:28:49 +00003409 } else if (tsx->role == PJSIP_ROLE_UAS &&
3410 tsx->state == PJSIP_TSX_STATE_TRYING &&
3411 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003412 {
3413 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003414 * Handle incoming UPDATE
3415 */
3416 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3417
3418
3419 } else if (tsx->role == PJSIP_ROLE_UAC &&
3420 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3421 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3422 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3423 {
3424 /*
3425 * Handle response to outgoing UPDATE request.
3426 */
3427 inv_handle_update_response(inv, e);
3428
3429 } else if (tsx->role == PJSIP_ROLE_UAS &&
3430 tsx->state == PJSIP_TSX_STATE_TRYING &&
3431 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3432 {
3433 /*
3434 * Handle incoming PRACK
3435 */
3436 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3437
3438 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003439
3440 /* Generic handling for UAC tsx completion */
3441 handle_uac_tsx_response(inv, e);
Benny Prijono7efa2d62009-04-27 12:50:16 +00003442
3443 } else if (tsx->role == PJSIP_ROLE_UAS &&
3444 tsx->method.id == PJSIP_BYE_METHOD &&
3445 tsx->status_code < 200 &&
3446 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3447 {
3448 /* Received BYE before the 2xx/OK response to INVITE.
3449 * Assume that the 2xx/OK response is lost and the BYE
3450 * arrives earlier.
3451 */
3452 inv_respond_incoming_bye(inv, tsx, e->body.tsx_state.src.rdata, e);
3453
3454 /* Set timer just in case we will never get the final response
3455 * for INVITE.
3456 */
3457 pjsip_tsx_set_timeout(inv->invite_tsx, 64*pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00003458 }
3459}
3460
Benny Prijono8ad55352006-02-08 11:16:05 +00003461/*
3462 * State CONNECTING is after 2xx response to INVITE is sent/received.
3463 */
3464static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003465{
3466 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3467 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3468
3469 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3470
Benny Prijono8ad55352006-02-08 11:16:05 +00003471 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003472
Benny Prijono8ad55352006-02-08 11:16:05 +00003473 /*
3474 * Handle INVITE state progression.
3475 */
Benny Prijono268ca612006-02-07 12:34:11 +00003476 switch (tsx->state) {
3477
3478 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003479 /* It can only go here if incoming ACK request has the same Via
3480 * branch parameter as the INVITE transaction.
3481 */
3482 if (tsx->status_code/100 == 2) {
3483 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3484 inv_check_sdp_in_incoming_msg(inv, tsx,
3485 e->body.tsx_state.src.rdata);
3486 }
3487
Benny Prijono38998232006-02-08 22:44:25 +00003488 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003489 }
Benny Prijono268ca612006-02-07 12:34:11 +00003490 break;
3491
3492 case PJSIP_TSX_STATE_TERMINATED:
3493 /* INVITE transaction can be terminated either because UAC
3494 * transaction received 2xx response or because of transport
3495 * error.
3496 */
3497 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003498 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003499 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003500 }
3501 break;
3502
3503 case PJSIP_TSX_STATE_DESTROYED:
3504 /* Do nothing. */
3505 break;
3506
3507 default:
3508 pj_assert(!"Unexpected state");
3509 }
3510
Benny Prijono8ad55352006-02-08 11:16:05 +00003511 } else if (tsx->role == PJSIP_ROLE_UAS &&
3512 tsx->method.id == PJSIP_BYE_METHOD &&
3513 tsx->status_code < 200 &&
3514 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3515 {
3516
3517 /*
3518 * Handle incoming BYE.
3519 */
3520
3521 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3522
Benny Prijono38998232006-02-08 22:44:25 +00003523 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3524 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003525 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3526 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003527 {
3528
3529 /*
3530 * Outgoing BYE
3531 */
3532 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3533
Benny Prijono268ca612006-02-07 12:34:11 +00003534 }
Benny Prijono70127222006-07-02 14:53:05 +00003535 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3536 tsx->role == PJSIP_ROLE_UAS &&
3537 tsx->status_code < 200 &&
3538 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3539 {
Benny Prijono38998232006-02-08 22:44:25 +00003540
Benny Prijono70127222006-07-02 14:53:05 +00003541 /*
3542 * Handle strandled incoming CANCEL.
3543 */
3544 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3545 pjsip_tx_data *tdata;
3546 pj_status_t status;
3547
3548 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3549 if (status != PJ_SUCCESS) return;
3550
3551 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3552 if (status != PJ_SUCCESS) return;
3553
Benny Prijono1f7767b2007-10-03 18:28:49 +00003554 } else if (tsx->role == PJSIP_ROLE_UAS &&
3555 tsx->state == PJSIP_TSX_STATE_TRYING &&
3556 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3557 {
3558 /*
3559 * Handle incoming UPDATE
3560 */
3561 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3562
3563
3564 } else if (tsx->role == PJSIP_ROLE_UAC &&
3565 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3566 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3567 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3568 {
3569 /*
3570 * Handle response to outgoing UPDATE request.
3571 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003572 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003573 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003574
3575 } else if (tsx->role == PJSIP_ROLE_UAS &&
3576 tsx->state == PJSIP_TSX_STATE_TRYING &&
3577 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3578 {
3579 /*
3580 * Handle incoming PRACK
3581 */
3582 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3583
3584 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono87402382008-02-21 19:28:21 +00003585
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003586 /* Generic handling for UAC tsx completion */
3587 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003588 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003589
Benny Prijono268ca612006-02-07 12:34:11 +00003590}
3591
Benny Prijono8ad55352006-02-08 11:16:05 +00003592/*
3593 * State CONFIRMED is after ACK is sent/received.
3594 */
3595static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003596{
3597 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3598 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3599
3600 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3601
Benny Prijono268ca612006-02-07 12:34:11 +00003602
Benny Prijono8ad55352006-02-08 11:16:05 +00003603 if (tsx->method.id == PJSIP_BYE_METHOD &&
3604 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003605 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3606 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003607 {
Benny Prijono38998232006-02-08 22:44:25 +00003608
Benny Prijono8ad55352006-02-08 11:16:05 +00003609 /*
Benny Prijono38998232006-02-08 22:44:25 +00003610 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003611 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003612
Benny Prijonoa66c7152006-02-09 01:26:14 +00003613 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003614
Benny Prijono8ad55352006-02-08 11:16:05 +00003615 }
3616 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3617 tsx->role == PJSIP_ROLE_UAS &&
3618 tsx->status_code < 200 &&
3619 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3620 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003621
Benny Prijono8ad55352006-02-08 11:16:05 +00003622 /*
3623 * Handle incoming BYE.
3624 */
Benny Prijono268ca612006-02-07 12:34:11 +00003625
Benny Prijono8ad55352006-02-08 11:16:05 +00003626 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3627
Benny Prijono268ca612006-02-07 12:34:11 +00003628 }
Benny Prijono70127222006-07-02 14:53:05 +00003629 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3630 tsx->role == PJSIP_ROLE_UAS &&
3631 tsx->status_code < 200 &&
3632 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3633 {
3634
3635 /*
3636 * Handle strandled incoming CANCEL.
3637 */
3638 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3639 pjsip_tx_data *tdata;
3640 pj_status_t status;
3641
3642 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3643 if (status != PJ_SUCCESS) return;
3644
3645 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3646 if (status != PJ_SUCCESS) return;
3647
3648 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003649 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3650 tsx->role == PJSIP_ROLE_UAS)
3651 {
3652
3653 /*
3654 * Handle incoming re-INVITE
3655 */
3656 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3657
3658 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3659 pjsip_tx_data *tdata;
3660 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00003661 pjsip_status_code st_code;
Benny Prijono26ff9062006-02-21 23:47:00 +00003662
3663 /* Check if we have INVITE pending. */
3664 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003665 pj_str_t reason;
3666
3667 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003668
3669 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003670 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3671 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003672 if (status != PJ_SUCCESS)
3673 return;
3674
3675 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3676
3677
3678 return;
3679 }
3680
3681 /* Save the invite transaction. */
3682 inv->invite_tsx = tsx;
3683
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003684 /* Process session timers headers in the re-INVITE */
Nanang Izzuddin65add622009-08-11 16:26:20 +00003685 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003686 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00003687 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
3688 NULL, &tdata);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003689 if (status != PJ_SUCCESS)
3690 return;
3691
3692 pjsip_timer_update_resp(inv, tdata);
3693 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3694 return;
3695 }
3696
Benny Prijono26ff9062006-02-21 23:47:00 +00003697 /* Process SDP in incoming message. */
3698 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3699
3700 if (status != PJ_SUCCESS) {
3701
3702 /* Not Acceptable */
3703 const pjsip_hdr *accept;
3704
3705 status = pjsip_dlg_create_response(inv->dlg, rdata,
3706 488, NULL, &tdata);
3707 if (status != PJ_SUCCESS)
3708 return;
3709
3710
3711 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3712 NULL);
3713 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003714 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003715 pjsip_hdr_clone(tdata->pool, accept));
3716 }
3717
3718 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3719
3720 return;
3721 }
3722
3723 /* Create 2xx ANSWER */
3724 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3725 if (status != PJ_SUCCESS)
3726 return;
3727
Benny Prijono7d910092007-06-20 04:19:46 +00003728 /* If the INVITE request has SDP body, send answer.
3729 * Otherwise generate offer from local active SDP.
3730 */
3731 if (rdata->msg_info.msg->body != NULL) {
3732 status = process_answer(inv, 200, tdata, NULL);
3733 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003734 /* INVITE does not have SDP.
3735 * If on_create_offer() callback is implemented, ask app.
3736 * to generate an offer, otherwise just send active local
3737 * SDP to signal that nothing gets modified.
3738 */
3739 pjmedia_sdp_session *sdp = NULL;
3740
3741 if (mod_inv.cb.on_create_offer) {
3742 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3743 if (sdp) {
Benny Prijono60e31fc2009-04-23 11:50:25 +00003744 /* Notify negotiator about the new offer. This will
3745 * fix the offer with correct SDP origin.
3746 */
Benny Prijono77998ce2007-06-20 10:03:46 +00003747 status = pjmedia_sdp_neg_modify_local_offer(dlg->pool,
3748 inv->neg,
3749 sdp);
Benny Prijono60e31fc2009-04-23 11:50:25 +00003750
3751 /* Retrieve the "fixed" offer from negotiator */
Benny Prijonoc8fe3df2009-04-29 20:56:57 +00003752 if (status==PJ_SUCCESS) {
3753 const pjmedia_sdp_session *lsdp = NULL;
3754 pjmedia_sdp_neg_get_neg_local(inv->neg, &lsdp);
3755 sdp = (pjmedia_sdp_session*)lsdp;
3756 }
Benny Prijono77998ce2007-06-20 10:03:46 +00003757 }
3758 }
3759
3760 if (sdp == NULL) {
3761 const pjmedia_sdp_session *active_sdp = NULL;
3762 status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
3763 inv->neg,
3764 &active_sdp);
3765 if (status == PJ_SUCCESS)
3766 sdp = (pjmedia_sdp_session*) active_sdp;
3767 }
3768
3769 if (sdp) {
3770 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003771 }
3772 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003773
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003774 if (status != PJ_SUCCESS) {
3775 /*
3776 * SDP negotiation has failed.
3777 */
3778 pj_status_t rc;
3779 pj_str_t reason;
3780
3781 /* Delete the 2xx answer */
3782 pjsip_tx_data_dec_ref(tdata);
3783
3784 /* Create 500 response */
3785 reason = pj_str("SDP negotiation failed");
3786 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3787 &tdata);
3788 if (rc == PJ_SUCCESS) {
3789 pjsip_warning_hdr *w;
3790 const pj_str_t *endpt_name;
3791
3792 endpt_name = pjsip_endpt_name(dlg->endpt);
3793 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3794 endpt_name,
3795 status);
3796 if (w)
3797 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3798
3799 pjsip_inv_send_msg(inv, tdata);
3800 }
3801 return;
3802 }
3803
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003804 /* Invoke Session Timers */
3805 pjsip_timer_update_resp(inv, tdata);
3806
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003807 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003808 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003809
Benny Prijono7d910092007-06-20 04:19:46 +00003810 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
3811 /* This is the case where ACK has the same branch as
3812 * the INVITE request.
3813 */
3814 if (tsx->status_code/100 == 2 &&
3815 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3816 {
3817 inv_check_sdp_in_incoming_msg(inv, tsx,
3818 e->body.tsx_state.src.rdata);
3819 }
3820
Benny Prijono26ff9062006-02-21 23:47:00 +00003821 }
3822
3823 }
3824 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3825 tsx->role == PJSIP_ROLE_UAC)
3826 {
Benny Prijono22e48c92008-03-20 14:40:50 +00003827
Benny Prijono26ff9062006-02-21 23:47:00 +00003828 /*
3829 * Handle outgoing re-INVITE
3830 */
Benny Prijono22e48c92008-03-20 14:40:50 +00003831 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
3832
Benny Prijono61fc5e62008-06-25 18:35:31 +00003833 /* Must not have other pending INVITE transaction */
3834 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
3835
Benny Prijono22e48c92008-03-20 14:40:50 +00003836 /* Save pending invite transaction */
3837 inv->invite_tsx = tsx;
3838
3839 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
3840 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00003841 {
3842
3843 /* Re-INVITE was accepted. */
3844
3845 /* Process SDP */
3846 inv_check_sdp_in_incoming_msg(inv, tsx,
3847 e->body.tsx_state.src.rdata);
3848
3849 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00003850 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003851
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003852 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00003853
3854 /* Handle response that terminates dialog */
3855 /* Nothing to do (already handled) */
3856
Benny Prijono77998ce2007-06-20 10:03:46 +00003857 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
3858
3859 pjmedia_sdp_neg_state neg_state;
3860
3861 /* Outgoing INVITE transaction has failed, cancel SDP nego */
3862 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
3863 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
3864 pjmedia_sdp_neg_cancel_offer(inv->neg);
3865 }
Benny Prijonoe641a742009-05-01 12:01:28 +00003866
3867 if (tsx == inv->invite_tsx)
3868 inv->invite_tsx = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00003869 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003870
3871 } else if (tsx->role == PJSIP_ROLE_UAS &&
3872 tsx->state == PJSIP_TSX_STATE_TRYING &&
3873 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3874 {
3875 /*
3876 * Handle incoming UPDATE
3877 */
3878 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3879
3880 } else if (tsx->role == PJSIP_ROLE_UAC &&
3881 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3882 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3883 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3884 {
3885 /*
3886 * Handle response to outgoing UPDATE request.
3887 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003888 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003889 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003890
3891 } else if (tsx->role == PJSIP_ROLE_UAS &&
3892 tsx->state == PJSIP_TSX_STATE_TRYING &&
3893 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3894 {
3895 /*
3896 * Handle strandled incoming PRACK
3897 */
3898 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3899
3900 } else if (tsx->role == PJSIP_ROLE_UAC) {
3901 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003902 * Handle 401/407/408/481 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00003903 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003904 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003905 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003906
Benny Prijono268ca612006-02-07 12:34:11 +00003907}
3908
Benny Prijono8ad55352006-02-08 11:16:05 +00003909/*
3910 * After session has been terminated, but before dialog is destroyed
3911 * (because dialog has other usages, or because dialog is waiting for
3912 * the last transaction to terminate).
3913 */
3914static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003915{
Benny Prijono8ad55352006-02-08 11:16:05 +00003916 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3917 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00003918
Benny Prijono8ad55352006-02-08 11:16:05 +00003919 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3920
Benny Prijono70127222006-07-02 14:53:05 +00003921 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00003922 tsx->status_code < 200 &&
3923 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3924 {
Benny Prijono70127222006-07-02 14:53:05 +00003925 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00003926
3927 /*
Benny Prijono70127222006-07-02 14:53:05 +00003928 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00003929 */
Benny Prijono70127222006-07-02 14:53:05 +00003930 if (tsx->method.id == PJSIP_BYE_METHOD) {
3931 inv_respond_incoming_bye( inv, tsx, rdata, e );
3932 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
3933 /*
3934 * Respond CANCEL with 200/OK too.
3935 */
3936 pjsip_tx_data *tdata;
3937 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00003938
Benny Prijono70127222006-07-02 14:53:05 +00003939 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3940 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00003941
Benny Prijono70127222006-07-02 14:53:05 +00003942 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3943 if (status != PJ_SUCCESS) return;
3944
3945 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00003946
3947 } else if (tsx->role == PJSIP_ROLE_UAC) {
3948 /*
3949 * Handle 401/407/408/481 response
3950 */
3951 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00003952 }
Benny Prijono268ca612006-02-07 12:34:11 +00003953}
3954