blob: b522b3bdfdc1a4be7475c5fbe2502453ebf44902 [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 Prijono40d62b62009-08-12 17:53:47 +000080#define POOL_INIT_SIZE 256
81#define POOL_INC_SIZE 256
82
Benny Prijono268ca612006-02-07 12:34:11 +000083/*
84 * Static prototypes.
85 */
86static pj_status_t mod_inv_load(pjsip_endpoint *endpt);
87static pj_status_t mod_inv_unload(void);
88static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata);
89static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata);
90static void mod_inv_on_tsx_state(pjsip_transaction*, pjsip_event*);
91
Benny Prijono8ad55352006-02-08 11:16:05 +000092static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e);
93static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e);
94static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e);
95static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e);
96static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e);
97static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e);
98static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e);
Benny Prijono268ca612006-02-07 12:34:11 +000099
Benny Prijono7d910092007-06-20 04:19:46 +0000100static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
101 pjsip_transaction *tsx,
102 pjsip_rx_data *rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +0000103static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv );
104static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
105 const pjmedia_sdp_session *c_sdp);
Benny Prijono7d910092007-06-20 04:19:46 +0000106static pj_status_t process_answer( pjsip_inv_session *inv,
107 int st_code,
108 pjsip_tx_data *tdata,
109 const pjmedia_sdp_session *local_sdp);
110
Nanang Izzuddincf69c282009-10-16 06:28:56 +0000111static pj_status_t handle_timer_response(pjsip_inv_session *inv,
112 const pjsip_rx_data *rdata,
113 pj_bool_t end_sess_on_failure);
114
Benny Prijono8ad55352006-02-08 11:16:05 +0000115static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
Benny Prijono268ca612006-02-07 12:34:11 +0000116{
117 &inv_on_state_null,
118 &inv_on_state_calling,
119 &inv_on_state_incoming,
120 &inv_on_state_early,
121 &inv_on_state_connecting,
122 &inv_on_state_confirmed,
123 &inv_on_state_disconnected,
Benny Prijono268ca612006-02-07 12:34:11 +0000124};
125
126static struct mod_inv
127{
128 pjsip_module mod;
129 pjsip_endpoint *endpt;
130 pjsip_inv_callback cb;
Benny Prijono268ca612006-02-07 12:34:11 +0000131} mod_inv =
132{
133 {
Benny Prijono2f8992b2006-02-25 21:16:36 +0000134 NULL, NULL, /* prev, next. */
135 { "mod-invite", 10 }, /* Name. */
136 -1, /* Id */
137 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
138 &mod_inv_load, /* load() */
139 NULL, /* start() */
140 NULL, /* stop() */
141 &mod_inv_unload, /* unload() */
142 &mod_inv_on_rx_request, /* on_rx_request() */
143 &mod_inv_on_rx_response, /* on_rx_response() */
144 NULL, /* on_tx_request. */
145 NULL, /* on_tx_response() */
146 &mod_inv_on_tsx_state, /* on_tsx_state() */
Benny Prijono268ca612006-02-07 12:34:11 +0000147 }
148};
149
150
Benny Prijonoa66c7152006-02-09 01:26:14 +0000151/* Invite session data to be attached to transaction. */
152struct tsx_inv_data
153{
Benny Prijono8fcb4332008-10-31 18:01:48 +0000154 pjsip_inv_session *inv; /* The invite session */
155 pj_bool_t sdp_done; /* SDP negotiation done for this tsx? */
156 pj_str_t done_tag; /* To tag in RX response with answer */
157 pj_bool_t done_early;/* Negotiation was done for early med? */
Benny Prijonoa66c7152006-02-09 01:26:14 +0000158};
159
Benny Prijono8ad55352006-02-08 11:16:05 +0000160/*
161 * Module load()
162 */
Benny Prijono268ca612006-02-07 12:34:11 +0000163static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
164{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000165 pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},
166 { "UPDATE", 6}};
Benny Prijono56315612006-07-18 14:39:40 +0000167 pj_str_t accepted = { "application/sdp", 15 };
Benny Prijono268ca612006-02-07 12:34:11 +0000168
Benny Prijono1f7767b2007-10-03 18:28:49 +0000169 /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */
Benny Prijono268ca612006-02-07 12:34:11 +0000170 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
171 PJ_ARRAY_SIZE(allowed), allowed);
172
Benny Prijono56315612006-07-18 14:39:40 +0000173 /* Register "application/sdp" in Accept header */
174 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
175 1, &accepted);
176
Benny Prijono268ca612006-02-07 12:34:11 +0000177 return PJ_SUCCESS;
178}
179
Benny Prijono8ad55352006-02-08 11:16:05 +0000180/*
181 * Module unload()
182 */
Benny Prijono268ca612006-02-07 12:34:11 +0000183static pj_status_t mod_inv_unload(void)
184{
185 /* Should remove capability here */
186 return PJ_SUCCESS;
187}
188
Benny Prijono8ad55352006-02-08 11:16:05 +0000189/*
Benny Prijono38998232006-02-08 22:44:25 +0000190 * Set session state.
191 */
192void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
193 pjsip_event *e)
194{
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000195 pjsip_inv_state prev_state = inv->state;
Benny Prijono7d910092007-06-20 04:19:46 +0000196 pj_status_t status;
197
198
199 /* If state is confirmed, check that SDP negotiation is done,
200 * otherwise disconnect the session.
201 */
202 if (state == PJSIP_INV_STATE_CONFIRMED) {
203 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
204 pjsip_tx_data *bye;
205
206 PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
207 "session"));
208
209 status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
210 NULL, &bye);
211 if (status == PJ_SUCCESS && bye)
212 status = pjsip_inv_send_msg(inv, bye);
213
214 return;
215 }
216 }
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000217
218 /* Set state. */
Benny Prijono38998232006-02-08 22:44:25 +0000219 inv->state = state;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000220
221 /* If state is DISCONNECTED, cause code MUST have been set. */
222 pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
223 inv->cause != 0);
224
225 /* Call on_state_changed() callback. */
226 if (mod_inv.cb.on_state_changed && inv->notify)
Benny Prijono38998232006-02-08 22:44:25 +0000227 (*mod_inv.cb.on_state_changed)(inv, e);
228
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000229 /* Only decrement when previous state is not already DISCONNECTED */
230 if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
231 prev_state != PJSIP_INV_STATE_DISCONNECTED)
232 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000233 if (inv->last_ack) {
234 pjsip_tx_data_dec_ref(inv->last_ack);
235 inv->last_ack = NULL;
236 }
Benny Prijono5e51a4e2008-11-27 00:06:46 +0000237 if (inv->invite_req) {
238 pjsip_tx_data_dec_ref(inv->invite_req);
239 inv->invite_req = NULL;
240 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000241 pjsip_100rel_end_session(inv);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000242 pjsip_timer_end_session(inv);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000243 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
Benny Prijono40d62b62009-08-12 17:53:47 +0000244
245 /* Release the flip-flop pools */
246 pj_pool_release(inv->pool_prov);
Benny Prijonobcc8dd72010-02-09 12:28:03 +0000247 inv->pool_prov = NULL;
Benny Prijono40d62b62009-08-12 17:53:47 +0000248 pj_pool_release(inv->pool_active);
Benny Prijonobcc8dd72010-02-09 12:28:03 +0000249 inv->pool_active = NULL;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000250 }
Benny Prijono38998232006-02-08 22:44:25 +0000251}
252
253
254/*
Benny Prijono0b6340c2006-06-13 22:21:23 +0000255 * Set cause code.
256 */
257void inv_set_cause(pjsip_inv_session *inv, int cause_code,
258 const pj_str_t *cause_text)
259{
260 if (cause_code > inv->cause) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000261 inv->cause = (pjsip_status_code) cause_code;
Benny Prijono0b6340c2006-06-13 22:21:23 +0000262 if (cause_text)
263 pj_strdup(inv->pool, &inv->cause_text, cause_text);
264 else if (cause_code/100 == 2)
265 inv->cause_text = pj_str("Normal call clearing");
266 else
267 inv->cause_text = *pjsip_get_status_text(cause_code);
268 }
269}
270
271
Benny Prijono1f7767b2007-10-03 18:28:49 +0000272/*
273 * Check if outgoing request needs to have SDP answer.
274 * This applies for both ACK and PRACK requests.
275 */
Benny Prijono9569a0b2007-10-04 15:35:26 +0000276static const pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv,
277 pjsip_transaction *tsx)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000278{
279 pjmedia_sdp_neg_state neg_state;
Benny Prijono9569a0b2007-10-04 15:35:26 +0000280 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000281 pj_status_t status;
282
283 /* If SDP negotiator is ready, start negotiation. */
284
285 /* Start nego when appropriate. */
286 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
287 PJMEDIA_SDP_NEG_STATE_NULL;
288
289 if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) {
290
291 /* Nothing to do */
292
293 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
294 pjmedia_sdp_neg_has_local_answer(inv->neg) )
295 {
296 struct tsx_inv_data *tsx_inv_data;
Benny Prijonod5f9f422007-11-25 04:40:07 +0000297 struct tsx_inv_data dummy;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000298
Benny Prijonod5f9f422007-11-25 04:40:07 +0000299 /* Get invite session's transaction data.
300 * Note that tsx may be NULL, for example when application sends
301 * delayed ACK request (at this time, the original INVITE
302 * transaction may have been destroyed.
303 */
304 if (tsx) {
305 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
306 } else {
307 tsx_inv_data = &dummy;
308 pj_bzero(&dummy, sizeof(dummy));
309 dummy.inv = inv;
310 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000311
312 status = inv_negotiate_sdp(inv);
313 if (status != PJ_SUCCESS)
314 return NULL;
315
316 /* Mark this transaction has having SDP offer/answer done. */
317 tsx_inv_data->sdp_done = 1;
318
319 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
320
321 } else {
322 /* This remark is only valid for ACK.
323 PJ_LOG(4,(inv->dlg->obj_name,
324 "FYI, the SDP negotiator state (%s) is in a mess "
325 "when sending this ACK/PRACK request",
326 pjmedia_sdp_neg_state_str(neg_state)));
327 */
328 }
329
330 return sdp;
331}
332
Benny Prijono0b6340c2006-06-13 22:21:23 +0000333
334/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000335 * Send ACK for 2xx response.
336 */
Benny Prijonod5f9f422007-11-25 04:40:07 +0000337static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +0000338{
Benny Prijonod5f9f422007-11-25 04:40:07 +0000339 pjsip_rx_data *rdata;
Benny Prijono268ca612006-02-07 12:34:11 +0000340 pj_status_t status;
341
Benny Prijonod5f9f422007-11-25 04:40:07 +0000342 if (e->type == PJSIP_EVENT_TSX_STATE)
343 rdata = e->body.tsx_state.src.rdata;
344 else if (e->type == PJSIP_EVENT_RX_MSG)
345 rdata = e->body.rx_msg.rdata;
346 else {
347 pj_assert(!"Unsupported event type");
348 return PJ_EBUG;
349 }
350
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000351 PJ_LOG(5,(inv->obj_name, "Received %s, sending ACK",
352 pjsip_rx_data_get_info(rdata)));
353
Benny Prijono9a048642010-02-10 08:48:27 +0000354 /* Check if we have cached ACK request. Must not use the cached ACK
355 * if it's still marked as pending by transport (#1011)
356 */
357 if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq &&
358 !inv->last_ack->is_pending)
359 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000360 pjsip_tx_data_add_ref(inv->last_ack);
Benny Prijonod5f9f422007-11-25 04:40:07 +0000361
362 } else if (mod_inv.cb.on_send_ack) {
363 /* If application handles ACK transmission manually, just notify the
364 * callback
365 */
366 PJ_LOG(5,(inv->obj_name, "Received %s, notifying application callback",
367 pjsip_rx_data_get_info(rdata)));
368
369 (*mod_inv.cb.on_send_ack)(inv, rdata);
370 return PJ_SUCCESS;
371
Benny Prijono1f7767b2007-10-03 18:28:49 +0000372 } else {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000373 status = pjsip_inv_create_ack(inv, rdata->msg_info.cseq->cseq,
374 &inv->last_ack);
Benny Prijono268ca612006-02-07 12:34:11 +0000375 }
376
Benny Prijono1f7767b2007-10-03 18:28:49 +0000377 /* Send ACK */
378 status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000379 if (status != PJ_SUCCESS) {
380 /* Better luck next time */
381 pj_assert(!"Unable to send ACK!");
382 return status;
383 }
384
Benny Prijonod5f9f422007-11-25 04:40:07 +0000385
Benny Prijonoe6da48a2008-09-22 14:36:00 +0000386 /* Set state to CONFIRMED (if we're not in CONFIRMED yet).
387 * But don't set it to CONFIRMED if we're already DISCONNECTED
388 * (this may have been a late 200/OK response.
389 */
390 if (inv->state < PJSIP_INV_STATE_CONFIRMED) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000391 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
392 }
393
Benny Prijono268ca612006-02-07 12:34:11 +0000394 return PJ_SUCCESS;
395}
396
Benny Prijono8ad55352006-02-08 11:16:05 +0000397/*
398 * Module on_rx_request()
399 *
400 * This callback is called for these events:
401 * - endpoint receives request which was unhandled by higher priority
402 * modules (e.g. transaction layer, dialog layer).
403 * - dialog distributes incoming request to its usages.
404 */
405static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
406{
407 pjsip_method *method;
Benny Prijono38998232006-02-08 22:44:25 +0000408 pjsip_dialog *dlg;
409 pjsip_inv_session *inv;
Benny Prijono8ad55352006-02-08 11:16:05 +0000410
411 /* Only wants to receive request from a dialog. */
Benny Prijono38998232006-02-08 22:44:25 +0000412 dlg = pjsip_rdata_get_dlg(rdata);
413 if (dlg == NULL)
Benny Prijono8ad55352006-02-08 11:16:05 +0000414 return PJ_FALSE;
415
Benny Prijonoa1e69682007-05-11 15:14:34 +0000416 inv = (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono38998232006-02-08 22:44:25 +0000417
Benny Prijono8ad55352006-02-08 11:16:05 +0000418 /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
419 * If we need to send response, it will be sent in the state
420 * handlers.
421 */
422 method = &rdata->msg_info.msg->line.req.method;
423
Benny Prijono70127222006-07-02 14:53:05 +0000424 if (method->id == PJSIP_INVITE_METHOD) {
425 return PJ_TRUE;
426 }
427
428 /* BYE and CANCEL must have existing invite session */
429 if (method->id == PJSIP_BYE_METHOD ||
430 method->id == PJSIP_CANCEL_METHOD)
Benny Prijono8ad55352006-02-08 11:16:05 +0000431 {
Benny Prijono70127222006-07-02 14:53:05 +0000432 if (inv == NULL)
433 return PJ_FALSE;
434
Benny Prijono8ad55352006-02-08 11:16:05 +0000435 return PJ_TRUE;
436 }
437
Benny Prijono38998232006-02-08 22:44:25 +0000438 /* On receipt ACK request, when state is CONNECTING,
439 * move state to CONFIRMED.
440 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000441 if (method->id == PJSIP_ACK_METHOD && inv) {
Benny Prijono38998232006-02-08 22:44:25 +0000442
Benny Prijonof521eb02006-08-06 23:07:25 +0000443 /* Ignore ACK if pending INVITE transaction has not finished. */
444 if (inv->invite_tsx &&
445 inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
446 {
447 return PJ_TRUE;
448 }
449
Benny Prijono5eff0432006-02-09 14:14:21 +0000450 /* Terminate INVITE transaction, if it's still present. */
451 if (inv->invite_tsx &&
452 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
453 {
Benny Prijono7d910092007-06-20 04:19:46 +0000454 /* Before we terminate INVITE transaction, process the SDP
Benny Prijono59e9e952008-09-21 22:55:43 +0000455 * in the ACK request, if any.
456 * Only do this when invite state is not already disconnected
457 * (http://trac.pjsip.org/repos/ticket/640).
Benny Prijono7d910092007-06-20 04:19:46 +0000458 */
Benny Prijono59e9e952008-09-21 22:55:43 +0000459 if (inv->state < PJSIP_INV_STATE_DISCONNECTED) {
460 inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
Nanang Izzuddin0fd92672010-06-16 15:26:18 +0000461
462 /* Check if local offer got no SDP answer and INVITE session
463 * is in CONFIRMED state.
464 */
465 if (pjmedia_sdp_neg_get_state(inv->neg)==
466 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
467 inv->state==PJSIP_INV_STATE_CONFIRMED)
468 {
469 pjmedia_sdp_neg_cancel_offer(inv->neg);
470 }
Benny Prijono59e9e952008-09-21 22:55:43 +0000471 }
Benny Prijono7d910092007-06-20 04:19:46 +0000472
473 /* Now we can terminate the INVITE transaction */
Benny Prijonof521eb02006-08-06 23:07:25 +0000474 pj_assert(inv->invite_tsx->status_code >= 200);
Benny Prijono5eff0432006-02-09 14:14:21 +0000475 pjsip_tsx_terminate(inv->invite_tsx,
476 inv->invite_tsx->status_code);
477 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000478 if (inv->last_answer) {
479 pjsip_tx_data_dec_ref(inv->last_answer);
480 inv->last_answer = NULL;
481 }
Benny Prijono5eff0432006-02-09 14:14:21 +0000482 }
483
Benny Prijono32ac8fe2006-03-02 21:16:55 +0000484 /* On receipt of ACK, only set state to confirmed when state
485 * is CONNECTING (e.g. we don't want to set the state to confirmed
486 * when we receive ACK retransmission after sending non-2xx!)
487 */
488 if (inv->state == PJSIP_INV_STATE_CONNECTING) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000489 pjsip_event event;
490
491 PJSIP_EVENT_INIT_RX_MSG(event, rdata);
492 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
493 }
Benny Prijono38998232006-02-08 22:44:25 +0000494 }
495
Benny Prijono8ad55352006-02-08 11:16:05 +0000496 return PJ_FALSE;
497}
498
Nanang Izzuddincf69c282009-10-16 06:28:56 +0000499/* This function will process Session Timer headers in received
500 * 2xx or 422 response of INVITE/UPDATE request.
501 */
502static pj_status_t handle_timer_response(pjsip_inv_session *inv,
503 const pjsip_rx_data *rdata,
504 pj_bool_t end_sess_on_failure)
505{
506 pjsip_status_code st_code;
507 pj_status_t status;
508
509 status = pjsip_timer_process_resp(inv, rdata, &st_code);
510 if (status != PJ_SUCCESS && end_sess_on_failure) {
511 pjsip_tx_data *tdata;
512 pj_status_t status2;
513
514 status2 = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
515 if (tdata && status2 == PJ_SUCCESS)
516 pjsip_inv_send_msg(inv, tdata);
517 }
518
519 return status;
520}
521
Benny Prijono8ad55352006-02-08 11:16:05 +0000522/*
523 * Module on_rx_response().
524 *
525 * This callback is called for these events:
526 * - dialog distributes incoming 2xx response to INVITE (outside
527 * transaction) to its usages.
528 * - endpoint distributes strayed responses.
529 */
Benny Prijono268ca612006-02-07 12:34:11 +0000530static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
531{
532 pjsip_dialog *dlg;
533 pjsip_inv_session *inv;
534 pjsip_msg *msg = rdata->msg_info.msg;
535
536 dlg = pjsip_rdata_get_dlg(rdata);
537
538 /* Ignore responses outside dialog */
539 if (dlg == NULL)
540 return PJ_FALSE;
541
542 /* Ignore responses not belonging to invite session */
543 inv = pjsip_dlg_get_inv_session(dlg);
544 if (inv == NULL)
545 return PJ_FALSE;
546
547 /* This MAY be retransmission of 2xx response to INVITE.
548 * If it is, we need to send ACK.
549 */
550 if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
Benny Prijono26ff9062006-02-21 23:47:00 +0000551 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
552 inv->invite_tsx == NULL)
553 {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000554 pjsip_event e;
Benny Prijono268ca612006-02-07 12:34:11 +0000555
Benny Prijonod5f9f422007-11-25 04:40:07 +0000556 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
557 inv_send_ack(inv, &e);
Benny Prijono268ca612006-02-07 12:34:11 +0000558 return PJ_TRUE;
559
560 }
561
562 /* No other processing needs to be done here. */
563 return PJ_FALSE;
564}
565
Benny Prijono8ad55352006-02-08 11:16:05 +0000566/*
567 * Module on_tsx_state()
568 *
569 * This callback is called by dialog framework for all transactions
570 * inside the dialog for all its dialog usages.
571 */
Benny Prijono268ca612006-02-07 12:34:11 +0000572static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
573{
574 pjsip_dialog *dlg;
575 pjsip_inv_session *inv;
576
577 dlg = pjsip_tsx_get_dlg(tsx);
578 if (dlg == NULL)
579 return;
580
581 inv = pjsip_dlg_get_inv_session(dlg);
582 if (inv == NULL)
583 return;
584
585 /* Call state handler for the invite session. */
586 (*inv_state_handler[inv->state])(inv, e);
587
588 /* Call on_tsx_state */
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000589 if (mod_inv.cb.on_tsx_state_changed && inv->notify)
Benny Prijono268ca612006-02-07 12:34:11 +0000590 (*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
591
Benny Prijono46249942007-02-19 22:23:14 +0000592 /* Clear invite transaction when tsx is confirmed.
593 * Previously we set invite_tsx to NULL only when transaction has
594 * terminated, but this didn't work when ACK has the same Via branch
595 * value as the INVITE (see http://www.pjsip.org/trac/ticket/113)
596 */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000597 if (tsx->state>=PJSIP_TSX_STATE_CONFIRMED && tsx == inv->invite_tsx) {
Benny Prijono46249942007-02-19 22:23:14 +0000598 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000599 if (inv->last_answer) {
600 pjsip_tx_data_dec_ref(inv->last_answer);
601 inv->last_answer = NULL;
602 }
603 }
Benny Prijono268ca612006-02-07 12:34:11 +0000604}
605
Benny Prijono8ad55352006-02-08 11:16:05 +0000606
607/*
608 * Initialize the invite module.
609 */
Benny Prijono268ca612006-02-07 12:34:11 +0000610PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
Benny Prijono268ca612006-02-07 12:34:11 +0000611 const pjsip_inv_callback *cb)
612{
613 pj_status_t status;
614
615 /* Check arguments. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000616 PJ_ASSERT_RETURN(endpt && cb, PJ_EINVAL);
Benny Prijono268ca612006-02-07 12:34:11 +0000617
618 /* Some callbacks are mandatory */
619 PJ_ASSERT_RETURN(cb->on_state_changed && cb->on_new_session, PJ_EINVAL);
620
621 /* Check if module already registered. */
622 PJ_ASSERT_RETURN(mod_inv.mod.id == -1, PJ_EINVALIDOP);
623
624 /* Copy param. */
625 pj_memcpy(&mod_inv.cb, cb, sizeof(pjsip_inv_callback));
626
627 mod_inv.endpt = endpt;
Benny Prijono268ca612006-02-07 12:34:11 +0000628
629 /* Register the module. */
630 status = pjsip_endpt_register_module(endpt, &mod_inv.mod);
Benny Prijono053f5222006-11-11 16:16:04 +0000631 if (status != PJ_SUCCESS)
632 return status;
Benny Prijono268ca612006-02-07 12:34:11 +0000633
Benny Prijono053f5222006-11-11 16:16:04 +0000634 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +0000635}
636
Benny Prijono8ad55352006-02-08 11:16:05 +0000637/*
638 * Get the instance of invite module.
639 */
Benny Prijono268ca612006-02-07 12:34:11 +0000640PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
641{
642 return &mod_inv.mod;
643}
644
645
Benny Prijono632ce712006-02-09 14:01:40 +0000646
Benny Prijono8ad55352006-02-08 11:16:05 +0000647/*
648 * Return the invite session for the specified dialog.
649 */
Benny Prijono268ca612006-02-07 12:34:11 +0000650PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
651{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000652 return (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono268ca612006-02-07 12:34:11 +0000653}
654
Benny Prijono8ad55352006-02-08 11:16:05 +0000655
Benny Prijono268ca612006-02-07 12:34:11 +0000656/*
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000657 * Get INVITE state name.
658 */
659PJ_DEF(const char *) pjsip_inv_state_name(pjsip_inv_state state)
660{
661 PJ_ASSERT_RETURN(state >= PJSIP_INV_STATE_NULL &&
662 state <= PJSIP_INV_STATE_DISCONNECTED,
663 "??");
664
665 return inv_state_names[state];
666}
667
668/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000669 * Create UAC invite session.
Benny Prijono268ca612006-02-07 12:34:11 +0000670 */
671PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
672 const pjmedia_sdp_session *local_sdp,
673 unsigned options,
674 pjsip_inv_session **p_inv)
675{
676 pjsip_inv_session *inv;
677 pj_status_t status;
678
679 /* Verify arguments. */
680 PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
681
Benny Prijono8eae8382006-08-10 21:44:26 +0000682 /* Must lock dialog first */
683 pjsip_dlg_inc_lock(dlg);
684
Benny Prijono268ca612006-02-07 12:34:11 +0000685 /* Normalize options */
686 if (options & PJSIP_INV_REQUIRE_100REL)
687 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000688 if (options & PJSIP_INV_REQUIRE_TIMER)
689 options |= PJSIP_INV_SUPPORT_TIMER;
690
691 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000692 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +0000693 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000694
695 inv->pool = dlg->pool;
696 inv->role = PJSIP_ROLE_UAC;
697 inv->state = PJSIP_INV_STATE_NULL;
698 inv->dlg = dlg;
699 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000700 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000701 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +0000702
Benny Prijono40d62b62009-08-12 17:53:47 +0000703 /* Create flip-flop pool (see ticket #877) */
704 /* (using inv->obj_name as temporary variable for pool names */
705 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg->pool);
706 inv->pool_prov = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
707 POOL_INIT_SIZE, POOL_INC_SIZE);
708 inv->pool_active = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
709 POOL_INIT_SIZE, POOL_INC_SIZE);
710
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000711 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +0000712 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000713
Benny Prijono268ca612006-02-07 12:34:11 +0000714 /* Create negotiator if local_sdp is specified. */
715 if (local_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +0000716 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
717 local_sdp, &inv->neg);
Benny Prijono8eae8382006-08-10 21:44:26 +0000718 if (status != PJ_SUCCESS) {
719 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000720 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000721 }
Benny Prijono268ca612006-02-07 12:34:11 +0000722 }
723
724 /* Register invite as dialog usage. */
725 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +0000726 if (status != PJ_SUCCESS) {
727 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000728 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000729 }
Benny Prijono268ca612006-02-07 12:34:11 +0000730
731 /* Increment dialog session */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000732 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +0000733
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000734 /* Create 100rel handler */
735 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000736
Benny Prijono268ca612006-02-07 12:34:11 +0000737 /* Done */
738 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000739
Benny Prijono8eae8382006-08-10 21:44:26 +0000740 pjsip_dlg_dec_lock(dlg);
741
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000742 PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
743 dlg->obj_name));
744
Benny Prijono268ca612006-02-07 12:34:11 +0000745 return PJ_SUCCESS;
746}
747
748/*
749 * Verify incoming INVITE request.
750 */
Benny Prijono87a90212008-01-23 20:29:30 +0000751PJ_DEF(pj_status_t) pjsip_inv_verify_request2(pjsip_rx_data *rdata,
752 unsigned *options,
753 const pjmedia_sdp_session *r_sdp,
754 const pjmedia_sdp_session *l_sdp,
755 pjsip_dialog *dlg,
756 pjsip_endpoint *endpt,
757 pjsip_tx_data **p_tdata)
Benny Prijono268ca612006-02-07 12:34:11 +0000758{
759 pjsip_msg *msg;
760 pjsip_allow_hdr *allow;
761 pjsip_supported_hdr *sup_hdr;
762 pjsip_require_hdr *req_hdr;
Benny Prijono8b33bba2010-06-02 03:03:43 +0000763 pjsip_contact_hdr *c_hdr;
Benny Prijono268ca612006-02-07 12:34:11 +0000764 int code = 200;
765 unsigned rem_option = 0;
766 pj_status_t status = PJ_SUCCESS;
767 pjsip_hdr res_hdr_list;
768
769 /* Init return arguments. */
770 if (p_tdata) *p_tdata = NULL;
771
772 /* Verify arguments. */
773 PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);
774
775 /* Normalize options */
776 if (*options & PJSIP_INV_REQUIRE_100REL)
777 *options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000778 if (*options & PJSIP_INV_REQUIRE_TIMER)
779 *options |= PJSIP_INV_SUPPORT_TIMER;
Benny Prijono07fe2302010-06-24 12:33:18 +0000780 if (*options & PJSIP_INV_REQUIRE_ICE)
781 *options |= PJSIP_INV_SUPPORT_ICE;
Benny Prijono268ca612006-02-07 12:34:11 +0000782
783 /* Get the message in rdata */
784 msg = rdata->msg_info.msg;
785
786 /* Must be INVITE request. */
787 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
788 msg->line.req.method.id == PJSIP_INVITE_METHOD,
789 PJ_EINVAL);
790
791 /* If tdata is specified, then either dlg or endpt must be specified */
792 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
793
794 /* Get the endpoint */
795 endpt = endpt ? endpt : dlg->endpt;
796
797 /* Init response header list */
798 pj_list_init(&res_hdr_list);
799
Benny Prijono8b33bba2010-06-02 03:03:43 +0000800 /* Check the Contact header */
801 c_hdr = (pjsip_contact_hdr*)
802 pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
803 if (!c_hdr || !c_hdr->uri) {
804 /* Missing Contact header or Contact contains "*" */
805 pjsip_warning_hdr *w;
806 pj_str_t warn_text;
807
808 warn_text = pj_str("Bad/missing Contact header");
809 w = pjsip_warning_hdr_create(rdata->tp_info.pool, 399,
810 pjsip_endpt_name(endpt),
811 &warn_text);
812 if (w) {
813 pj_list_push_back(&res_hdr_list, w);
814 }
815
816 code = PJSIP_SC_BAD_REQUEST;
817 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
818 goto on_return;
819 }
820
Benny Prijono87a90212008-01-23 20:29:30 +0000821 /* Check the request body, see if it's something that we support,
822 * only when the body hasn't been parsed before.
Benny Prijono268ca612006-02-07 12:34:11 +0000823 */
Benny Prijono87a90212008-01-23 20:29:30 +0000824 if (r_sdp==NULL && msg->body) {
Benny Prijono268ca612006-02-07 12:34:11 +0000825 pjsip_msg_body *body = msg->body;
826 pj_str_t str_application = {"application", 11};
827 pj_str_t str_sdp = { "sdp", 3 };
828 pjmedia_sdp_session *sdp;
829
830 /* Check content type. */
831 if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||
832 pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)
833 {
834 /* Not "application/sdp" */
835 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
836 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
837
838 if (p_tdata) {
839 /* Add Accept header to response */
840 pjsip_accept_hdr *acc;
841
842 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
843 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
844 acc->values[acc->count++] = pj_str("application/sdp");
845 pj_list_push_back(&res_hdr_list, acc);
846 }
847
848 goto on_return;
849 }
850
851 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000852 status = pjmedia_sdp_parse(rdata->tp_info.pool,
853 (char*)body->data, body->len, &sdp);
Benny Prijono268ca612006-02-07 12:34:11 +0000854 if (status == PJ_SUCCESS)
855 status = pjmedia_sdp_validate(sdp);
856
857 if (status != PJ_SUCCESS) {
858 /* Unparseable or invalid SDP */
859 code = PJSIP_SC_BAD_REQUEST;
860
861 if (p_tdata) {
862 /* Add Warning header. */
863 pjsip_warning_hdr *w;
864
865 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
866 pjsip_endpt_name(endpt),
867 status);
868 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
869
870 pj_list_push_back(&res_hdr_list, w);
871 }
872
873 goto on_return;
874 }
875
Benny Prijono87a90212008-01-23 20:29:30 +0000876 r_sdp = sdp;
877 }
878
879 if (r_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +0000880 /* Negotiate with local SDP */
881 if (l_sdp) {
882 pjmedia_sdp_neg *neg;
883
884 /* Local SDP must be valid! */
885 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
886 status);
887
888 /* Create SDP negotiator */
889 status = pjmedia_sdp_neg_create_w_remote_offer(
Benny Prijono87a90212008-01-23 20:29:30 +0000890 rdata->tp_info.pool, l_sdp, r_sdp, &neg);
Benny Prijono268ca612006-02-07 12:34:11 +0000891 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
892
893 /* Negotiate SDP */
894 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
895 if (status != PJ_SUCCESS) {
896
897 /* Incompatible media */
898 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000899
900 if (p_tdata) {
901 pjsip_accept_hdr *acc;
902 pjsip_warning_hdr *w;
903
904 /* Add Warning header. */
905 w = pjsip_warning_hdr_create_from_status(
906 rdata->tp_info.pool,
907 pjsip_endpt_name(endpt), status);
908 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
909
910 pj_list_push_back(&res_hdr_list, w);
911
912 /* Add Accept header to response */
913 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
914 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
915 acc->values[acc->count++] = pj_str("application/sdp");
916 pj_list_push_back(&res_hdr_list, acc);
917
918 }
919
920 goto on_return;
921 }
922 }
923 }
924
925 /* Check supported methods, see if peer supports UPDATE.
926 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
927 * implicitly by sending this INVITE.
928 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000929 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000930 if (allow) {
931 unsigned i;
932 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
933
934 for (i=0; i<allow->count; ++i) {
935 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
936 break;
937 }
938
939 if (i != allow->count) {
940 /* UPDATE is present in Allow */
941 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
942 }
943
944 }
945
946 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000947 sup_hdr = (pjsip_supported_hdr*)
948 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000949 if (sup_hdr) {
950 unsigned i;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000951 const pj_str_t STR_100REL = { "100rel", 6};
952 const pj_str_t STR_TIMER = { "timer", 5};
Benny Prijono07fe2302010-06-24 12:33:18 +0000953 const pj_str_t STR_ICE = { "ice", 3 };
Benny Prijono268ca612006-02-07 12:34:11 +0000954
955 for (i=0; i<sup_hdr->count; ++i) {
956 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
957 rem_option |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono07fe2302010-06-24 12:33:18 +0000958 else if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000959 rem_option |= PJSIP_INV_SUPPORT_TIMER;
Benny Prijono07fe2302010-06-24 12:33:18 +0000960 else if (pj_stricmp(&sup_hdr->values[i], &STR_ICE)==0)
961 rem_option |= PJSIP_INV_SUPPORT_ICE;
Benny Prijono268ca612006-02-07 12:34:11 +0000962 }
963 }
964
965 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000966 req_hdr = (pjsip_require_hdr*)
967 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000968 if (req_hdr) {
969 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +0000970 const pj_str_t STR_100REL = { "100rel", 6};
Benny Prijono053f5222006-11-11 16:16:04 +0000971 const pj_str_t STR_REPLACES = { "replaces", 8 };
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000972 const pj_str_t STR_TIMER = { "timer", 5 };
Benny Prijono07fe2302010-06-24 12:33:18 +0000973 const pj_str_t STR_ICE = { "ice", 3 };
Benny Prijono268ca612006-02-07 12:34:11 +0000974 unsigned unsupp_cnt = 0;
975 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
976
977 for (i=0; i<req_hdr->count; ++i) {
978 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
979 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
980 {
981 rem_option |= PJSIP_INV_REQUIRE_100REL;
982
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000983 } else if ((*options & PJSIP_INV_SUPPORT_TIMER) &&
984 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000985 {
986 rem_option |= PJSIP_INV_REQUIRE_TIMER;
987
Benny Prijono053f5222006-11-11 16:16:04 +0000988 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
989 pj_bool_t supp;
990
991 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
992 NULL, &STR_REPLACES);
993 if (!supp)
994 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
Benny Prijono07fe2302010-06-24 12:33:18 +0000995 } else if ((*options & PJSIP_INV_SUPPORT_ICE) &&
996 pj_stricmp(&req_hdr->values[i], &STR_ICE)==0)
997 {
998 rem_option |= PJSIP_INV_REQUIRE_ICE;
Benny Prijono053f5222006-11-11 16:16:04 +0000999
Nanang Izzuddin5d5a20e2009-08-06 16:04:20 +00001000 } else if (!pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
1001 NULL, &req_hdr->values[i]))
1002 {
Benny Prijono268ca612006-02-07 12:34:11 +00001003 /* Unknown/unsupported extension tag! */
1004 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
1005 }
1006 }
1007
1008 /* Check if there are required tags that we don't support */
1009 if (unsupp_cnt) {
1010
1011 code = PJSIP_SC_BAD_EXTENSION;
1012 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1013
1014 if (p_tdata) {
1015 pjsip_unsupported_hdr *unsupp_hdr;
1016 const pjsip_hdr *h;
1017
1018 /* Add Unsupported header. */
1019 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
1020 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
1021
1022 unsupp_hdr->count = unsupp_cnt;
1023 for (i=0; i<unsupp_cnt; ++i)
1024 unsupp_hdr->values[i] = unsupp_tags[i];
1025
1026 pj_list_push_back(&res_hdr_list, unsupp_hdr);
1027
1028 /* Add Supported header. */
1029 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
1030 NULL);
1031 pj_assert(h);
1032 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001033 sup_hdr = (pjsip_supported_hdr*)
1034 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001035 pj_list_push_back(&res_hdr_list, sup_hdr);
1036 }
1037 }
1038
1039 goto on_return;
1040 }
1041 }
1042
1043 /* Check if there are local requirements that are not supported
1044 * by peer.
1045 */
1046 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
1047 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
Nanang Izzuddin65add622009-08-11 16:26:20 +00001048 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
1049 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
Benny Prijono268ca612006-02-07 12:34:11 +00001050 {
1051 code = PJSIP_SC_EXTENSION_REQUIRED;
1052 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1053
1054 if (p_tdata) {
1055 const pjsip_hdr *h;
1056
1057 /* Add Require header. */
1058 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
1059 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
1060
1061 if (*options & PJSIP_INV_REQUIRE_100REL)
1062 req_hdr->values[req_hdr->count++] = pj_str("100rel");
Benny Prijono268ca612006-02-07 12:34:11 +00001063 if (*options & PJSIP_INV_REQUIRE_TIMER)
1064 req_hdr->values[req_hdr->count++] = pj_str("timer");
1065
1066 pj_list_push_back(&res_hdr_list, req_hdr);
1067
1068 /* Add Supported header. */
1069 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
1070 NULL);
1071 pj_assert(h);
1072 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001073 sup_hdr = (pjsip_supported_hdr*)
1074 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001075 pj_list_push_back(&res_hdr_list, sup_hdr);
1076 }
1077
1078 }
1079
1080 goto on_return;
1081 }
1082
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001083 /* If remote Require something that we support, make us Require
1084 * that feature too.
1085 */
1086 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
1087 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
1088 *options |= PJSIP_INV_REQUIRE_100REL;
1089 }
1090 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1091 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1092 *options |= PJSIP_INV_REQUIRE_TIMER;
1093 }
1094
Benny Prijono268ca612006-02-07 12:34:11 +00001095on_return:
1096
1097 /* Create response if necessary */
1098 if (code != 200 && p_tdata) {
1099 pjsip_tx_data *tdata;
1100 const pjsip_hdr *h;
1101
1102 if (dlg) {
1103 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1104 &tdata);
1105 } else {
1106 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1107 &tdata);
1108 }
1109
1110 if (status != PJ_SUCCESS)
1111 return status;
1112
1113 /* Add response headers. */
1114 h = res_hdr_list.next;
1115 while (h != &res_hdr_list) {
1116 pjsip_hdr *cloned;
1117
Benny Prijonoa1e69682007-05-11 15:14:34 +00001118 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001119 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1120
1121 pjsip_msg_add_hdr(tdata->msg, cloned);
1122
1123 h = h->next;
1124 }
1125
1126 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001127
1128 /* Can not return PJ_SUCCESS when response message is produced.
1129 * Ref: PROTOS test ~#2490
1130 */
1131 if (status == PJ_SUCCESS)
1132 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1133
Benny Prijono268ca612006-02-07 12:34:11 +00001134 }
1135
1136 return status;
1137}
1138
Benny Prijono87a90212008-01-23 20:29:30 +00001139
1140/*
1141 * Verify incoming INVITE request.
1142 */
1143PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1144 unsigned *options,
1145 const pjmedia_sdp_session *l_sdp,
1146 pjsip_dialog *dlg,
1147 pjsip_endpoint *endpt,
1148 pjsip_tx_data **p_tdata)
1149{
1150 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1151 endpt, p_tdata);
1152}
1153
Benny Prijono268ca612006-02-07 12:34:11 +00001154/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001155 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001156 */
1157PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1158 pjsip_rx_data *rdata,
1159 const pjmedia_sdp_session *local_sdp,
1160 unsigned options,
1161 pjsip_inv_session **p_inv)
1162{
1163 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001164 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001165 pjsip_msg *msg;
1166 pjmedia_sdp_session *rem_sdp = NULL;
1167 pj_status_t status;
1168
1169 /* Verify arguments. */
1170 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1171
1172 /* Dialog MUST have been initialised. */
1173 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1174
1175 msg = rdata->msg_info.msg;
1176
1177 /* rdata MUST contain INVITE request */
1178 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1179 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1180 PJ_EINVALIDOP);
1181
Benny Prijono8eae8382006-08-10 21:44:26 +00001182 /* Lock dialog */
1183 pjsip_dlg_inc_lock(dlg);
1184
Benny Prijono268ca612006-02-07 12:34:11 +00001185 /* Normalize options */
1186 if (options & PJSIP_INV_REQUIRE_100REL)
1187 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +00001188 if (options & PJSIP_INV_REQUIRE_TIMER)
1189 options |= PJSIP_INV_SUPPORT_TIMER;
1190
1191 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001192 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001193 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001194
1195 inv->pool = dlg->pool;
1196 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001197 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001198 inv->dlg = dlg;
1199 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001200 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001201 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001202
Benny Prijono40d62b62009-08-12 17:53:47 +00001203 /* Create flip-flop pool (see ticket #877) */
1204 /* (using inv->obj_name as temporary variable for pool names */
1205 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg->pool);
1206 inv->pool_prov = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1207 POOL_INIT_SIZE, POOL_INC_SIZE);
1208 inv->pool_active = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1209 POOL_INIT_SIZE, POOL_INC_SIZE);
1210
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001211 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001212 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001213
Benny Prijono268ca612006-02-07 12:34:11 +00001214 /* Parse SDP in message body, if present. */
1215 if (msg->body) {
1216 pjsip_msg_body *body = msg->body;
1217
1218 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001219 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001220 &rem_sdp);
1221 if (status == PJ_SUCCESS)
1222 status = pjmedia_sdp_validate(rem_sdp);
1223
Benny Prijono8eae8382006-08-10 21:44:26 +00001224 if (status != PJ_SUCCESS) {
1225 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001226 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001227 }
Benny Prijono268ca612006-02-07 12:34:11 +00001228 }
1229
1230 /* Create negotiator. */
1231 if (rem_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001232 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool,
1233 local_sdp, rem_sdp,
1234 &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001235
1236 } else if (local_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001237 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1238 local_sdp, &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001239 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001240 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001241 }
1242
Benny Prijono8eae8382006-08-10 21:44:26 +00001243 if (status != PJ_SUCCESS) {
1244 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001245 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001246 }
Benny Prijono268ca612006-02-07 12:34:11 +00001247
1248 /* Register invite as dialog usage. */
1249 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001250 if (status != PJ_SUCCESS) {
1251 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001252 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001253 }
Benny Prijono268ca612006-02-07 12:34:11 +00001254
1255 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001256 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001257
1258 /* Save the invite transaction. */
1259 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001260
1261 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001262 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001263 tsx_inv_data->inv = inv;
1264 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001265
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001266 /* Create 100rel handler */
1267 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001268 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001269 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001270
Benny Prijono268ca612006-02-07 12:34:11 +00001271 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001272 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001273 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001274
1275 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1276 dlg->obj_name));
1277
Benny Prijono268ca612006-02-07 12:34:11 +00001278 return PJ_SUCCESS;
1279}
1280
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001281/*
1282 * Forcefully terminate the session.
1283 */
1284PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1285 int st_code,
1286 pj_bool_t notify)
1287{
1288 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1289
1290 /* Lock dialog. */
1291 pjsip_dlg_inc_lock(inv->dlg);
1292
1293 /* Set callback notify flag. */
1294 inv->notify = notify;
1295
1296 /* If there's pending transaction, terminate the transaction.
1297 * This may subsequently set the INVITE session state to
1298 * disconnected.
1299 */
1300 if (inv->invite_tsx &&
1301 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1302 {
1303 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1304
1305 }
1306
1307 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001308 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001309
1310 /* Forcefully terminate the session if state is not DISCONNECTED */
1311 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1312 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1313 }
1314
1315 /* Done.
1316 * The dec_lock() below will actually destroys the dialog if it
1317 * has no other session.
1318 */
1319 pjsip_dlg_dec_lock(inv->dlg);
1320
1321 return PJ_SUCCESS;
1322}
1323
1324
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001325/*
1326 * Restart UAC session, possibly because app or us wants to re-send the
1327 * INVITE request due to 401/407 challenge or 3xx response.
1328 */
1329PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1330 pj_bool_t new_offer)
1331{
1332 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1333
1334 inv->state = PJSIP_INV_STATE_NULL;
1335 inv->invite_tsx = NULL;
1336 if (inv->last_answer) {
1337 pjsip_tx_data_dec_ref(inv->last_answer);
1338 inv->last_answer = NULL;
1339 }
1340
1341 if (new_offer && inv->neg) {
1342 pjmedia_sdp_neg_state neg_state;
1343
1344 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1345 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1346 pjmedia_sdp_neg_cancel_offer(inv->neg);
1347 }
1348 }
1349
1350 return PJ_SUCCESS;
1351}
1352
1353
Benny Prijono268ca612006-02-07 12:34:11 +00001354static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1355{
1356 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001357 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001358}
1359
1360static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1361{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001362 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001363}
1364
Benny Prijono56315612006-07-18 14:39:40 +00001365
1366PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1367 pjmedia_sdp_session *sdp,
1368 pjsip_msg_body **p_body)
1369{
1370 const pj_str_t STR_APPLICATION = { "application", 11};
1371 const pj_str_t STR_SDP = { "sdp", 3 };
1372 pjsip_msg_body *body;
1373
Benny Prijonoa1e69682007-05-11 15:14:34 +00001374 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001375 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1376
1377 body->content_type.type = STR_APPLICATION;
1378 body->content_type.subtype = STR_SDP;
1379 body->data = sdp;
1380 body->len = 0;
1381 body->clone_data = &clone_sdp;
1382 body->print_body = &print_sdp;
1383
1384 *p_body = body;
1385
1386 return PJ_SUCCESS;
1387}
1388
Benny Prijono268ca612006-02-07 12:34:11 +00001389static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1390 const pjmedia_sdp_session *c_sdp)
1391{
1392 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001393 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001394
Benny Prijono56315612006-07-18 14:39:40 +00001395 status = pjsip_create_sdp_body(pool,
1396 pjmedia_sdp_session_clone(pool, c_sdp),
1397 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001398
Benny Prijono56315612006-07-18 14:39:40 +00001399 if (status != PJ_SUCCESS)
1400 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001401
1402 return body;
1403}
1404
1405/*
1406 * Create initial INVITE request.
1407 */
1408PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1409 pjsip_tx_data **p_tdata )
1410{
1411 pjsip_tx_data *tdata;
1412 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001413 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001414 pj_status_t status;
1415
1416 /* Verify arguments. */
1417 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1418
Benny Prijono26ff9062006-02-21 23:47:00 +00001419 /* State MUST be NULL or CONFIRMED. */
1420 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1421 inv->state == PJSIP_INV_STATE_CONFIRMED,
1422 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001423
Benny Prijono64f851e2006-02-23 13:49:28 +00001424 /* Lock dialog. */
1425 pjsip_dlg_inc_lock(inv->dlg);
1426
Benny Prijono268ca612006-02-07 12:34:11 +00001427 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001428 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001429 &tdata);
1430 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001431 goto on_return;
1432
Benny Prijono268ca612006-02-07 12:34:11 +00001433
Benny Prijono26ff9062006-02-21 23:47:00 +00001434 /* If this is the first INVITE, then copy the headers from inv_hdr.
1435 * These are the headers parsed from the request URI when the
1436 * dialog was created.
1437 */
1438 if (inv->state == PJSIP_INV_STATE_NULL) {
1439 hdr = inv->dlg->inv_hdr.next;
1440
1441 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001442 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001443 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1444 hdr = hdr->next;
1445 }
1446 }
1447
1448 /* See if we have SDP to send. */
1449 if (inv->neg) {
1450 pjmedia_sdp_neg_state neg_state;
1451
1452 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1453
1454 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1455 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1456 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1457
1458
1459 } else {
1460 has_sdp = PJ_FALSE;
1461 }
1462
Benny Prijono268ca612006-02-07 12:34:11 +00001463 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001464 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001465 const pjmedia_sdp_session *offer;
1466
1467 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono176a11f2009-04-14 11:14:51 +00001468 if (status != PJ_SUCCESS) {
1469 pjsip_tx_data_dec_ref(tdata);
Benny Prijono64f851e2006-02-23 13:49:28 +00001470 goto on_return;
Benny Prijono176a11f2009-04-14 11:14:51 +00001471 }
Benny Prijono268ca612006-02-07 12:34:11 +00001472
1473 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1474 }
1475
1476 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001477 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001478 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1479 if (hdr) {
1480 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1481 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1482 }
Benny Prijono268ca612006-02-07 12:34:11 +00001483 }
1484
1485 /* Add Supported header */
1486 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1487 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001488 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001489 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1490 }
1491
1492 /* Add Require header. */
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001493 if ((inv->options & PJSIP_INV_REQUIRE_100REL) ||
1494 (inv->options & PJSIP_INV_REQUIRE_TIMER))
1495 {
1496 pjsip_require_hdr *hreq;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001497
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001498 hreq = pjsip_require_hdr_create(tdata->pool);
1499
1500 if (inv->options & PJSIP_INV_REQUIRE_100REL)
1501 hreq->values[hreq->count++] = pj_str("100rel");
1502 if (inv->options & PJSIP_INV_REQUIRE_TIMER)
1503 hreq->values[hreq->count++] = pj_str("timer");
1504
1505 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001506 }
Benny Prijono268ca612006-02-07 12:34:11 +00001507
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001508 status = pjsip_timer_update_req(inv, tdata);
1509 if (status != PJ_SUCCESS)
1510 goto on_return;
1511
Benny Prijono268ca612006-02-07 12:34:11 +00001512 /* Done. */
1513 *p_tdata = tdata;
1514
Benny Prijono64f851e2006-02-23 13:49:28 +00001515
1516on_return:
1517 pjsip_dlg_dec_lock(inv->dlg);
1518 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001519}
1520
1521
Benny Prijono40d62b62009-08-12 17:53:47 +00001522/* Util: swap pool */
1523static void swap_pool(pj_pool_t **p1, pj_pool_t **p2)
1524{
1525 pj_pool_t *tmp = *p1;
1526 *p1 = *p2;
1527 *p2 = tmp;
1528}
1529
Benny Prijono268ca612006-02-07 12:34:11 +00001530/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001531 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001532 */
1533static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1534{
1535 pj_status_t status;
1536
1537 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1538 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1539 PJMEDIA_SDPNEG_EINSTATE);
1540
Benny Prijono40d62b62009-08-12 17:53:47 +00001541 status = pjmedia_sdp_neg_negotiate(inv->pool_prov, inv->neg, 0);
Benny Prijono95196582006-02-09 00:13:40 +00001542
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001543 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1544
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001545 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001546 (*mod_inv.cb.on_media_update)(inv, status);
1547
Benny Prijonobcc8dd72010-02-09 12:28:03 +00001548 /* Invite session may have been terminated by the application even
1549 * after a successful SDP negotiation, for example when no audio
1550 * codec is present in the offer (see ticket #1034).
1551 */
1552 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Nanang Izzuddin756da442009-08-14 13:23:22 +00001553
Benny Prijonobcc8dd72010-02-09 12:28:03 +00001554 /* Swap the flip-flop pool when SDP negotiation success. */
1555 if (status == PJ_SUCCESS) {
1556 swap_pool(&inv->pool_prov, &inv->pool_active);
1557 }
1558
1559 /* Reset the provisional pool regardless SDP negotiation result. */
1560 pj_pool_reset(inv->pool_prov);
1561
1562 } else {
1563
1564 status = PJSIP_ERRNO_FROM_SIP_STATUS(inv->cause);
1565 }
Benny Prijono40d62b62009-08-12 17:53:47 +00001566
Benny Prijono95196582006-02-09 00:13:40 +00001567 return status;
1568}
1569
1570/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001571 * Check in incoming message for SDP offer/answer.
1572 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001573static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1574 pjsip_transaction *tsx,
1575 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001576{
1577 struct tsx_inv_data *tsx_inv_data;
1578 static const pj_str_t str_application = { "application", 11 };
1579 static const pj_str_t str_sdp = { "sdp", 3 };
1580 pj_status_t status;
1581 pjsip_msg *msg;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001582 pjmedia_sdp_session *rem_sdp;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001583
1584 /* Check if SDP is present in the message. */
1585
1586 msg = rdata->msg_info.msg;
1587 if (msg->body == NULL) {
1588 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001589 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001590 }
1591
1592 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1593 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1594 {
1595 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001596 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001597 }
1598
Benny Prijono8fcb4332008-10-31 18:01:48 +00001599 /* Get/attach invite session's transaction data */
1600 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1601 if (tsx_inv_data == NULL) {
1602 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1603 tsx_inv_data->inv = inv;
1604 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1605 }
1606
1607 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1608 * EXCEPT if:
1609 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1610 * - the previous negotiation was done on an early media (18x) and
1611 * this response is a final/2xx response, and
1612 * - the 2xx response has different To tag than the 18x response
1613 * (i.e. the request has forked).
1614 *
1615 * The exception above is to add a rudimentary support for early media
1616 * forking (sample case: custom ringback). See this ticket for more
1617 * info: http://trac.pjsip.org/repos/ticket/657
1618 */
1619 if (tsx_inv_data->sdp_done) {
1620 pj_str_t res_tag;
1621
1622 res_tag = rdata->msg_info.to->tag;
1623
1624 /* Allow final response after SDP has been negotiated in early
1625 * media, IF this response is a final response with different
1626 * tag.
1627 */
1628 if (tsx->role == PJSIP_ROLE_UAC &&
1629 rdata->msg_info.msg->line.status.code/100 == 2 &&
1630 tsx_inv_data->done_early &&
1631 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1632 {
1633 const pjmedia_sdp_session *reoffer_sdp = NULL;
1634
1635 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1636 "after SDP negotiation has been done in early "
1637 "media. Renegotiating SDP.."));
1638
1639 /* Retrieve original SDP offer from INVITE request */
1640 reoffer_sdp = (const pjmedia_sdp_session*)
1641 tsx->last_tx->msg->body->data;
1642
1643 /* Feed the original offer to negotiator */
Benny Prijono40d62b62009-08-12 17:53:47 +00001644 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
1645 inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001646 reoffer_sdp);
1647 if (status != PJ_SUCCESS) {
1648 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1649 "forked 2xx response (err=%d)", status));
1650 return status;
1651 }
1652
1653 } else {
1654
1655 if (rdata->msg_info.msg->body) {
1656 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1657 "body is ignored"));
1658 }
1659 return PJ_SUCCESS;
1660 }
1661 }
1662
Benny Prijonoa66c7152006-02-09 01:26:14 +00001663 /* Parse the SDP body. */
1664
Benny Prijonoa1e69682007-05-11 15:14:34 +00001665 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1666 (char*)msg->body->data,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001667 msg->body->len, &rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001668 if (status == PJ_SUCCESS)
Benny Prijono8fcb4332008-10-31 18:01:48 +00001669 status = pjmedia_sdp_validate(rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001670
Benny Prijonoa66c7152006-02-09 01:26:14 +00001671 if (status != PJ_SUCCESS) {
1672 char errmsg[PJ_ERR_MSG_SIZE];
1673 pj_strerror(status, errmsg, sizeof(errmsg));
1674 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1675 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001676 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001677 }
1678
1679 /* The SDP can be an offer or answer, depending on negotiator's state */
1680
1681 if (inv->neg == NULL ||
1682 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1683 {
1684
1685 /* This is an offer. */
1686
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001687 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1688 pjsip_rx_data_get_info(rdata)));
1689
Benny Prijonoa66c7152006-02-09 01:26:14 +00001690 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001691 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001692 rem_sdp, &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001693 } else {
Benny Prijono40d62b62009-08-12 17:53:47 +00001694 status=pjmedia_sdp_neg_set_remote_offer(inv->pool_prov, inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001695 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001696 }
1697
1698 if (status != PJ_SUCCESS) {
1699 char errmsg[PJ_ERR_MSG_SIZE];
1700 pj_strerror(status, errmsg, sizeof(errmsg));
1701 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1702 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001703 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001704 }
1705
1706 /* Inform application about remote offer. */
1707
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001708 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001709
Benny Prijono8fcb4332008-10-31 18:01:48 +00001710 (*mod_inv.cb.on_rx_offer)(inv, rem_sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001711
1712 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001713
1714 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1715 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1716 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001717 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001718
1719 /* This is an answer.
1720 * Process and negotiate remote answer.
1721 */
1722
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001723 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1724 pjsip_rx_data_get_info(rdata)));
1725
Benny Prijono40d62b62009-08-12 17:53:47 +00001726 status = pjmedia_sdp_neg_set_remote_answer(inv->pool_prov, inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001727 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001728
1729 if (status != PJ_SUCCESS) {
1730 char errmsg[PJ_ERR_MSG_SIZE];
1731 pj_strerror(status, errmsg, sizeof(errmsg));
1732 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1733 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001734 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001735 }
1736
1737 /* Negotiate SDP */
1738
1739 inv_negotiate_sdp(inv);
1740
Benny Prijono8fcb4332008-10-31 18:01:48 +00001741 /* Mark this transaction has having SDP offer/answer done, and
1742 * save the reference to the To tag
1743 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001744
1745 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001746 status_code = rdata->msg_info.msg->line.status.code;
1747 tsx_inv_data->done_early = (status_code/100==1);
1748 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1749 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001750
1751 } else {
1752
1753 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1754 pjsip_rx_data_get_info(rdata),
1755 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1756 }
1757
Benny Prijono26ff9062006-02-21 23:47:00 +00001758 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001759}
1760
1761
Benny Prijono26ff9062006-02-21 23:47:00 +00001762/*
1763 * Process INVITE answer, for both initial and subsequent re-INVITE
1764 */
1765static pj_status_t process_answer( pjsip_inv_session *inv,
1766 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001767 pjsip_tx_data *tdata,
1768 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001769{
1770 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001771 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001772
Benny Prijono64f851e2006-02-23 13:49:28 +00001773 /* If local_sdp is specified, then we MUST NOT have answered the
1774 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001775 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001776 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1777
1778 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001779 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1780 local_sdp,
Benny Prijono64f851e2006-02-23 13:49:28 +00001781 &inv->neg);
1782 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1783 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1784 {
Benny Prijono40d62b62009-08-12 17:53:47 +00001785 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov, inv->neg,
Benny Prijono64f851e2006-02-23 13:49:28 +00001786 local_sdp);
1787 } else {
1788
1789 /* Can not specify local SDP at this state. */
1790 pj_assert(0);
1791 status = PJMEDIA_SDPNEG_EINSTATE;
1792 }
1793
1794 if (status != PJ_SUCCESS)
1795 return status;
1796
1797 }
1798
1799
1800 /* If SDP negotiator is ready, start negotiation. */
1801 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001802
1803 pjmedia_sdp_neg_state neg_state;
1804
Benny Prijono64f851e2006-02-23 13:49:28 +00001805 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001806 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1807 PJMEDIA_SDP_NEG_STATE_NULL;
1808
1809 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1810
1811 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1812
1813 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1814 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1815 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001816 struct tsx_inv_data *tsx_inv_data;
1817
1818 /* Get invite session's transaction data */
1819 tsx_inv_data = (struct tsx_inv_data*)
1820 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001821
1822 status = inv_negotiate_sdp(inv);
1823 if (status != PJ_SUCCESS)
1824 return status;
1825
Benny Prijono77998ce2007-06-20 10:03:46 +00001826 /* Mark this transaction has having SDP offer/answer done. */
1827 tsx_inv_data->sdp_done = 1;
1828
Benny Prijono26ff9062006-02-21 23:47:00 +00001829 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1830 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001831 }
1832
Benny Prijono64f851e2006-02-23 13:49:28 +00001833 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001834 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001835 *
1836 * Note note:
1837 * - When offer/answer has been completed in reliable 183, we MUST NOT
1838 * send SDP in 2xx response. So if we don't have SDP to send, clear
1839 * the SDP in the message body ONLY if 100rel is active in this
1840 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001841 */
1842 if (sdp) {
1843 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001844 } else {
1845 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1846 tdata->msg->body = NULL;
1847 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001848 }
1849
Benny Prijono26ff9062006-02-21 23:47:00 +00001850
1851 return PJ_SUCCESS;
1852}
1853
Benny Prijonoa66c7152006-02-09 01:26:14 +00001854
1855/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001856 * Create first response to INVITE
1857 */
1858PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1859 pjsip_rx_data *rdata,
1860 int st_code,
1861 const pj_str_t *st_text,
1862 const pjmedia_sdp_session *sdp,
1863 pjsip_tx_data **p_tdata)
1864{
1865 pjsip_tx_data *tdata;
1866 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00001867 pjsip_status_code st_code2;
Benny Prijono64f851e2006-02-23 13:49:28 +00001868
1869 /* Verify arguments. */
1870 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1871
1872 /* Must have INVITE transaction. */
1873 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1874
1875 pjsip_dlg_inc_lock(inv->dlg);
1876
1877 /* Create response */
1878 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1879 &tdata);
1880 if (status != PJ_SUCCESS)
1881 goto on_return;
1882
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001883 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00001884 status = pjsip_timer_process_req(inv, rdata, &st_code2);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001885 if (status != PJ_SUCCESS) {
1886 pj_status_t status2;
1887
Nanang Izzuddin65add622009-08-11 16:26:20 +00001888 status2 = pjsip_dlg_modify_response(inv->dlg, tdata, st_code2, NULL);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001889 if (status2 != PJ_SUCCESS) {
1890 pjsip_tx_data_dec_ref(tdata);
1891 goto on_return;
1892 }
1893 status2 = pjsip_timer_update_resp(inv, tdata);
1894 if (status2 == PJ_SUCCESS)
1895 *p_tdata = tdata;
1896 else
1897 pjsip_tx_data_dec_ref(tdata);
1898
1899 goto on_return;
1900 }
1901
Benny Prijono64f851e2006-02-23 13:49:28 +00001902 /* Process SDP in answer */
1903 status = process_answer(inv, st_code, tdata, sdp);
1904 if (status != PJ_SUCCESS) {
1905 pjsip_tx_data_dec_ref(tdata);
1906 goto on_return;
1907 }
1908
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001909 /* Save this answer */
1910 inv->last_answer = tdata;
1911 pjsip_tx_data_add_ref(inv->last_answer);
1912 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1913 pjsip_tx_data_get_info(inv->last_answer)));
1914
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001915 /* Invoke Session Timers */
1916 pjsip_timer_update_resp(inv, tdata);
1917
Benny Prijono64f851e2006-02-23 13:49:28 +00001918 *p_tdata = tdata;
1919
1920on_return:
1921 pjsip_dlg_dec_lock(inv->dlg);
1922 return status;
1923}
1924
1925
1926/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001927 * Answer initial INVITE
1928 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001929 */
1930PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1931 int st_code,
1932 const pj_str_t *st_text,
1933 const pjmedia_sdp_session *local_sdp,
1934 pjsip_tx_data **p_tdata )
1935{
1936 pjsip_tx_data *last_res;
1937 pj_status_t status;
1938
1939 /* Verify arguments. */
1940 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1941
1942 /* Must have INVITE transaction. */
1943 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1944
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001945 /* Must have created an answer before */
1946 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001947
Benny Prijono64f851e2006-02-23 13:49:28 +00001948 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001949
1950 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001951 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001952 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1953 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001954 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001955
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001956 /* For non-2xx final response, strip message body */
1957 if (st_code >= 300) {
1958 last_res->msg->body = NULL;
1959 }
Benny Prijono268ca612006-02-07 12:34:11 +00001960
Benny Prijono26ff9062006-02-21 23:47:00 +00001961 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001962 status = process_answer(inv, st_code, last_res, local_sdp);
1963 if (status != PJ_SUCCESS) {
1964 pjsip_tx_data_dec_ref(last_res);
1965 goto on_return;
1966 }
Benny Prijono268ca612006-02-07 12:34:11 +00001967
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001968 /* Invoke Session Timers */
1969 pjsip_timer_update_resp(inv, last_res);
Benny Prijono268ca612006-02-07 12:34:11 +00001970
1971 *p_tdata = last_res;
1972
Benny Prijono64f851e2006-02-23 13:49:28 +00001973on_return:
1974 pjsip_dlg_dec_lock(inv->dlg);
1975 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001976}
1977
1978
1979/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001980 * Set SDP answer.
1981 */
1982PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1983 const pjmedia_sdp_session *sdp )
1984{
1985 pj_status_t status;
1986
1987 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1988
1989 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono40d62b62009-08-12 17:53:47 +00001990 status = pjmedia_sdp_neg_set_local_answer( inv->pool_prov, inv->neg, sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001991 pjsip_dlg_dec_lock(inv->dlg);
1992
1993 return status;
1994}
1995
1996
1997/*
Benny Prijono268ca612006-02-07 12:34:11 +00001998 * End session.
1999 */
2000PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
2001 int st_code,
2002 const pj_str_t *st_text,
2003 pjsip_tx_data **p_tdata )
2004{
2005 pjsip_tx_data *tdata;
2006 pj_status_t status;
2007
2008 /* Verify arguments. */
2009 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2010
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002011 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002012 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002013
Benny Prijono268ca612006-02-07 12:34:11 +00002014 /* Create appropriate message. */
2015 switch (inv->state) {
2016 case PJSIP_INV_STATE_CALLING:
2017 case PJSIP_INV_STATE_EARLY:
2018 case PJSIP_INV_STATE_INCOMING:
2019
2020 if (inv->role == PJSIP_ROLE_UAC) {
2021
2022 /* For UAC when session has not been confirmed, create CANCEL. */
2023
2024 /* MUST have the original UAC INVITE transaction. */
2025 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
2026
2027 /* But CANCEL should only be called when we have received a
2028 * provisional response. If we haven't received any responses,
2029 * just destroy the transaction.
2030 */
2031 if (inv->invite_tsx->status_code < 100) {
2032
Benny Prijono006a4e82009-04-26 11:30:22 +00002033 /* Do not stop INVITE retransmission, see ticket #506 */
2034 //pjsip_tsx_stop_retransmit(inv->invite_tsx);
Benny Prijono1dc8be02007-05-30 04:26:40 +00002035 inv->cancelling = PJ_TRUE;
2036 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00002037 *p_tdata = NULL;
Benny Prijono006a4e82009-04-26 11:30:22 +00002038 PJ_LOG(4, (inv->obj_name, "Delaying CANCEL since no "
2039 "provisional response is received yet"));
Benny Prijonofccab712006-02-22 22:23:22 +00002040 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002041 }
2042
2043 /* The CSeq here assumes that the dialog is started with an
2044 * INVITE session. This may not be correct; dialog can be
2045 * started as SUBSCRIBE session.
2046 * So fix this!
2047 */
2048 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
2049 inv->invite_tsx->last_tx,
2050 &tdata);
Benny Prijono99b04372009-04-26 11:02:04 +00002051 if (status != PJ_SUCCESS)
2052 return status;
2053
2054 /* Set timeout for the INVITE transaction, in case UAS is not
2055 * able to respond the INVITE with 487 final response. The
2056 * timeout value is 64*T1.
2057 */
2058 pjsip_tsx_set_timeout(inv->invite_tsx, 64 * pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00002059
2060 } else {
2061
2062 /* For UAS, send a final response. */
2063 tdata = inv->invite_tsx->last_tx;
2064 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
2065
Benny Prijono26ff9062006-02-21 23:47:00 +00002066 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
2067 // st_text);
2068 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002069 }
2070 break;
2071
2072 case PJSIP_INV_STATE_CONNECTING:
2073 case PJSIP_INV_STATE_CONFIRMED:
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002074 /* End Session Timer */
2075 pjsip_timer_end_session(inv);
2076
Benny Prijono268ca612006-02-07 12:34:11 +00002077 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002078 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2079 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002080 break;
2081
2082 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00002083 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002084 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00002085
2086 default:
2087 pj_assert("!Invalid operation!");
2088 return PJ_EINVALIDOP;
2089 }
2090
2091 if (status != PJ_SUCCESS)
2092 return status;
2093
2094
2095 /* Done */
2096
Benny Prijono0606e702007-05-22 12:21:40 +00002097 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00002098 *p_tdata = tdata;
2099
2100 return PJ_SUCCESS;
2101}
2102
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002103/* Following redirection recursion, get next target from the target set and
2104 * notify user.
2105 *
2106 * Returns PJ_FALSE if recursion fails (either because there's no more target
2107 * or user rejects the recursion). If we return PJ_FALSE, caller should
2108 * disconnect the session.
2109 *
2110 * Note:
2111 * the event 'e' argument may be NULL.
2112 */
2113static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
2114 const pj_str_t *reason, pjsip_event *e)
2115{
Benny Prijono08a48b82008-11-27 12:42:07 +00002116 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002117 pjsip_target *target;
2118
2119 /* Won't redirect if the callback is not implemented. */
2120 if (mod_inv.cb.on_redirected == NULL)
2121 return PJ_FALSE;
2122
2123 if (reason == NULL)
2124 reason = pjsip_get_status_text(code);
2125
2126 /* Set status of current target */
2127 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
2128 code, reason);
2129
2130 /* Fetch next target from the target set. We only want to
2131 * process SIP/SIPS URI for now.
2132 */
2133 for (;;) {
2134 target = pjsip_target_set_get_next(&inv->dlg->target_set);
2135 if (target == NULL) {
2136 /* No more target. */
2137 return PJ_FALSE;
2138 }
2139
2140 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
2141 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
2142 {
2143 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
2144 reason = pjsip_get_status_text(code);
2145
2146 /* Mark this target as unusable and fetch next target. */
2147 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
2148 } else {
2149 /* Found a target */
2150 break;
2151 }
2152 }
2153
2154 /* We have target in 'target'. Set this target as current target
2155 * and notify callback.
2156 */
2157 pjsip_target_set_set_current(&inv->dlg->target_set, target);
2158
Benny Prijono08a48b82008-11-27 12:42:07 +00002159 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002160
2161
2162 /* Check what the application wants to do now */
2163 switch (op) {
2164 case PJSIP_REDIRECT_ACCEPT:
2165 case PJSIP_REDIRECT_STOP:
2166 /* Must increment session counter, that's the convention of the
2167 * pjsip_inv_process_redirect().
2168 */
2169 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2170
2171 /* Act on the recursion */
2172 pjsip_inv_process_redirect(inv, op, e);
2173 return PJ_TRUE;
2174
2175 case PJSIP_REDIRECT_PENDING:
2176 /* Increment session so that the dialog/session is not destroyed
2177 * while we're waiting for user confirmation.
2178 */
2179 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2180
2181 /* Also clear the invite_tsx variable, otherwise when this tsx is
2182 * terminated, it will also terminate the session.
2183 */
2184 inv->invite_tsx = NULL;
2185
2186 /* Done. The processing will continue once the application calls
2187 * pjsip_inv_process_redirect().
2188 */
2189 return PJ_TRUE;
2190
2191 case PJSIP_REDIRECT_REJECT:
2192 /* Recursively call this function again to fetch next target, if any.
2193 */
2194 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2195
2196 }
2197
2198 pj_assert(!"Should not reach here");
2199 return PJ_FALSE;
2200}
2201
2202
2203/* Process redirection/recursion */
2204PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2205 pjsip_redirect_op op,
2206 pjsip_event *e)
2207{
2208 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2209 pjsip_event usr_event;
2210 pj_status_t status = PJ_SUCCESS;
2211
2212 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2213
2214 if (e == NULL) {
2215 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2216 e = &usr_event;
2217 }
2218
2219 pjsip_dlg_inc_lock(inv->dlg);
2220
2221 /* Decrement session. That's the convention here to prevent the dialog
2222 * or session from being destroyed while we're waiting for user
2223 * confirmation.
2224 */
2225 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2226
2227 /* See what the application wants to do now */
2228 switch (op) {
2229 case PJSIP_REDIRECT_ACCEPT:
2230 /* User accept the redirection. Reset the session and resend the
2231 * INVITE request.
2232 */
2233 {
2234 pjsip_tx_data *tdata;
2235 pjsip_via_hdr *via;
2236
2237 /* Get the original INVITE request. */
2238 tdata = inv->invite_req;
2239 pjsip_tx_data_add_ref(tdata);
2240
2241 /* Restore strict route set.
2242 * See http://trac.pjsip.org/repos/ticket/492
2243 */
2244 pjsip_restore_strict_route_set(tdata);
2245
2246 /* Set target */
Benny Prijono20da7992008-12-18 16:48:43 +00002247 tdata->msg->line.req.uri = (pjsip_uri*)
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002248 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2249
2250 /* Remove branch param in Via header. */
2251 via = (pjsip_via_hdr*)
2252 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2253 via->branch_param.slen = 0;
2254
2255 /* Must invalidate the message! */
2256 pjsip_tx_data_invalidate_msg(tdata);
2257
2258 /* Reset the session */
2259 pjsip_inv_uac_restart(inv, PJ_FALSE);
2260
2261 /* (re)Send the INVITE request */
2262 status = pjsip_inv_send_msg(inv, tdata);
2263 }
2264 break;
2265
2266 case PJSIP_REDIRECT_STOP:
2267 /* User doesn't want the redirection. Disconnect the session now. */
2268 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2269 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2270
2271 /* Caller should expect that the invite session is gone now, so
2272 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2273 */
2274 break;
2275
2276 case PJSIP_REDIRECT_REJECT:
2277 /* Current target is rejected. Fetch next target if any. */
2278 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2279 inv_set_cause(inv, cancel_code,
2280 pjsip_get_status_text(cancel_code));
2281 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2282
2283 /* Tell caller that the invite session is gone now */
2284 status = PJSIP_ESESSIONTERMINATED;
2285 }
2286 break;
2287
2288
2289 case PJSIP_REDIRECT_PENDING:
2290 pj_assert(!"Should not happen");
2291 break;
2292 }
2293
2294
2295 pjsip_dlg_dec_lock(inv->dlg);
2296
2297 return status;
2298}
2299
Benny Prijono268ca612006-02-07 12:34:11 +00002300
2301/*
2302 * Create re-INVITE.
2303 */
2304PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2305 const pj_str_t *new_contact,
2306 const pjmedia_sdp_session *new_offer,
2307 pjsip_tx_data **p_tdata )
2308{
Benny Prijono26ff9062006-02-21 23:47:00 +00002309 pj_status_t status;
2310 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002311
Benny Prijono26ff9062006-02-21 23:47:00 +00002312 /* Check arguments. */
2313 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2314
2315 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002316 if (inv->invite_tsx!=NULL)
2317 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002318
2319
2320 pjsip_dlg_inc_lock(inv->dlg);
2321
2322 if (new_contact) {
2323 pj_str_t tmp;
2324 const pj_str_t STR_CONTACT = { "Contact", 7 };
2325
2326 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002327 contact_hdr = (pjsip_contact_hdr*)
2328 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002329 tmp.ptr, tmp.slen, NULL);
2330 if (!contact_hdr) {
2331 status = PJSIP_EINVALIDURI;
2332 goto on_return;
2333 }
2334 }
2335
2336
2337 if (new_offer) {
2338 if (!inv->neg) {
Benny Prijono40d62b62009-08-12 17:53:47 +00002339 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
2340 new_offer,
Benny Prijono26ff9062006-02-21 23:47:00 +00002341 &inv->neg);
2342 if (status != PJ_SUCCESS)
2343 goto on_return;
2344
2345 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2346
2347 case PJMEDIA_SDP_NEG_STATE_NULL:
2348 pj_assert(!"Unexpected SDP neg state NULL");
2349 status = PJ_EBUG;
2350 goto on_return;
2351
2352 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2353 PJ_LOG(4,(inv->obj_name,
2354 "pjsip_inv_reinvite: already have an offer, new "
2355 "offer is ignored"));
2356 break;
2357
2358 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
Benny Prijono40d62b62009-08-12 17:53:47 +00002359 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov,
2360 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002361 new_offer);
2362 if (status != PJ_SUCCESS)
2363 goto on_return;
2364 break;
2365
2366 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2367 PJ_LOG(4,(inv->obj_name,
2368 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2369 "offer is ignored"));
2370 break;
2371
2372 case PJMEDIA_SDP_NEG_STATE_DONE:
Benny Prijono40d62b62009-08-12 17:53:47 +00002373 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
2374 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002375 new_offer);
2376 if (status != PJ_SUCCESS)
2377 goto on_return;
2378 break;
2379 }
2380 }
2381
2382 if (contact_hdr)
2383 inv->dlg->local.contact = contact_hdr;
2384
2385 status = pjsip_inv_invite(inv, p_tdata);
2386
2387on_return:
2388 pjsip_dlg_dec_lock(inv->dlg);
2389 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002390}
2391
2392/*
2393 * Create UPDATE.
2394 */
2395PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2396 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002397 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002398 pjsip_tx_data **p_tdata )
2399{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002400 pjsip_contact_hdr *contact_hdr = NULL;
2401 pjsip_tx_data *tdata = NULL;
2402 pjmedia_sdp_session *sdp_copy;
2403 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002404
Benny Prijono1f7767b2007-10-03 18:28:49 +00002405 /* Verify arguments. */
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002406 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002407
2408 /* Dialog must have been established */
2409 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2410 PJ_EINVALIDOP);
2411
2412 /* Invite session must not have been disconnected */
2413 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2414 PJ_EINVALIDOP);
2415
2416 /* Lock dialog. */
2417 pjsip_dlg_inc_lock(inv->dlg);
2418
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002419 /* Process offer, if any */
2420 if (offer) {
2421 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2422 PJ_LOG(4,(inv->dlg->obj_name,
2423 "Invalid SDP offer/answer state for UPDATE"));
2424 status = PJ_EINVALIDOP;
2425 goto on_error;
2426 }
2427
2428 /* Notify negotiator about the new offer. This will fix the offer
2429 * with correct SDP origin.
2430 */
2431 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg,
2432 offer);
2433 if (status != PJ_SUCCESS)
2434 goto on_error;
2435
2436 /* Retrieve the "fixed" offer from negotiator */
2437 pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002438 }
2439
Benny Prijono1f7767b2007-10-03 18:28:49 +00002440 /* Update Contact if required */
2441 if (new_contact) {
2442 pj_str_t tmp;
2443 const pj_str_t STR_CONTACT = { "Contact", 7 };
2444
2445 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2446 contact_hdr = (pjsip_contact_hdr*)
2447 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2448 tmp.ptr, tmp.slen, NULL);
2449 if (!contact_hdr) {
2450 status = PJSIP_EINVALIDURI;
2451 goto on_error;
2452 }
2453
2454 inv->dlg->local.contact = contact_hdr;
2455 }
2456
2457 /* Create request */
2458 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2459 -1, &tdata);
2460 if (status != PJ_SUCCESS)
2461 goto on_error;
2462
2463 /* Attach SDP body */
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002464 if (offer) {
2465 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2466 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2467 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00002468
2469 /* Unlock dialog. */
2470 pjsip_dlg_dec_lock(inv->dlg);
2471
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002472 status = pjsip_timer_update_req(inv, tdata);
2473 if (status != PJ_SUCCESS)
2474 goto on_error;
2475
Benny Prijono1f7767b2007-10-03 18:28:49 +00002476 *p_tdata = tdata;
2477
2478 return PJ_SUCCESS;
2479
2480on_error:
2481 if (tdata)
2482 pjsip_tx_data_dec_ref(tdata);
2483
2484 /* Unlock dialog. */
2485 pjsip_dlg_dec_lock(inv->dlg);
2486
2487 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002488}
2489
2490/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002491 * Create an ACK request.
2492 */
2493PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2494 int cseq,
2495 pjsip_tx_data **p_tdata)
2496{
2497 const pjmedia_sdp_session *sdp = NULL;
2498 pj_status_t status;
2499
2500 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2501
2502 /* Lock dialog. */
2503 pjsip_dlg_inc_lock(inv->dlg);
2504
2505 /* Destroy last_ack */
2506 if (inv->last_ack) {
2507 pjsip_tx_data_dec_ref(inv->last_ack);
2508 inv->last_ack = NULL;
2509 }
2510
2511 /* Create new ACK request */
2512 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2513 cseq, &inv->last_ack);
2514 if (status != PJ_SUCCESS) {
2515 pjsip_dlg_dec_lock(inv->dlg);
2516 return status;
2517 }
2518
2519 /* See if we have pending SDP answer to send */
2520 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2521 if (sdp) {
2522 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2523 }
2524
2525 /* Keep this for subsequent response retransmission */
2526 inv->last_ack_cseq = cseq;
2527 pjsip_tx_data_add_ref(inv->last_ack);
2528
2529 /* Done */
2530 *p_tdata = inv->last_ack;
2531
2532 /* Unlock dialog. */
2533 pjsip_dlg_dec_lock(inv->dlg);
2534
2535 return PJ_SUCCESS;
2536}
2537
2538/*
Benny Prijono268ca612006-02-07 12:34:11 +00002539 * Send a request or response message.
2540 */
2541PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002542 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002543{
2544 pj_status_t status;
2545
2546 /* Verify arguments. */
2547 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2548
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002549 PJ_LOG(5,(inv->obj_name, "Sending %s",
2550 pjsip_tx_data_get_info(tdata)));
2551
Benny Prijono268ca612006-02-07 12:34:11 +00002552 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002553 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002554
Benny Prijono64158af2006-04-04 11:06:34 +00002555 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002556
Benny Prijono22e48c92008-03-20 14:40:50 +00002557 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002558 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2559 inv->invite_tsx)
2560 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002561 pjsip_tx_data_dec_ref(tdata);
2562 pjsip_dlg_dec_lock(inv->dlg);
2563 return PJ_EINVALIDOP;
2564 }
2565
2566 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002567 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002568 tsx_inv_data->inv = inv;
2569
Benny Prijono64158af2006-04-04 11:06:34 +00002570 pjsip_dlg_dec_lock(inv->dlg);
2571
2572 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2573 tsx_inv_data);
2574 if (status != PJ_SUCCESS)
2575 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002576
2577 } else {
2578 pjsip_cseq_hdr *cseq;
2579
2580 /* Can only do this to send response to original INVITE
2581 * request.
2582 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002583 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 +00002584 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002585 PJ_EINVALIDOP);
2586
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002587 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002588 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002589 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002590 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002591 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002592 }
2593
Benny Prijono268ca612006-02-07 12:34:11 +00002594 if (status != PJ_SUCCESS)
2595 return status;
2596 }
2597
2598 /* Done (?) */
2599 return PJ_SUCCESS;
2600}
2601
2602
Benny Prijono8ad55352006-02-08 11:16:05 +00002603/*
2604 * Respond to incoming CANCEL request.
2605 */
2606static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2607 pjsip_transaction *cancel_tsx,
2608 pjsip_rx_data *rdata)
2609{
2610 pjsip_tx_data *tdata;
2611 pjsip_transaction *invite_tsx;
2612 pj_str_t key;
2613 pj_status_t status;
2614
2615 /* See if we have matching INVITE server transaction: */
2616
2617 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002618 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002619 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2620
2621 if (invite_tsx == NULL) {
2622
2623 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002624 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002625 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002626 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002627 &tdata);
2628
2629 } else {
2630 /* Always answer CANCEL will 200 (OK) regardless of
2631 * the state of the INVITE transaction.
2632 */
2633 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2634 &tdata);
2635 }
2636
2637 /* See if we have created the response successfully. */
2638 if (status != PJ_SUCCESS) return;
2639
2640 /* Send the CANCEL response */
2641 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2642 if (status != PJ_SUCCESS) return;
2643
2644
2645 /* See if we need to terminate the UAS INVITE transaction
2646 * with 487 (Request Terminated) response.
2647 */
2648 if (invite_tsx && invite_tsx->status_code < 200) {
2649
2650 pj_assert(invite_tsx->last_tx != NULL);
2651
2652 tdata = invite_tsx->last_tx;
2653
2654 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002655 if (status == PJ_SUCCESS) {
2656 /* Remove the message body */
2657 tdata->msg->body = NULL;
Benny Prijono1e08e4f2009-05-13 08:57:38 +00002658 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
2659 status = pjsip_100rel_tx_response(inv, tdata);
2660 } else {
2661 status = pjsip_dlg_send_response(inv->dlg, invite_tsx,
2662 tdata);
2663 }
Benny Prijonofc8bb142007-11-08 09:56:50 +00002664 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002665 }
2666
2667 if (invite_tsx)
2668 pj_mutex_unlock(invite_tsx->mutex);
2669}
2670
2671
2672/*
2673 * Respond to incoming BYE request.
2674 */
2675static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2676 pjsip_transaction *bye_tsx,
2677 pjsip_rx_data *rdata,
2678 pjsip_event *e )
2679{
2680 pj_status_t status;
2681 pjsip_tx_data *tdata;
2682
2683 /* Respond BYE with 200: */
2684
2685 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2686 if (status != PJ_SUCCESS) return;
2687
2688 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2689 if (status != PJ_SUCCESS) return;
2690
2691 /* Terminate session: */
2692
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002693 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002694 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002695 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002696 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002697}
2698
2699/*
Benny Prijono38998232006-02-08 22:44:25 +00002700 * Respond to BYE request.
2701 */
2702static void inv_handle_bye_response( pjsip_inv_session *inv,
2703 pjsip_transaction *tsx,
2704 pjsip_rx_data *rdata,
2705 pjsip_event *e )
2706{
2707 pj_status_t status;
2708
2709 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002710 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002711 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2712 return;
2713 }
2714
2715 /* Handle 401/407 challenge. */
2716 if (tsx->status_code == 401 || tsx->status_code == 407) {
2717
2718 pjsip_tx_data *tdata;
2719
2720 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2721 rdata,
2722 tsx->last_tx,
2723 &tdata);
2724
2725 if (status != PJ_SUCCESS) {
2726
2727 /* Does not have proper credentials.
2728 * End the session anyway.
2729 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002730 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002731 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2732
2733 } else {
2734 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002735 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002736 }
2737
2738 } else {
2739
2740 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002741 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002742 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2743 }
2744
2745}
2746
2747/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002748 * Respond to incoming UPDATE request.
2749 */
2750static void inv_respond_incoming_update(pjsip_inv_session *inv,
2751 pjsip_rx_data *rdata)
2752{
2753 pjmedia_sdp_neg_state neg_state;
2754 pj_status_t status;
2755 pjsip_tx_data *tdata = NULL;
Nanang Izzuddin65add622009-08-11 16:26:20 +00002756 pjsip_status_code st_code;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002757
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002758 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00002759 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002760 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00002761 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002762 NULL, &tdata);
2763 goto on_return;
2764 }
2765
Benny Prijono1f7767b2007-10-03 18:28:49 +00002766 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2767
2768 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2769 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2770 status = pjsip_dlg_create_response(inv->dlg, rdata,
2771 PJSIP_SC_REQUEST_PENDING, NULL,
2772 &tdata);
2773 }
2774 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2775 * receive UPDATE while we haven't sent answer.
2776 */
2777 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2778 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2779 status = pjsip_dlg_create_response(inv->dlg, rdata,
2780 PJSIP_SC_INTERNAL_SERVER_ERROR,
2781 NULL, &tdata);
2782
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002783 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2784 * This is a valid scenario according to session-timer draft.
2785 */
2786 } else if (rdata->msg_info.msg->body == NULL) {
2787
2788 status = pjsip_dlg_create_response(inv->dlg, rdata,
2789 200, NULL, &tdata);
2790
Benny Prijono1f7767b2007-10-03 18:28:49 +00002791 } else {
2792 /* We receive new offer from remote */
2793 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2794
2795 /* Application MUST have supplied the answer by now.
2796 * If so, negotiate the SDP.
2797 */
2798 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2799 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2800 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2801 {
Benny Prijonoab74c902010-06-23 12:21:20 +00002802 /* Negotiation has failed. If negotiator is still
2803 * stuck at non-DONE state, cancel any ongoing offer.
2804 */
2805 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2806 if (neg_state != PJMEDIA_SDP_NEG_STATE_DONE) {
2807 pjmedia_sdp_neg_cancel_offer(inv->neg);
2808 }
2809
Benny Prijono1f7767b2007-10-03 18:28:49 +00002810 status = pjsip_dlg_create_response(inv->dlg, rdata,
2811 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2812 NULL, &tdata);
2813 } else {
2814 /* New media has been negotiated successfully, send 200/OK */
2815 status = pjsip_dlg_create_response(inv->dlg, rdata,
2816 PJSIP_SC_OK, NULL, &tdata);
2817 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002818 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002819 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2820 if (status == PJ_SUCCESS)
2821 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2822 }
2823 }
2824 }
2825
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002826on_return:
2827 /* Invoke Session Timers */
2828 if (status == PJ_SUCCESS)
2829 status = pjsip_timer_update_resp(inv, tdata);
2830
Benny Prijono1f7767b2007-10-03 18:28:49 +00002831 if (status != PJ_SUCCESS) {
2832 if (tdata != NULL) {
2833 pjsip_tx_data_dec_ref(tdata);
2834 tdata = NULL;
2835 }
2836 return;
2837 }
2838
2839 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2840}
2841
2842
2843/*
2844 * Handle incoming response to UAC UPDATE request.
2845 */
2846static void inv_handle_update_response( pjsip_inv_session *inv,
2847 pjsip_event *e)
2848{
2849 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2850 struct tsx_inv_data *tsx_inv_data = NULL;
2851 pj_status_t status = -1;
2852
Benny Prijono48ab2b72007-11-08 09:24:30 +00002853 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002854 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002855 (tsx->status_code == 401 || tsx->status_code == 407))
2856 {
Benny Prijono48ab2b72007-11-08 09:24:30 +00002857 pjsip_tx_data *tdata;
2858
2859 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2860 e->body.tsx_state.src.rdata,
2861 tsx->last_tx,
2862 &tdata);
2863
2864 if (status != PJ_SUCCESS) {
2865
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002866 /* Somehow failed. Probably it's not a good idea to terminate
2867 * the session since this is just a request within dialog. And
2868 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002869 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002870 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002871 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2872 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002873 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002874
2875 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002876 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002877 status = pjsip_inv_send_msg(inv, tdata);
2878 }
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002879 }
2880
2881 /* Process 422 response */
2882 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2883 tsx->status_code == 422)
2884 {
2885 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2886 PJ_FALSE);
2887 }
Benny Prijono48ab2b72007-11-08 09:24:30 +00002888
2889 /* Process 2xx response */
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002890 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002891 tsx->status_code/100 == 2 &&
2892 e->body.tsx_state.src.rdata->msg_info.msg->body)
2893 {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002894 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2895 PJ_FALSE);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002896 status = inv_check_sdp_in_incoming_msg(inv, tsx,
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002897 e->body.tsx_state.src.rdata);
2898 }
2899
2900 /* Get/attach invite session's transaction data */
2901 else
2902 {
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002903 /* Session-Timer needs to see any error responses, to determine
2904 * whether peer supports UPDATE with empty body.
2905 */
2906 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2907 tsx->role == PJSIP_ROLE_UAC)
2908 {
2909 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2910 PJ_FALSE);
2911 }
2912
Benny Prijono1f7767b2007-10-03 18:28:49 +00002913 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2914 if (tsx_inv_data == NULL) {
2915 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2916 tsx_inv_data->inv = inv;
2917 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2918 }
2919 }
2920
Benny Prijonoab74c902010-06-23 12:21:20 +00002921 /* Cancel the negotiation if we don't get successful negotiation by now */
2922 if (pjmedia_sdp_neg_get_state(inv->neg) ==
2923 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002924 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2925 {
2926 pjmedia_sdp_neg_cancel_offer(inv->neg);
2927
2928 /* Prevent from us cancelling different offer! */
2929 tsx_inv_data->sdp_done = PJ_TRUE;
2930 }
2931}
2932
2933
2934/*
2935 * Handle incoming reliable response.
2936 */
2937static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2938 pjsip_rx_data *rdata)
2939{
2940 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002941 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002942 pj_status_t status;
2943
2944 /* Create PRACK */
2945 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2946 if (status != PJ_SUCCESS)
2947 return;
2948
2949 /* See if we need to attach SDP answer on the PRACK request */
2950 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2951 if (sdp) {
2952 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2953 }
2954
2955 /* Send PRACK (must be using 100rel module!) */
2956 pjsip_100rel_send_prack(inv, tdata);
2957}
2958
2959
2960/*
2961 * Handle incoming PRACK.
2962 */
2963static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2964 pjsip_rx_data *rdata)
2965{
2966 pj_status_t status;
2967
2968 /* Run through 100rel module to see if we can accept this
2969 * PRACK request. The 100rel will send 200/OK to PRACK request.
2970 */
2971 status = pjsip_100rel_on_rx_prack(inv, rdata);
2972 if (status != PJ_SUCCESS)
2973 return;
2974
2975 /* Now check for SDP answer in the PRACK request */
2976 if (rdata->msg_info.msg->body) {
2977 status = inv_check_sdp_in_incoming_msg(inv,
2978 pjsip_rdata_get_tsx(rdata), rdata);
2979 } else {
2980 /* No SDP body */
2981 status = -1;
2982 }
2983
2984 /* If SDP negotiation has been successful, also mark the
2985 * SDP negotiation flag in the invite transaction to be
2986 * done too.
2987 */
2988 if (status == PJ_SUCCESS && inv->invite_tsx) {
2989 struct tsx_inv_data *tsx_inv_data;
2990
2991 /* Get/attach invite session's transaction data */
2992 tsx_inv_data = (struct tsx_inv_data*)
2993 inv->invite_tsx->mod_data[mod_inv.mod.id];
2994 if (tsx_inv_data == NULL) {
2995 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2996 struct tsx_inv_data);
2997 tsx_inv_data->inv = inv;
2998 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2999 }
3000
3001 tsx_inv_data->sdp_done = PJ_TRUE;
3002 }
3003}
3004
3005
3006/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003007 * State NULL is before anything is sent/received.
3008 */
3009static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003010{
3011 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3012 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3013
3014 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3015
3016 if (tsx->method.id == PJSIP_INVITE_METHOD) {
3017
Benny Prijono64f851e2006-02-23 13:49:28 +00003018 /* Keep the initial INVITE transaction. */
3019 if (inv->invite_tsx == NULL)
3020 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00003021
Benny Prijono64f851e2006-02-23 13:49:28 +00003022 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00003023
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003024 /* Save the original INVITE request, if on_redirected() callback
3025 * is implemented. We may need to resend the INVITE if we receive
3026 * redirection response.
3027 */
3028 if (mod_inv.cb.on_redirected) {
3029 if (inv->invite_req) {
3030 pjsip_tx_data_dec_ref(inv->invite_req);
3031 inv->invite_req = NULL;
3032 }
3033 inv->invite_req = tsx->last_tx;
3034 pjsip_tx_data_add_ref(inv->invite_req);
3035 }
3036
Benny Prijono268ca612006-02-07 12:34:11 +00003037 switch (tsx->state) {
3038 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003039 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003040 break;
3041 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00003042 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003043 break;
3044 }
3045
3046 } else {
3047 switch (tsx->state) {
3048 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003049 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003050 break;
Benny Prijono38998232006-02-08 22:44:25 +00003051 case PJSIP_TSX_STATE_PROCEEDING:
3052 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3053 if (tsx->status_code > 100)
3054 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
3055 break;
Benny Prijono2285e7e2008-12-17 14:28:18 +00003056 case PJSIP_TSX_STATE_TERMINATED:
3057 /* there is a failure in sending response. */
3058 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3059 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3060 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003061 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00003062 inv_on_state_incoming(inv, e);
3063 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003064 }
3065 }
3066
3067 } else {
3068 pj_assert(!"Unexpected transaction type");
3069 }
3070}
3071
Benny Prijono8ad55352006-02-08 11:16:05 +00003072/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003073 * Generic UAC transaction handler:
3074 * - resend request on 401 or 407 response.
3075 * - terminate dialog on 408 and 481 response.
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003076 * - resend request on 422 response.
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003077 */
3078static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
3079 pjsip_event *e)
3080{
3081 /* RFC 3261 Section 12.2.1.2:
3082 * If the response for a request within a dialog is a 481
3083 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
3084 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
3085 * no response at all is received for the request (the client
3086 * transaction would inform the TU about the timeout.)
3087 *
3088 * For INVITE initiated dialogs, terminating the dialog consists of
3089 * sending a BYE.
3090 *
3091 * Note:
3092 * according to X, this should terminate dialog usage only, not the
3093 * dialog.
3094 */
3095 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3096
3097 pj_assert(tsx->role == PJSIP_UAC_ROLE);
3098
3099 /* Note that 481 response to CANCEL does not terminate dialog usage,
3100 * but only the transaction.
3101 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00003102 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
3103 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003104 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00003105 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3106 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
3107 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003108 {
3109 pjsip_tx_data *bye;
3110 pj_status_t status;
3111
3112 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3113 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3114
3115 /* Send BYE */
3116 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
3117 -1, &bye);
3118 if (status == PJ_SUCCESS) {
3119 pjsip_inv_send_msg(inv, bye);
3120 }
3121
3122 return PJ_TRUE; /* Handled */
3123
3124 }
3125 /* Handle 401/407 challenge. */
3126 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3127 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
3128 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
3129 {
3130
3131 pjsip_tx_data *tdata;
3132 pj_status_t status;
3133
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003134 if (tsx->method.id == PJSIP_INVITE_METHOD)
3135 inv->invite_tsx = NULL;
3136
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003137 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
3138 e->body.tsx_state.src.rdata,
3139 tsx->last_tx, &tdata);
3140
3141 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003142 /* Somehow failed. Probably it's not a good idea to terminate
3143 * the session since this is just a request within dialog. And
3144 * even if we terminate we should send BYE.
3145 */
3146 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003147 inv_set_cause(inv, PJSIP_SC_OK, NULL);
3148 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003149 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003150
3151 } else {
3152 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003153 status = pjsip_inv_send_msg(inv, tdata);
3154 }
3155
3156 return PJ_TRUE; /* Handled */
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003157 }
3158
3159 /* Handle session timer 422 response. */
3160 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3161 tsx->status_code == PJSIP_SC_SESSION_TIMER_TOO_SMALL)
3162 {
3163 handle_timer_response(inv, e->body.tsx_state.src.rdata,
3164 PJ_FALSE);
3165
3166 return PJ_TRUE; /* Handled */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003167
3168 } else {
3169 return PJ_FALSE; /* Unhandled */
3170 }
3171}
3172
3173
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003174/* Handle call rejection, especially with regard to processing call
3175 * redirection. We need to handle the following scenarios:
3176 * - 3xx response is received -- see if on_redirected() callback is
3177 * implemented. If so, add the Contact URIs in the response to the
3178 * target set and notify user.
3179 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
3180 * if so fetch the next target if any and notify the on_redirected()
3181 * callback.
3182 * - for other cases -- disconnect the session.
3183 */
3184static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
3185{
3186 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3187 pj_status_t status;
3188
3189 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
3190
3191 if (mod_inv.cb.on_redirected == NULL) {
3192
3193 /* Redirection callback is not implemented, disconnect the
3194 * call.
3195 */
3196 goto terminate_session;
3197
3198 } else {
3199 const pjsip_msg *res_msg;
3200
3201 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
3202
3203 /* Gather all Contact URI's in the response and add them
3204 * to target set. The function will take care of removing
3205 * duplicate URI's.
3206 */
3207 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
3208 inv->dlg->pool, res_msg);
3209
3210 /* Recurse to alternate targets if application allows us */
3211 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3212 {
3213 /* Recursion fails, terminate session now */
3214 goto terminate_session;
3215 }
3216
3217 /* Done */
3218 }
3219
3220 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
3221 !inv->cancelling)
3222 {
3223
3224 /* Handle authentication failure:
3225 * Resend the request with Authorization header.
3226 */
3227 pjsip_tx_data *tdata;
3228
3229 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
3230 e->body.tsx_state.src.rdata,
3231 tsx->last_tx,
3232 &tdata);
3233
3234 if (status != PJ_SUCCESS) {
3235
3236 /* Does not have proper credentials. If we are currently
3237 * recursing, try the next target. Otherwise end the session.
3238 */
3239 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3240 {
3241 /* Recursion fails, terminate session now */
3242 goto terminate_session;
3243 }
3244
3245 } else {
3246
3247 /* Restart session. */
3248 pjsip_inv_uac_restart(inv, PJ_FALSE);
3249
3250 /* Send the request. */
3251 status = pjsip_inv_send_msg(inv, tdata);
3252 }
3253
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003254 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3255 tsx->status_code == PJSIP_SC_SESSION_TIMER_TOO_SMALL)
3256 {
3257 /* Handle session timer 422 response:
3258 * Resend the request with requested session timer setting.
3259 */
3260 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
3261 PJ_TRUE);
3262
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003263 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3264 /* Global error */
3265 goto terminate_session;
3266
3267 } else {
3268 /* See if we have alternate target to try */
3269 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3270 /* Recursion fails, terminate session now */
3271 goto terminate_session;
3272 }
3273 }
3274 return;
3275
3276terminate_session:
3277 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3278 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3279}
3280
3281
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003282/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003283 * State CALLING is after sending initial INVITE request but before
3284 * any response (with tag) is received.
3285 */
3286static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003287{
3288 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3289 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003290 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003291
3292 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3293
Benny Prijono8ad55352006-02-08 11:16:05 +00003294 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003295
3296 switch (tsx->state) {
3297
Benny Prijono64f851e2006-02-23 13:49:28 +00003298 case PJSIP_TSX_STATE_CALLING:
3299 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3300 break;
3301
Benny Prijono268ca612006-02-07 12:34:11 +00003302 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003303 if (inv->pending_cancel) {
3304 pjsip_tx_data *cancel;
3305
3306 inv->pending_cancel = PJ_FALSE;
3307
3308 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3309 if (status == PJ_SUCCESS && cancel)
3310 status = pjsip_inv_send_msg(inv, cancel);
3311 }
3312
Benny Prijono268ca612006-02-07 12:34:11 +00003313 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003314
Benny Prijono8ad55352006-02-08 11:16:05 +00003315 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003316
3317 inv_check_sdp_in_incoming_msg(inv, tsx,
3318 e->body.tsx_state.src.rdata);
3319
Benny Prijono1f7767b2007-10-03 18:28:49 +00003320 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3321 inv_handle_incoming_reliable_response(
3322 inv, e->body.tsx_state.src.rdata);
3323 }
3324
Benny Prijono268ca612006-02-07 12:34:11 +00003325 } else {
3326 /* Ignore 100 (Trying) response, as it doesn't change
3327 * session state. It only ceases retransmissions.
3328 */
3329 }
3330 break;
3331
3332 case PJSIP_TSX_STATE_COMPLETED:
3333 if (tsx->status_code/100 == 2) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003334
Benny Prijono268ca612006-02-07 12:34:11 +00003335 /* This should not happen.
3336 * When transaction receives 2xx, it should be terminated
3337 */
3338 pj_assert(0);
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003339
3340 /* Process session timer response. */
3341 status = handle_timer_response(inv,
3342 e->body.tsx_state.src.rdata,
3343 PJ_TRUE);
3344 if (status != PJ_SUCCESS)
3345 break;
3346
Benny Prijono8ad55352006-02-08 11:16:05 +00003347 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003348
3349 inv_check_sdp_in_incoming_msg(inv, tsx,
3350 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003351
3352 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003353 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003354 }
3355 break;
3356
3357 case PJSIP_TSX_STATE_TERMINATED:
3358 /* INVITE transaction can be terminated either because UAC
3359 * transaction received 2xx response or because of transport
3360 * error.
3361 */
3362 if (tsx->status_code/100 == 2) {
3363 /* This must be receipt of 2xx response */
3364
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003365 /* Process session timer response. */
3366 status = handle_timer_response(inv,
3367 e->body.tsx_state.src.rdata,
3368 PJ_TRUE);
3369 if (status != PJ_SUCCESS)
3370 break;
3371
Benny Prijono268ca612006-02-07 12:34:11 +00003372 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003373 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003374
Benny Prijonoa66c7152006-02-09 01:26:14 +00003375 inv_check_sdp_in_incoming_msg(inv, tsx,
3376 e->body.tsx_state.src.rdata);
3377
Benny Prijono268ca612006-02-07 12:34:11 +00003378 /* Send ACK */
3379 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3380
Benny Prijonod5f9f422007-11-25 04:40:07 +00003381 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003382
Benny Prijono268ca612006-02-07 12:34:11 +00003383 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003384 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003385 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003386 }
3387 break;
3388
Benny Prijono34a404e2006-02-09 14:38:30 +00003389 default:
3390 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003391 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003392
Benny Prijono1f7767b2007-10-03 18:28:49 +00003393 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003394 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003395 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003396 * Transaction Does Not Exist), 408, or when it's timed out. In these
3397 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003398 * Note that 481 response to CANCEL does not terminate dialog usage,
3399 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003400 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003401 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3402 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003403 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3404 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003405 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003406 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003407 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003408 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3409 }
Benny Prijono268ca612006-02-07 12:34:11 +00003410 }
3411}
3412
Benny Prijono8ad55352006-02-08 11:16:05 +00003413/*
3414 * State INCOMING is after we received the request, but before
3415 * responses with tag are sent.
3416 */
3417static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003418{
3419 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3420 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3421
3422 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3423
Benny Prijono8ad55352006-02-08 11:16:05 +00003424 if (tsx == inv->invite_tsx) {
3425
3426 /*
3427 * Handle the INVITE state transition.
3428 */
3429
Benny Prijono268ca612006-02-07 12:34:11 +00003430 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003431
Benny Prijono64f851e2006-02-23 13:49:28 +00003432 case PJSIP_TSX_STATE_TRYING:
3433 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3434 break;
3435
Benny Prijono268ca612006-02-07 12:34:11 +00003436 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003437 /*
3438 * Transaction sent provisional response.
3439 */
Benny Prijono268ca612006-02-07 12:34:11 +00003440 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003441 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003442 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003443
Benny Prijono268ca612006-02-07 12:34:11 +00003444 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003445 /*
3446 * Transaction sent final response.
3447 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003448 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003449 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003450 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003451 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003452 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003453 }
Benny Prijono268ca612006-02-07 12:34:11 +00003454 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003455
Benny Prijono268ca612006-02-07 12:34:11 +00003456 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003457 /*
3458 * This happens on transport error (e.g. failed to send
3459 * response)
3460 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003461 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003462 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003463 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003464
Benny Prijono268ca612006-02-07 12:34:11 +00003465 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003466 pj_assert(!"Unexpected INVITE state");
3467 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003468 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003469
3470 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3471 tsx->role == PJSIP_ROLE_UAS &&
3472 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3473 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3474 {
3475
3476 /*
3477 * Handle incoming CANCEL request.
3478 */
3479
3480 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3481
Benny Prijono268ca612006-02-07 12:34:11 +00003482 }
3483}
3484
Benny Prijono8ad55352006-02-08 11:16:05 +00003485/*
3486 * State EARLY is for both UAS and UAC, after response with To tag
3487 * is sent/received.
3488 */
3489static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003490{
3491 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3492 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3493
3494 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3495
Benny Prijono8ad55352006-02-08 11:16:05 +00003496 if (tsx == inv->invite_tsx) {
3497
3498 /*
3499 * Handle the INVITE state progress.
3500 */
Benny Prijono268ca612006-02-07 12:34:11 +00003501
3502 switch (tsx->state) {
3503
3504 case PJSIP_TSX_STATE_PROCEEDING:
3505 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003506 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003507
3508 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3509 inv_check_sdp_in_incoming_msg(inv, tsx,
3510 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003511
3512 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3513 inv_handle_incoming_reliable_response(
3514 inv, e->body.tsx_state.src.rdata);
3515 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003516 }
Benny Prijono268ca612006-02-07 12:34:11 +00003517 break;
3518
3519 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003520 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003521 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003522 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003523 pj_status_t status;
3524
3525 /* Process session timer response. */
3526 status = handle_timer_response(inv,
3527 e->body.tsx_state.src.rdata,
3528 PJ_TRUE);
3529 if (status != PJ_SUCCESS)
3530 break;
3531
Benny Prijonoa66c7152006-02-09 01:26:14 +00003532 inv_check_sdp_in_incoming_msg(inv, tsx,
3533 e->body.tsx_state.src.rdata);
3534 }
3535
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003536 } else if (tsx->role == PJSIP_ROLE_UAC) {
3537
3538 handle_uac_call_rejection(inv, e);
3539
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003540 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003541 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003542 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003543 }
Benny Prijono268ca612006-02-07 12:34:11 +00003544 break;
3545
Benny Prijonof3195072006-02-14 21:15:30 +00003546 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003547 /* For some reason can go here (maybe when ACK for 2xx has
3548 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003549
Benny Prijono268ca612006-02-07 12:34:11 +00003550 case PJSIP_TSX_STATE_TERMINATED:
3551 /* INVITE transaction can be terminated either because UAC
3552 * transaction received 2xx response or because of transport
3553 * error.
3554 */
3555 if (tsx->status_code/100 == 2) {
3556
3557 /* This must be receipt of 2xx response */
3558
3559 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003560 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003561
Benny Prijonoa66c7152006-02-09 01:26:14 +00003562 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003563 pj_status_t status;
3564
3565 /* Process session timer response. */
3566 status = handle_timer_response(inv,
3567 e->body.tsx_state.src.rdata,
3568 PJ_TRUE);
3569 if (status != PJ_SUCCESS)
3570 break;
3571
Benny Prijonoa66c7152006-02-09 01:26:14 +00003572 inv_check_sdp_in_incoming_msg(inv, tsx,
3573 e->body.tsx_state.src.rdata);
3574 }
3575
Benny Prijono268ca612006-02-07 12:34:11 +00003576 /* if UAC, send ACK and move state to confirmed. */
3577 if (tsx->role == PJSIP_ROLE_UAC) {
3578 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3579
Benny Prijonod5f9f422007-11-25 04:40:07 +00003580 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003581 }
3582
3583 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003584 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003585 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003586 }
3587 break;
3588
3589 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003590 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003591 }
3592
Benny Prijono8ad55352006-02-08 11:16:05 +00003593 } else if (inv->role == PJSIP_ROLE_UAS &&
3594 tsx->role == PJSIP_ROLE_UAS &&
3595 tsx->method.id == PJSIP_CANCEL_METHOD &&
3596 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3597 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3598 {
Benny Prijono268ca612006-02-07 12:34:11 +00003599
Benny Prijono8ad55352006-02-08 11:16:05 +00003600 /*
3601 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003602 */
3603
Benny Prijono8ad55352006-02-08 11:16:05 +00003604 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3605
Benny Prijono1f7767b2007-10-03 18:28:49 +00003606 } else if (tsx->role == PJSIP_ROLE_UAS &&
3607 tsx->state == PJSIP_TSX_STATE_TRYING &&
3608 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003609 {
3610 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003611 * Handle incoming UPDATE
3612 */
3613 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3614
3615
3616 } else if (tsx->role == PJSIP_ROLE_UAC &&
3617 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3618 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3619 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3620 {
3621 /*
3622 * Handle response to outgoing UPDATE request.
3623 */
3624 inv_handle_update_response(inv, e);
3625
3626 } else if (tsx->role == PJSIP_ROLE_UAS &&
3627 tsx->state == PJSIP_TSX_STATE_TRYING &&
3628 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3629 {
3630 /*
3631 * Handle incoming PRACK
3632 */
3633 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3634
3635 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003636
3637 /* Generic handling for UAC tsx completion */
3638 handle_uac_tsx_response(inv, e);
Benny Prijono7efa2d62009-04-27 12:50:16 +00003639
3640 } else if (tsx->role == PJSIP_ROLE_UAS &&
3641 tsx->method.id == PJSIP_BYE_METHOD &&
3642 tsx->status_code < 200 &&
3643 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3644 {
3645 /* Received BYE before the 2xx/OK response to INVITE.
3646 * Assume that the 2xx/OK response is lost and the BYE
3647 * arrives earlier.
3648 */
3649 inv_respond_incoming_bye(inv, tsx, e->body.tsx_state.src.rdata, e);
3650
3651 /* Set timer just in case we will never get the final response
3652 * for INVITE.
3653 */
3654 pjsip_tsx_set_timeout(inv->invite_tsx, 64*pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00003655 }
3656}
3657
Benny Prijono8ad55352006-02-08 11:16:05 +00003658/*
3659 * State CONNECTING is after 2xx response to INVITE is sent/received.
3660 */
3661static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003662{
3663 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3664 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3665
3666 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3667
Benny Prijono8ad55352006-02-08 11:16:05 +00003668 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003669
Benny Prijono8ad55352006-02-08 11:16:05 +00003670 /*
3671 * Handle INVITE state progression.
3672 */
Benny Prijono268ca612006-02-07 12:34:11 +00003673 switch (tsx->state) {
3674
3675 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003676 /* It can only go here if incoming ACK request has the same Via
3677 * branch parameter as the INVITE transaction.
3678 */
3679 if (tsx->status_code/100 == 2) {
3680 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3681 inv_check_sdp_in_incoming_msg(inv, tsx,
3682 e->body.tsx_state.src.rdata);
3683 }
3684
Benny Prijono38998232006-02-08 22:44:25 +00003685 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003686 }
Benny Prijono268ca612006-02-07 12:34:11 +00003687 break;
3688
3689 case PJSIP_TSX_STATE_TERMINATED:
3690 /* INVITE transaction can be terminated either because UAC
3691 * transaction received 2xx response or because of transport
3692 * error.
3693 */
3694 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003695 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003696 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003697 }
3698 break;
3699
3700 case PJSIP_TSX_STATE_DESTROYED:
3701 /* Do nothing. */
3702 break;
3703
3704 default:
3705 pj_assert(!"Unexpected state");
3706 }
3707
Benny Prijono8ad55352006-02-08 11:16:05 +00003708 } else if (tsx->role == PJSIP_ROLE_UAS &&
3709 tsx->method.id == PJSIP_BYE_METHOD &&
3710 tsx->status_code < 200 &&
3711 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3712 {
3713
3714 /*
3715 * Handle incoming BYE.
3716 */
3717
3718 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3719
Benny Prijono38998232006-02-08 22:44:25 +00003720 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3721 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003722 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3723 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003724 {
3725
3726 /*
3727 * Outgoing BYE
3728 */
3729 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3730
Benny Prijono268ca612006-02-07 12:34:11 +00003731 }
Benny Prijono70127222006-07-02 14:53:05 +00003732 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3733 tsx->role == PJSIP_ROLE_UAS &&
3734 tsx->status_code < 200 &&
3735 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3736 {
Benny Prijono38998232006-02-08 22:44:25 +00003737
Benny Prijono70127222006-07-02 14:53:05 +00003738 /*
3739 * Handle strandled incoming CANCEL.
3740 */
3741 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3742 pjsip_tx_data *tdata;
3743 pj_status_t status;
3744
3745 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3746 if (status != PJ_SUCCESS) return;
3747
3748 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3749 if (status != PJ_SUCCESS) return;
3750
Benny Prijono1f7767b2007-10-03 18:28:49 +00003751 } else if (tsx->role == PJSIP_ROLE_UAS &&
3752 tsx->state == PJSIP_TSX_STATE_TRYING &&
3753 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3754 {
3755 /*
3756 * Handle incoming UPDATE
3757 */
3758 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3759
3760
3761 } else if (tsx->role == PJSIP_ROLE_UAC &&
3762 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3763 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3764 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3765 {
3766 /*
3767 * Handle response to outgoing UPDATE request.
3768 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003769 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003770 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003771
3772 } else if (tsx->role == PJSIP_ROLE_UAS &&
3773 tsx->state == PJSIP_TSX_STATE_TRYING &&
3774 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3775 {
3776 /*
3777 * Handle incoming PRACK
3778 */
3779 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3780
3781 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono87402382008-02-21 19:28:21 +00003782
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003783 /* Generic handling for UAC tsx completion */
3784 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003785 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003786
Benny Prijono268ca612006-02-07 12:34:11 +00003787}
3788
Benny Prijono8ad55352006-02-08 11:16:05 +00003789/*
3790 * State CONFIRMED is after ACK is sent/received.
3791 */
3792static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003793{
3794 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3795 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3796
3797 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3798
Benny Prijono268ca612006-02-07 12:34:11 +00003799
Benny Prijono8ad55352006-02-08 11:16:05 +00003800 if (tsx->method.id == PJSIP_BYE_METHOD &&
3801 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003802 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3803 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003804 {
Benny Prijono38998232006-02-08 22:44:25 +00003805
Benny Prijono8ad55352006-02-08 11:16:05 +00003806 /*
Benny Prijono38998232006-02-08 22:44:25 +00003807 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003808 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003809
Benny Prijonoa66c7152006-02-09 01:26:14 +00003810 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003811
Benny Prijono8ad55352006-02-08 11:16:05 +00003812 }
3813 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3814 tsx->role == PJSIP_ROLE_UAS &&
3815 tsx->status_code < 200 &&
3816 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3817 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003818
Benny Prijono8ad55352006-02-08 11:16:05 +00003819 /*
3820 * Handle incoming BYE.
3821 */
Benny Prijono268ca612006-02-07 12:34:11 +00003822
Benny Prijono8ad55352006-02-08 11:16:05 +00003823 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3824
Benny Prijono268ca612006-02-07 12:34:11 +00003825 }
Benny Prijono70127222006-07-02 14:53:05 +00003826 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3827 tsx->role == PJSIP_ROLE_UAS &&
3828 tsx->status_code < 200 &&
3829 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3830 {
3831
3832 /*
3833 * Handle strandled incoming CANCEL.
3834 */
3835 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3836 pjsip_tx_data *tdata;
3837 pj_status_t status;
3838
3839 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3840 if (status != PJ_SUCCESS) return;
3841
3842 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3843 if (status != PJ_SUCCESS) return;
3844
3845 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003846 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3847 tsx->role == PJSIP_ROLE_UAS)
3848 {
3849
3850 /*
3851 * Handle incoming re-INVITE
3852 */
3853 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3854
3855 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3856 pjsip_tx_data *tdata;
3857 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00003858 pjsip_status_code st_code;
Benny Prijono26ff9062006-02-21 23:47:00 +00003859
3860 /* Check if we have INVITE pending. */
3861 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003862 pj_str_t reason;
3863
3864 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003865
3866 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003867 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3868 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003869 if (status != PJ_SUCCESS)
3870 return;
3871
3872 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3873
3874
3875 return;
3876 }
3877
3878 /* Save the invite transaction. */
3879 inv->invite_tsx = tsx;
3880
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003881 /* Process session timers headers in the re-INVITE */
Nanang Izzuddin65add622009-08-11 16:26:20 +00003882 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003883 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00003884 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
3885 NULL, &tdata);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003886 if (status != PJ_SUCCESS)
3887 return;
3888
3889 pjsip_timer_update_resp(inv, tdata);
3890 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3891 return;
3892 }
3893
Benny Prijono26ff9062006-02-21 23:47:00 +00003894 /* Process SDP in incoming message. */
3895 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3896
3897 if (status != PJ_SUCCESS) {
3898
3899 /* Not Acceptable */
3900 const pjsip_hdr *accept;
3901
3902 status = pjsip_dlg_create_response(inv->dlg, rdata,
3903 488, NULL, &tdata);
3904 if (status != PJ_SUCCESS)
3905 return;
3906
3907
3908 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3909 NULL);
3910 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003911 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003912 pjsip_hdr_clone(tdata->pool, accept));
3913 }
3914
3915 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3916
3917 return;
3918 }
3919
3920 /* Create 2xx ANSWER */
3921 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3922 if (status != PJ_SUCCESS)
3923 return;
3924
Benny Prijono7d910092007-06-20 04:19:46 +00003925 /* If the INVITE request has SDP body, send answer.
3926 * Otherwise generate offer from local active SDP.
3927 */
3928 if (rdata->msg_info.msg->body != NULL) {
3929 status = process_answer(inv, 200, tdata, NULL);
3930 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003931 /* INVITE does not have SDP.
3932 * If on_create_offer() callback is implemented, ask app.
3933 * to generate an offer, otherwise just send active local
3934 * SDP to signal that nothing gets modified.
3935 */
3936 pjmedia_sdp_session *sdp = NULL;
3937
3938 if (mod_inv.cb.on_create_offer) {
3939 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3940 if (sdp) {
Benny Prijono60e31fc2009-04-23 11:50:25 +00003941 /* Notify negotiator about the new offer. This will
3942 * fix the offer with correct SDP origin.
3943 */
Benny Prijono40d62b62009-08-12 17:53:47 +00003944 status =
3945 pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
3946 inv->neg,
3947 sdp);
Benny Prijono60e31fc2009-04-23 11:50:25 +00003948
3949 /* Retrieve the "fixed" offer from negotiator */
Benny Prijonoc8fe3df2009-04-29 20:56:57 +00003950 if (status==PJ_SUCCESS) {
3951 const pjmedia_sdp_session *lsdp = NULL;
3952 pjmedia_sdp_neg_get_neg_local(inv->neg, &lsdp);
3953 sdp = (pjmedia_sdp_session*)lsdp;
3954 }
Benny Prijono77998ce2007-06-20 10:03:46 +00003955 }
3956 }
3957
3958 if (sdp == NULL) {
3959 const pjmedia_sdp_session *active_sdp = NULL;
Benny Prijono40d62b62009-08-12 17:53:47 +00003960 status = pjmedia_sdp_neg_send_local_offer(inv->pool_prov,
Benny Prijono77998ce2007-06-20 10:03:46 +00003961 inv->neg,
3962 &active_sdp);
3963 if (status == PJ_SUCCESS)
3964 sdp = (pjmedia_sdp_session*) active_sdp;
3965 }
3966
3967 if (sdp) {
3968 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003969 }
3970 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003971
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003972 if (status != PJ_SUCCESS) {
3973 /*
3974 * SDP negotiation has failed.
3975 */
3976 pj_status_t rc;
3977 pj_str_t reason;
3978
3979 /* Delete the 2xx answer */
3980 pjsip_tx_data_dec_ref(tdata);
3981
3982 /* Create 500 response */
3983 reason = pj_str("SDP negotiation failed");
3984 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3985 &tdata);
3986 if (rc == PJ_SUCCESS) {
3987 pjsip_warning_hdr *w;
3988 const pj_str_t *endpt_name;
3989
3990 endpt_name = pjsip_endpt_name(dlg->endpt);
3991 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3992 endpt_name,
3993 status);
3994 if (w)
3995 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3996
3997 pjsip_inv_send_msg(inv, tdata);
3998 }
3999 return;
4000 }
4001
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00004002 /* Invoke Session Timers */
4003 pjsip_timer_update_resp(inv, tdata);
4004
Benny Prijono1d9b9a42006-09-25 13:40:12 +00004005 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00004006 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00004007
Benny Prijono7d910092007-06-20 04:19:46 +00004008 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
4009 /* This is the case where ACK has the same branch as
4010 * the INVITE request.
4011 */
4012 if (tsx->status_code/100 == 2 &&
4013 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
4014 {
4015 inv_check_sdp_in_incoming_msg(inv, tsx,
4016 e->body.tsx_state.src.rdata);
Nanang Izzuddin0fd92672010-06-16 15:26:18 +00004017
4018 /* Check if local offer got no SDP answer */
4019 if (pjmedia_sdp_neg_get_state(inv->neg)==
4020 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
4021 {
4022 pjmedia_sdp_neg_cancel_offer(inv->neg);
4023 }
Benny Prijono7d910092007-06-20 04:19:46 +00004024 }
4025
Benny Prijono26ff9062006-02-21 23:47:00 +00004026 }
4027
4028 }
4029 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
4030 tsx->role == PJSIP_ROLE_UAC)
4031 {
Benny Prijono22e48c92008-03-20 14:40:50 +00004032
Benny Prijono26ff9062006-02-21 23:47:00 +00004033 /*
4034 * Handle outgoing re-INVITE
4035 */
Benny Prijono22e48c92008-03-20 14:40:50 +00004036 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
4037
Benny Prijono61fc5e62008-06-25 18:35:31 +00004038 /* Must not have other pending INVITE transaction */
4039 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
4040
Benny Prijono22e48c92008-03-20 14:40:50 +00004041 /* Save pending invite transaction */
4042 inv->invite_tsx = tsx;
4043
4044 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
4045 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00004046 {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004047 pj_status_t status;
Benny Prijono26ff9062006-02-21 23:47:00 +00004048
4049 /* Re-INVITE was accepted. */
4050
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004051 /* Process session timer response. */
4052 status = handle_timer_response(inv,
4053 e->body.tsx_state.src.rdata,
4054 PJ_TRUE);
4055 if (status != PJ_SUCCESS)
4056 return;
4057
Benny Prijono26ff9062006-02-21 23:47:00 +00004058 /* Process SDP */
4059 inv_check_sdp_in_incoming_msg(inv, tsx,
4060 e->body.tsx_state.src.rdata);
4061
Nanang Izzuddin0fd92672010-06-16 15:26:18 +00004062 /* Check if local offer got no SDP answer */
4063 if (pjmedia_sdp_neg_get_state(inv->neg)==
4064 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
4065 {
4066 pjmedia_sdp_neg_cancel_offer(inv->neg);
4067 }
4068
Benny Prijono26ff9062006-02-21 23:47:00 +00004069 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00004070 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00004071
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004072 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00004073
4074 /* Handle response that terminates dialog */
4075 /* Nothing to do (already handled) */
4076
Benny Prijono77998ce2007-06-20 10:03:46 +00004077 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
4078
4079 pjmedia_sdp_neg_state neg_state;
4080
4081 /* Outgoing INVITE transaction has failed, cancel SDP nego */
4082 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
4083 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
4084 pjmedia_sdp_neg_cancel_offer(inv->neg);
4085 }
Benny Prijonoe641a742009-05-01 12:01:28 +00004086
4087 if (tsx == inv->invite_tsx)
4088 inv->invite_tsx = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00004089 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00004090
4091 } else if (tsx->role == PJSIP_ROLE_UAS &&
4092 tsx->state == PJSIP_TSX_STATE_TRYING &&
4093 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
4094 {
4095 /*
4096 * Handle incoming UPDATE
4097 */
4098 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
4099
4100 } else if (tsx->role == PJSIP_ROLE_UAC &&
4101 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
4102 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
4103 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
4104 {
4105 /*
4106 * Handle response to outgoing UPDATE request.
4107 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004108 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00004109 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00004110
4111 } else if (tsx->role == PJSIP_ROLE_UAS &&
4112 tsx->state == PJSIP_TSX_STATE_TRYING &&
4113 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
4114 {
4115 /*
4116 * Handle strandled incoming PRACK
4117 */
4118 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
4119
4120 } else if (tsx->role == PJSIP_ROLE_UAC) {
4121 /*
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004122 * Handle 401/407/408/481/422 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00004123 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004124 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00004125 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00004126
Benny Prijono268ca612006-02-07 12:34:11 +00004127}
4128
Benny Prijono8ad55352006-02-08 11:16:05 +00004129/*
4130 * After session has been terminated, but before dialog is destroyed
4131 * (because dialog has other usages, or because dialog is waiting for
4132 * the last transaction to terminate).
4133 */
4134static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00004135{
Benny Prijono8ad55352006-02-08 11:16:05 +00004136 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4137 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00004138
Benny Prijono8ad55352006-02-08 11:16:05 +00004139 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
4140
Benny Prijono70127222006-07-02 14:53:05 +00004141 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00004142 tsx->status_code < 200 &&
4143 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
4144 {
Benny Prijono70127222006-07-02 14:53:05 +00004145 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00004146
4147 /*
Benny Prijono70127222006-07-02 14:53:05 +00004148 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00004149 */
Benny Prijono70127222006-07-02 14:53:05 +00004150 if (tsx->method.id == PJSIP_BYE_METHOD) {
4151 inv_respond_incoming_bye( inv, tsx, rdata, e );
4152 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
4153 /*
4154 * Respond CANCEL with 200/OK too.
4155 */
4156 pjsip_tx_data *tdata;
4157 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00004158
Benny Prijono70127222006-07-02 14:53:05 +00004159 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
4160 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00004161
Benny Prijono70127222006-07-02 14:53:05 +00004162 status = pjsip_dlg_send_response(dlg, tsx, tdata);
4163 if (status != PJ_SUCCESS) return;
4164
4165 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00004166
4167 } else if (tsx->role == PJSIP_ROLE_UAC) {
4168 /*
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004169 * Handle 401/407/408/481/422 response
Benny Prijono61fc5e62008-06-25 18:35:31 +00004170 */
4171 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00004172 }
Benny Prijono268ca612006-02-07 12:34:11 +00004173}
4174