blob: dab68d4c46e363714ed8701cd47aa591e48ad61d [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;
780
781 /* Get the message in rdata */
782 msg = rdata->msg_info.msg;
783
784 /* Must be INVITE request. */
785 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
786 msg->line.req.method.id == PJSIP_INVITE_METHOD,
787 PJ_EINVAL);
788
789 /* If tdata is specified, then either dlg or endpt must be specified */
790 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
791
792 /* Get the endpoint */
793 endpt = endpt ? endpt : dlg->endpt;
794
795 /* Init response header list */
796 pj_list_init(&res_hdr_list);
797
Benny Prijono8b33bba2010-06-02 03:03:43 +0000798 /* Check the Contact header */
799 c_hdr = (pjsip_contact_hdr*)
800 pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
801 if (!c_hdr || !c_hdr->uri) {
802 /* Missing Contact header or Contact contains "*" */
803 pjsip_warning_hdr *w;
804 pj_str_t warn_text;
805
806 warn_text = pj_str("Bad/missing Contact header");
807 w = pjsip_warning_hdr_create(rdata->tp_info.pool, 399,
808 pjsip_endpt_name(endpt),
809 &warn_text);
810 if (w) {
811 pj_list_push_back(&res_hdr_list, w);
812 }
813
814 code = PJSIP_SC_BAD_REQUEST;
815 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
816 goto on_return;
817 }
818
Benny Prijono87a90212008-01-23 20:29:30 +0000819 /* Check the request body, see if it's something that we support,
820 * only when the body hasn't been parsed before.
Benny Prijono268ca612006-02-07 12:34:11 +0000821 */
Benny Prijono87a90212008-01-23 20:29:30 +0000822 if (r_sdp==NULL && msg->body) {
Benny Prijono268ca612006-02-07 12:34:11 +0000823 pjsip_msg_body *body = msg->body;
824 pj_str_t str_application = {"application", 11};
825 pj_str_t str_sdp = { "sdp", 3 };
826 pjmedia_sdp_session *sdp;
827
828 /* Check content type. */
829 if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||
830 pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)
831 {
832 /* Not "application/sdp" */
833 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
834 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
835
836 if (p_tdata) {
837 /* Add Accept header to response */
838 pjsip_accept_hdr *acc;
839
840 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
841 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
842 acc->values[acc->count++] = pj_str("application/sdp");
843 pj_list_push_back(&res_hdr_list, acc);
844 }
845
846 goto on_return;
847 }
848
849 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000850 status = pjmedia_sdp_parse(rdata->tp_info.pool,
851 (char*)body->data, body->len, &sdp);
Benny Prijono268ca612006-02-07 12:34:11 +0000852 if (status == PJ_SUCCESS)
853 status = pjmedia_sdp_validate(sdp);
854
855 if (status != PJ_SUCCESS) {
856 /* Unparseable or invalid SDP */
857 code = PJSIP_SC_BAD_REQUEST;
858
859 if (p_tdata) {
860 /* Add Warning header. */
861 pjsip_warning_hdr *w;
862
863 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
864 pjsip_endpt_name(endpt),
865 status);
866 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
867
868 pj_list_push_back(&res_hdr_list, w);
869 }
870
871 goto on_return;
872 }
873
Benny Prijono87a90212008-01-23 20:29:30 +0000874 r_sdp = sdp;
875 }
876
877 if (r_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +0000878 /* Negotiate with local SDP */
879 if (l_sdp) {
880 pjmedia_sdp_neg *neg;
881
882 /* Local SDP must be valid! */
883 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
884 status);
885
886 /* Create SDP negotiator */
887 status = pjmedia_sdp_neg_create_w_remote_offer(
Benny Prijono87a90212008-01-23 20:29:30 +0000888 rdata->tp_info.pool, l_sdp, r_sdp, &neg);
Benny Prijono268ca612006-02-07 12:34:11 +0000889 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
890
891 /* Negotiate SDP */
892 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
893 if (status != PJ_SUCCESS) {
894
895 /* Incompatible media */
896 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000897
898 if (p_tdata) {
899 pjsip_accept_hdr *acc;
900 pjsip_warning_hdr *w;
901
902 /* Add Warning header. */
903 w = pjsip_warning_hdr_create_from_status(
904 rdata->tp_info.pool,
905 pjsip_endpt_name(endpt), status);
906 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
907
908 pj_list_push_back(&res_hdr_list, w);
909
910 /* Add Accept header to response */
911 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
912 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
913 acc->values[acc->count++] = pj_str("application/sdp");
914 pj_list_push_back(&res_hdr_list, acc);
915
916 }
917
918 goto on_return;
919 }
920 }
921 }
922
923 /* Check supported methods, see if peer supports UPDATE.
924 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
925 * implicitly by sending this INVITE.
926 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000927 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000928 if (allow) {
929 unsigned i;
930 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
931
932 for (i=0; i<allow->count; ++i) {
933 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
934 break;
935 }
936
937 if (i != allow->count) {
938 /* UPDATE is present in Allow */
939 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
940 }
941
942 }
943
944 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000945 sup_hdr = (pjsip_supported_hdr*)
946 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000947 if (sup_hdr) {
948 unsigned i;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000949 const pj_str_t STR_100REL = { "100rel", 6};
950 const pj_str_t STR_TIMER = { "timer", 5};
Benny Prijono268ca612006-02-07 12:34:11 +0000951
952 for (i=0; i<sup_hdr->count; ++i) {
953 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
954 rem_option |= PJSIP_INV_SUPPORT_100REL;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000955 if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000956 rem_option |= PJSIP_INV_SUPPORT_TIMER;
957 }
958 }
959
960 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000961 req_hdr = (pjsip_require_hdr*)
962 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000963 if (req_hdr) {
964 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +0000965 const pj_str_t STR_100REL = { "100rel", 6};
Benny Prijono053f5222006-11-11 16:16:04 +0000966 const pj_str_t STR_REPLACES = { "replaces", 8 };
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000967 const pj_str_t STR_TIMER = { "timer", 5 };
Benny Prijono268ca612006-02-07 12:34:11 +0000968 unsigned unsupp_cnt = 0;
969 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
970
971 for (i=0; i<req_hdr->count; ++i) {
972 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
973 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
974 {
975 rem_option |= PJSIP_INV_REQUIRE_100REL;
976
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000977 } else if ((*options & PJSIP_INV_SUPPORT_TIMER) &&
978 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000979 {
980 rem_option |= PJSIP_INV_REQUIRE_TIMER;
981
Benny Prijono053f5222006-11-11 16:16:04 +0000982 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
983 pj_bool_t supp;
984
985 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
986 NULL, &STR_REPLACES);
987 if (!supp)
988 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
989
Nanang Izzuddin5d5a20e2009-08-06 16:04:20 +0000990 } else if (!pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
991 NULL, &req_hdr->values[i]))
992 {
Benny Prijono268ca612006-02-07 12:34:11 +0000993 /* Unknown/unsupported extension tag! */
994 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
995 }
996 }
997
998 /* Check if there are required tags that we don't support */
999 if (unsupp_cnt) {
1000
1001 code = PJSIP_SC_BAD_EXTENSION;
1002 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1003
1004 if (p_tdata) {
1005 pjsip_unsupported_hdr *unsupp_hdr;
1006 const pjsip_hdr *h;
1007
1008 /* Add Unsupported header. */
1009 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
1010 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
1011
1012 unsupp_hdr->count = unsupp_cnt;
1013 for (i=0; i<unsupp_cnt; ++i)
1014 unsupp_hdr->values[i] = unsupp_tags[i];
1015
1016 pj_list_push_back(&res_hdr_list, unsupp_hdr);
1017
1018 /* Add Supported header. */
1019 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
1020 NULL);
1021 pj_assert(h);
1022 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001023 sup_hdr = (pjsip_supported_hdr*)
1024 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001025 pj_list_push_back(&res_hdr_list, sup_hdr);
1026 }
1027 }
1028
1029 goto on_return;
1030 }
1031 }
1032
1033 /* Check if there are local requirements that are not supported
1034 * by peer.
1035 */
1036 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
1037 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
Nanang Izzuddin65add622009-08-11 16:26:20 +00001038 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
1039 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
Benny Prijono268ca612006-02-07 12:34:11 +00001040 {
1041 code = PJSIP_SC_EXTENSION_REQUIRED;
1042 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1043
1044 if (p_tdata) {
1045 const pjsip_hdr *h;
1046
1047 /* Add Require header. */
1048 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
1049 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
1050
1051 if (*options & PJSIP_INV_REQUIRE_100REL)
1052 req_hdr->values[req_hdr->count++] = pj_str("100rel");
Benny Prijono268ca612006-02-07 12:34:11 +00001053 if (*options & PJSIP_INV_REQUIRE_TIMER)
1054 req_hdr->values[req_hdr->count++] = pj_str("timer");
1055
1056 pj_list_push_back(&res_hdr_list, req_hdr);
1057
1058 /* Add Supported header. */
1059 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
1060 NULL);
1061 pj_assert(h);
1062 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001063 sup_hdr = (pjsip_supported_hdr*)
1064 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001065 pj_list_push_back(&res_hdr_list, sup_hdr);
1066 }
1067
1068 }
1069
1070 goto on_return;
1071 }
1072
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001073 /* If remote Require something that we support, make us Require
1074 * that feature too.
1075 */
1076 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
1077 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
1078 *options |= PJSIP_INV_REQUIRE_100REL;
1079 }
1080 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1081 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1082 *options |= PJSIP_INV_REQUIRE_TIMER;
1083 }
1084
Benny Prijono268ca612006-02-07 12:34:11 +00001085on_return:
1086
1087 /* Create response if necessary */
1088 if (code != 200 && p_tdata) {
1089 pjsip_tx_data *tdata;
1090 const pjsip_hdr *h;
1091
1092 if (dlg) {
1093 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1094 &tdata);
1095 } else {
1096 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1097 &tdata);
1098 }
1099
1100 if (status != PJ_SUCCESS)
1101 return status;
1102
1103 /* Add response headers. */
1104 h = res_hdr_list.next;
1105 while (h != &res_hdr_list) {
1106 pjsip_hdr *cloned;
1107
Benny Prijonoa1e69682007-05-11 15:14:34 +00001108 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001109 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1110
1111 pjsip_msg_add_hdr(tdata->msg, cloned);
1112
1113 h = h->next;
1114 }
1115
1116 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001117
1118 /* Can not return PJ_SUCCESS when response message is produced.
1119 * Ref: PROTOS test ~#2490
1120 */
1121 if (status == PJ_SUCCESS)
1122 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1123
Benny Prijono268ca612006-02-07 12:34:11 +00001124 }
1125
1126 return status;
1127}
1128
Benny Prijono87a90212008-01-23 20:29:30 +00001129
1130/*
1131 * Verify incoming INVITE request.
1132 */
1133PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1134 unsigned *options,
1135 const pjmedia_sdp_session *l_sdp,
1136 pjsip_dialog *dlg,
1137 pjsip_endpoint *endpt,
1138 pjsip_tx_data **p_tdata)
1139{
1140 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1141 endpt, p_tdata);
1142}
1143
Benny Prijono268ca612006-02-07 12:34:11 +00001144/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001145 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001146 */
1147PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1148 pjsip_rx_data *rdata,
1149 const pjmedia_sdp_session *local_sdp,
1150 unsigned options,
1151 pjsip_inv_session **p_inv)
1152{
1153 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001154 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001155 pjsip_msg *msg;
1156 pjmedia_sdp_session *rem_sdp = NULL;
1157 pj_status_t status;
1158
1159 /* Verify arguments. */
1160 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1161
1162 /* Dialog MUST have been initialised. */
1163 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1164
1165 msg = rdata->msg_info.msg;
1166
1167 /* rdata MUST contain INVITE request */
1168 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1169 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1170 PJ_EINVALIDOP);
1171
Benny Prijono8eae8382006-08-10 21:44:26 +00001172 /* Lock dialog */
1173 pjsip_dlg_inc_lock(dlg);
1174
Benny Prijono268ca612006-02-07 12:34:11 +00001175 /* Normalize options */
1176 if (options & PJSIP_INV_REQUIRE_100REL)
1177 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +00001178 if (options & PJSIP_INV_REQUIRE_TIMER)
1179 options |= PJSIP_INV_SUPPORT_TIMER;
1180
1181 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001182 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001183 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001184
1185 inv->pool = dlg->pool;
1186 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001187 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001188 inv->dlg = dlg;
1189 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001190 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001191 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001192
Benny Prijono40d62b62009-08-12 17:53:47 +00001193 /* Create flip-flop pool (see ticket #877) */
1194 /* (using inv->obj_name as temporary variable for pool names */
1195 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg->pool);
1196 inv->pool_prov = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1197 POOL_INIT_SIZE, POOL_INC_SIZE);
1198 inv->pool_active = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1199 POOL_INIT_SIZE, POOL_INC_SIZE);
1200
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001201 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001202 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001203
Benny Prijono268ca612006-02-07 12:34:11 +00001204 /* Parse SDP in message body, if present. */
1205 if (msg->body) {
1206 pjsip_msg_body *body = msg->body;
1207
1208 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001209 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001210 &rem_sdp);
1211 if (status == PJ_SUCCESS)
1212 status = pjmedia_sdp_validate(rem_sdp);
1213
Benny Prijono8eae8382006-08-10 21:44:26 +00001214 if (status != PJ_SUCCESS) {
1215 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001216 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001217 }
Benny Prijono268ca612006-02-07 12:34:11 +00001218 }
1219
1220 /* Create negotiator. */
1221 if (rem_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001222 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool,
1223 local_sdp, rem_sdp,
1224 &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001225
1226 } else if (local_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001227 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1228 local_sdp, &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001229 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001230 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001231 }
1232
Benny Prijono8eae8382006-08-10 21:44:26 +00001233 if (status != PJ_SUCCESS) {
1234 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001235 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001236 }
Benny Prijono268ca612006-02-07 12:34:11 +00001237
1238 /* Register invite as dialog usage. */
1239 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001240 if (status != PJ_SUCCESS) {
1241 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001242 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001243 }
Benny Prijono268ca612006-02-07 12:34:11 +00001244
1245 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001246 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001247
1248 /* Save the invite transaction. */
1249 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001250
1251 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001252 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001253 tsx_inv_data->inv = inv;
1254 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001255
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001256 /* Create 100rel handler */
1257 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001258 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001259 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001260
Benny Prijono268ca612006-02-07 12:34:11 +00001261 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001262 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001263 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001264
1265 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1266 dlg->obj_name));
1267
Benny Prijono268ca612006-02-07 12:34:11 +00001268 return PJ_SUCCESS;
1269}
1270
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001271/*
1272 * Forcefully terminate the session.
1273 */
1274PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1275 int st_code,
1276 pj_bool_t notify)
1277{
1278 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1279
1280 /* Lock dialog. */
1281 pjsip_dlg_inc_lock(inv->dlg);
1282
1283 /* Set callback notify flag. */
1284 inv->notify = notify;
1285
1286 /* If there's pending transaction, terminate the transaction.
1287 * This may subsequently set the INVITE session state to
1288 * disconnected.
1289 */
1290 if (inv->invite_tsx &&
1291 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1292 {
1293 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1294
1295 }
1296
1297 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001298 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001299
1300 /* Forcefully terminate the session if state is not DISCONNECTED */
1301 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1302 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1303 }
1304
1305 /* Done.
1306 * The dec_lock() below will actually destroys the dialog if it
1307 * has no other session.
1308 */
1309 pjsip_dlg_dec_lock(inv->dlg);
1310
1311 return PJ_SUCCESS;
1312}
1313
1314
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001315/*
1316 * Restart UAC session, possibly because app or us wants to re-send the
1317 * INVITE request due to 401/407 challenge or 3xx response.
1318 */
1319PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1320 pj_bool_t new_offer)
1321{
1322 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1323
1324 inv->state = PJSIP_INV_STATE_NULL;
1325 inv->invite_tsx = NULL;
1326 if (inv->last_answer) {
1327 pjsip_tx_data_dec_ref(inv->last_answer);
1328 inv->last_answer = NULL;
1329 }
1330
1331 if (new_offer && inv->neg) {
1332 pjmedia_sdp_neg_state neg_state;
1333
1334 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1335 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1336 pjmedia_sdp_neg_cancel_offer(inv->neg);
1337 }
1338 }
1339
1340 return PJ_SUCCESS;
1341}
1342
1343
Benny Prijono268ca612006-02-07 12:34:11 +00001344static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1345{
1346 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001347 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001348}
1349
1350static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1351{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001352 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001353}
1354
Benny Prijono56315612006-07-18 14:39:40 +00001355
1356PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1357 pjmedia_sdp_session *sdp,
1358 pjsip_msg_body **p_body)
1359{
1360 const pj_str_t STR_APPLICATION = { "application", 11};
1361 const pj_str_t STR_SDP = { "sdp", 3 };
1362 pjsip_msg_body *body;
1363
Benny Prijonoa1e69682007-05-11 15:14:34 +00001364 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001365 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1366
1367 body->content_type.type = STR_APPLICATION;
1368 body->content_type.subtype = STR_SDP;
1369 body->data = sdp;
1370 body->len = 0;
1371 body->clone_data = &clone_sdp;
1372 body->print_body = &print_sdp;
1373
1374 *p_body = body;
1375
1376 return PJ_SUCCESS;
1377}
1378
Benny Prijono268ca612006-02-07 12:34:11 +00001379static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1380 const pjmedia_sdp_session *c_sdp)
1381{
1382 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001383 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001384
Benny Prijono56315612006-07-18 14:39:40 +00001385 status = pjsip_create_sdp_body(pool,
1386 pjmedia_sdp_session_clone(pool, c_sdp),
1387 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001388
Benny Prijono56315612006-07-18 14:39:40 +00001389 if (status != PJ_SUCCESS)
1390 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001391
1392 return body;
1393}
1394
1395/*
1396 * Create initial INVITE request.
1397 */
1398PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1399 pjsip_tx_data **p_tdata )
1400{
1401 pjsip_tx_data *tdata;
1402 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001403 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001404 pj_status_t status;
1405
1406 /* Verify arguments. */
1407 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1408
Benny Prijono26ff9062006-02-21 23:47:00 +00001409 /* State MUST be NULL or CONFIRMED. */
1410 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1411 inv->state == PJSIP_INV_STATE_CONFIRMED,
1412 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001413
Benny Prijono64f851e2006-02-23 13:49:28 +00001414 /* Lock dialog. */
1415 pjsip_dlg_inc_lock(inv->dlg);
1416
Benny Prijono268ca612006-02-07 12:34:11 +00001417 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001418 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001419 &tdata);
1420 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001421 goto on_return;
1422
Benny Prijono268ca612006-02-07 12:34:11 +00001423
Benny Prijono26ff9062006-02-21 23:47:00 +00001424 /* If this is the first INVITE, then copy the headers from inv_hdr.
1425 * These are the headers parsed from the request URI when the
1426 * dialog was created.
1427 */
1428 if (inv->state == PJSIP_INV_STATE_NULL) {
1429 hdr = inv->dlg->inv_hdr.next;
1430
1431 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001432 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001433 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1434 hdr = hdr->next;
1435 }
1436 }
1437
1438 /* See if we have SDP to send. */
1439 if (inv->neg) {
1440 pjmedia_sdp_neg_state neg_state;
1441
1442 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1443
1444 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1445 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1446 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1447
1448
1449 } else {
1450 has_sdp = PJ_FALSE;
1451 }
1452
Benny Prijono268ca612006-02-07 12:34:11 +00001453 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001454 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001455 const pjmedia_sdp_session *offer;
1456
1457 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono176a11f2009-04-14 11:14:51 +00001458 if (status != PJ_SUCCESS) {
1459 pjsip_tx_data_dec_ref(tdata);
Benny Prijono64f851e2006-02-23 13:49:28 +00001460 goto on_return;
Benny Prijono176a11f2009-04-14 11:14:51 +00001461 }
Benny Prijono268ca612006-02-07 12:34:11 +00001462
1463 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1464 }
1465
1466 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001467 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001468 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1469 if (hdr) {
1470 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1471 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1472 }
Benny Prijono268ca612006-02-07 12:34:11 +00001473 }
1474
1475 /* Add Supported header */
1476 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1477 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001478 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001479 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1480 }
1481
1482 /* Add Require header. */
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001483 if ((inv->options & PJSIP_INV_REQUIRE_100REL) ||
1484 (inv->options & PJSIP_INV_REQUIRE_TIMER))
1485 {
1486 pjsip_require_hdr *hreq;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001487
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001488 hreq = pjsip_require_hdr_create(tdata->pool);
1489
1490 if (inv->options & PJSIP_INV_REQUIRE_100REL)
1491 hreq->values[hreq->count++] = pj_str("100rel");
1492 if (inv->options & PJSIP_INV_REQUIRE_TIMER)
1493 hreq->values[hreq->count++] = pj_str("timer");
1494
1495 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001496 }
Benny Prijono268ca612006-02-07 12:34:11 +00001497
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001498 status = pjsip_timer_update_req(inv, tdata);
1499 if (status != PJ_SUCCESS)
1500 goto on_return;
1501
Benny Prijono268ca612006-02-07 12:34:11 +00001502 /* Done. */
1503 *p_tdata = tdata;
1504
Benny Prijono64f851e2006-02-23 13:49:28 +00001505
1506on_return:
1507 pjsip_dlg_dec_lock(inv->dlg);
1508 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001509}
1510
1511
Benny Prijono40d62b62009-08-12 17:53:47 +00001512/* Util: swap pool */
1513static void swap_pool(pj_pool_t **p1, pj_pool_t **p2)
1514{
1515 pj_pool_t *tmp = *p1;
1516 *p1 = *p2;
1517 *p2 = tmp;
1518}
1519
Benny Prijono268ca612006-02-07 12:34:11 +00001520/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001521 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001522 */
1523static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1524{
1525 pj_status_t status;
1526
1527 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1528 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1529 PJMEDIA_SDPNEG_EINSTATE);
1530
Benny Prijono40d62b62009-08-12 17:53:47 +00001531 status = pjmedia_sdp_neg_negotiate(inv->pool_prov, inv->neg, 0);
Benny Prijono95196582006-02-09 00:13:40 +00001532
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001533 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1534
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001535 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001536 (*mod_inv.cb.on_media_update)(inv, status);
1537
Benny Prijonobcc8dd72010-02-09 12:28:03 +00001538 /* Invite session may have been terminated by the application even
1539 * after a successful SDP negotiation, for example when no audio
1540 * codec is present in the offer (see ticket #1034).
1541 */
1542 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Nanang Izzuddin756da442009-08-14 13:23:22 +00001543
Benny Prijonobcc8dd72010-02-09 12:28:03 +00001544 /* Swap the flip-flop pool when SDP negotiation success. */
1545 if (status == PJ_SUCCESS) {
1546 swap_pool(&inv->pool_prov, &inv->pool_active);
1547 }
1548
1549 /* Reset the provisional pool regardless SDP negotiation result. */
1550 pj_pool_reset(inv->pool_prov);
1551
1552 } else {
1553
1554 status = PJSIP_ERRNO_FROM_SIP_STATUS(inv->cause);
1555 }
Benny Prijono40d62b62009-08-12 17:53:47 +00001556
Benny Prijono95196582006-02-09 00:13:40 +00001557 return status;
1558}
1559
1560/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001561 * Check in incoming message for SDP offer/answer.
1562 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001563static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1564 pjsip_transaction *tsx,
1565 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001566{
1567 struct tsx_inv_data *tsx_inv_data;
1568 static const pj_str_t str_application = { "application", 11 };
1569 static const pj_str_t str_sdp = { "sdp", 3 };
1570 pj_status_t status;
1571 pjsip_msg *msg;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001572 pjmedia_sdp_session *rem_sdp;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001573
1574 /* Check if SDP is present in the message. */
1575
1576 msg = rdata->msg_info.msg;
1577 if (msg->body == NULL) {
1578 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001579 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001580 }
1581
1582 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1583 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1584 {
1585 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001586 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001587 }
1588
Benny Prijono8fcb4332008-10-31 18:01:48 +00001589 /* Get/attach invite session's transaction data */
1590 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1591 if (tsx_inv_data == NULL) {
1592 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1593 tsx_inv_data->inv = inv;
1594 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1595 }
1596
1597 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1598 * EXCEPT if:
1599 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1600 * - the previous negotiation was done on an early media (18x) and
1601 * this response is a final/2xx response, and
1602 * - the 2xx response has different To tag than the 18x response
1603 * (i.e. the request has forked).
1604 *
1605 * The exception above is to add a rudimentary support for early media
1606 * forking (sample case: custom ringback). See this ticket for more
1607 * info: http://trac.pjsip.org/repos/ticket/657
1608 */
1609 if (tsx_inv_data->sdp_done) {
1610 pj_str_t res_tag;
1611
1612 res_tag = rdata->msg_info.to->tag;
1613
1614 /* Allow final response after SDP has been negotiated in early
1615 * media, IF this response is a final response with different
1616 * tag.
1617 */
1618 if (tsx->role == PJSIP_ROLE_UAC &&
1619 rdata->msg_info.msg->line.status.code/100 == 2 &&
1620 tsx_inv_data->done_early &&
1621 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1622 {
1623 const pjmedia_sdp_session *reoffer_sdp = NULL;
1624
1625 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1626 "after SDP negotiation has been done in early "
1627 "media. Renegotiating SDP.."));
1628
1629 /* Retrieve original SDP offer from INVITE request */
1630 reoffer_sdp = (const pjmedia_sdp_session*)
1631 tsx->last_tx->msg->body->data;
1632
1633 /* Feed the original offer to negotiator */
Benny Prijono40d62b62009-08-12 17:53:47 +00001634 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
1635 inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001636 reoffer_sdp);
1637 if (status != PJ_SUCCESS) {
1638 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1639 "forked 2xx response (err=%d)", status));
1640 return status;
1641 }
1642
1643 } else {
1644
1645 if (rdata->msg_info.msg->body) {
1646 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1647 "body is ignored"));
1648 }
1649 return PJ_SUCCESS;
1650 }
1651 }
1652
Benny Prijonoa66c7152006-02-09 01:26:14 +00001653 /* Parse the SDP body. */
1654
Benny Prijonoa1e69682007-05-11 15:14:34 +00001655 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1656 (char*)msg->body->data,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001657 msg->body->len, &rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001658 if (status == PJ_SUCCESS)
Benny Prijono8fcb4332008-10-31 18:01:48 +00001659 status = pjmedia_sdp_validate(rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001660
Benny Prijonoa66c7152006-02-09 01:26:14 +00001661 if (status != PJ_SUCCESS) {
1662 char errmsg[PJ_ERR_MSG_SIZE];
1663 pj_strerror(status, errmsg, sizeof(errmsg));
1664 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1665 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001666 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001667 }
1668
1669 /* The SDP can be an offer or answer, depending on negotiator's state */
1670
1671 if (inv->neg == NULL ||
1672 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1673 {
1674
1675 /* This is an offer. */
1676
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001677 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1678 pjsip_rx_data_get_info(rdata)));
1679
Benny Prijonoa66c7152006-02-09 01:26:14 +00001680 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001681 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001682 rem_sdp, &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001683 } else {
Benny Prijono40d62b62009-08-12 17:53:47 +00001684 status=pjmedia_sdp_neg_set_remote_offer(inv->pool_prov, inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001685 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001686 }
1687
1688 if (status != PJ_SUCCESS) {
1689 char errmsg[PJ_ERR_MSG_SIZE];
1690 pj_strerror(status, errmsg, sizeof(errmsg));
1691 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1692 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001693 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001694 }
1695
1696 /* Inform application about remote offer. */
1697
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001698 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001699
Benny Prijono8fcb4332008-10-31 18:01:48 +00001700 (*mod_inv.cb.on_rx_offer)(inv, rem_sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001701
1702 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001703
1704 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1705 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1706 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001707 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001708
1709 /* This is an answer.
1710 * Process and negotiate remote answer.
1711 */
1712
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001713 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1714 pjsip_rx_data_get_info(rdata)));
1715
Benny Prijono40d62b62009-08-12 17:53:47 +00001716 status = pjmedia_sdp_neg_set_remote_answer(inv->pool_prov, inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001717 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001718
1719 if (status != PJ_SUCCESS) {
1720 char errmsg[PJ_ERR_MSG_SIZE];
1721 pj_strerror(status, errmsg, sizeof(errmsg));
1722 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1723 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001724 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001725 }
1726
1727 /* Negotiate SDP */
1728
1729 inv_negotiate_sdp(inv);
1730
Benny Prijono8fcb4332008-10-31 18:01:48 +00001731 /* Mark this transaction has having SDP offer/answer done, and
1732 * save the reference to the To tag
1733 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001734
1735 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001736 status_code = rdata->msg_info.msg->line.status.code;
1737 tsx_inv_data->done_early = (status_code/100==1);
1738 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1739 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001740
1741 } else {
1742
1743 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1744 pjsip_rx_data_get_info(rdata),
1745 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1746 }
1747
Benny Prijono26ff9062006-02-21 23:47:00 +00001748 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001749}
1750
1751
Benny Prijono26ff9062006-02-21 23:47:00 +00001752/*
1753 * Process INVITE answer, for both initial and subsequent re-INVITE
1754 */
1755static pj_status_t process_answer( pjsip_inv_session *inv,
1756 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001757 pjsip_tx_data *tdata,
1758 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001759{
1760 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001761 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001762
Benny Prijono64f851e2006-02-23 13:49:28 +00001763 /* If local_sdp is specified, then we MUST NOT have answered the
1764 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001765 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001766 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1767
1768 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001769 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1770 local_sdp,
Benny Prijono64f851e2006-02-23 13:49:28 +00001771 &inv->neg);
1772 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1773 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1774 {
Benny Prijono40d62b62009-08-12 17:53:47 +00001775 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov, inv->neg,
Benny Prijono64f851e2006-02-23 13:49:28 +00001776 local_sdp);
1777 } else {
1778
1779 /* Can not specify local SDP at this state. */
1780 pj_assert(0);
1781 status = PJMEDIA_SDPNEG_EINSTATE;
1782 }
1783
1784 if (status != PJ_SUCCESS)
1785 return status;
1786
1787 }
1788
1789
1790 /* If SDP negotiator is ready, start negotiation. */
1791 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001792
1793 pjmedia_sdp_neg_state neg_state;
1794
Benny Prijono64f851e2006-02-23 13:49:28 +00001795 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001796 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1797 PJMEDIA_SDP_NEG_STATE_NULL;
1798
1799 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1800
1801 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1802
1803 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1804 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1805 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001806 struct tsx_inv_data *tsx_inv_data;
1807
1808 /* Get invite session's transaction data */
1809 tsx_inv_data = (struct tsx_inv_data*)
1810 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001811
1812 status = inv_negotiate_sdp(inv);
1813 if (status != PJ_SUCCESS)
1814 return status;
1815
Benny Prijono77998ce2007-06-20 10:03:46 +00001816 /* Mark this transaction has having SDP offer/answer done. */
1817 tsx_inv_data->sdp_done = 1;
1818
Benny Prijono26ff9062006-02-21 23:47:00 +00001819 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1820 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001821 }
1822
Benny Prijono64f851e2006-02-23 13:49:28 +00001823 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001824 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001825 *
1826 * Note note:
1827 * - When offer/answer has been completed in reliable 183, we MUST NOT
1828 * send SDP in 2xx response. So if we don't have SDP to send, clear
1829 * the SDP in the message body ONLY if 100rel is active in this
1830 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001831 */
1832 if (sdp) {
1833 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001834 } else {
1835 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1836 tdata->msg->body = NULL;
1837 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001838 }
1839
Benny Prijono26ff9062006-02-21 23:47:00 +00001840
1841 return PJ_SUCCESS;
1842}
1843
Benny Prijonoa66c7152006-02-09 01:26:14 +00001844
1845/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001846 * Create first response to INVITE
1847 */
1848PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1849 pjsip_rx_data *rdata,
1850 int st_code,
1851 const pj_str_t *st_text,
1852 const pjmedia_sdp_session *sdp,
1853 pjsip_tx_data **p_tdata)
1854{
1855 pjsip_tx_data *tdata;
1856 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00001857 pjsip_status_code st_code2;
Benny Prijono64f851e2006-02-23 13:49:28 +00001858
1859 /* Verify arguments. */
1860 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1861
1862 /* Must have INVITE transaction. */
1863 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1864
1865 pjsip_dlg_inc_lock(inv->dlg);
1866
1867 /* Create response */
1868 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1869 &tdata);
1870 if (status != PJ_SUCCESS)
1871 goto on_return;
1872
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001873 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00001874 status = pjsip_timer_process_req(inv, rdata, &st_code2);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001875 if (status != PJ_SUCCESS) {
1876 pj_status_t status2;
1877
Nanang Izzuddin65add622009-08-11 16:26:20 +00001878 status2 = pjsip_dlg_modify_response(inv->dlg, tdata, st_code2, NULL);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001879 if (status2 != PJ_SUCCESS) {
1880 pjsip_tx_data_dec_ref(tdata);
1881 goto on_return;
1882 }
1883 status2 = pjsip_timer_update_resp(inv, tdata);
1884 if (status2 == PJ_SUCCESS)
1885 *p_tdata = tdata;
1886 else
1887 pjsip_tx_data_dec_ref(tdata);
1888
1889 goto on_return;
1890 }
1891
Benny Prijono64f851e2006-02-23 13:49:28 +00001892 /* Process SDP in answer */
1893 status = process_answer(inv, st_code, tdata, sdp);
1894 if (status != PJ_SUCCESS) {
1895 pjsip_tx_data_dec_ref(tdata);
1896 goto on_return;
1897 }
1898
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001899 /* Save this answer */
1900 inv->last_answer = tdata;
1901 pjsip_tx_data_add_ref(inv->last_answer);
1902 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1903 pjsip_tx_data_get_info(inv->last_answer)));
1904
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001905 /* Invoke Session Timers */
1906 pjsip_timer_update_resp(inv, tdata);
1907
Benny Prijono64f851e2006-02-23 13:49:28 +00001908 *p_tdata = tdata;
1909
1910on_return:
1911 pjsip_dlg_dec_lock(inv->dlg);
1912 return status;
1913}
1914
1915
1916/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001917 * Answer initial INVITE
1918 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001919 */
1920PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1921 int st_code,
1922 const pj_str_t *st_text,
1923 const pjmedia_sdp_session *local_sdp,
1924 pjsip_tx_data **p_tdata )
1925{
1926 pjsip_tx_data *last_res;
1927 pj_status_t status;
1928
1929 /* Verify arguments. */
1930 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1931
1932 /* Must have INVITE transaction. */
1933 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1934
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001935 /* Must have created an answer before */
1936 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001937
Benny Prijono64f851e2006-02-23 13:49:28 +00001938 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001939
1940 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001941 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001942 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1943 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001944 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001945
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001946 /* For non-2xx final response, strip message body */
1947 if (st_code >= 300) {
1948 last_res->msg->body = NULL;
1949 }
Benny Prijono268ca612006-02-07 12:34:11 +00001950
Benny Prijono26ff9062006-02-21 23:47:00 +00001951 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001952 status = process_answer(inv, st_code, last_res, local_sdp);
1953 if (status != PJ_SUCCESS) {
1954 pjsip_tx_data_dec_ref(last_res);
1955 goto on_return;
1956 }
Benny Prijono268ca612006-02-07 12:34:11 +00001957
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001958 /* Invoke Session Timers */
1959 pjsip_timer_update_resp(inv, last_res);
Benny Prijono268ca612006-02-07 12:34:11 +00001960
1961 *p_tdata = last_res;
1962
Benny Prijono64f851e2006-02-23 13:49:28 +00001963on_return:
1964 pjsip_dlg_dec_lock(inv->dlg);
1965 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001966}
1967
1968
1969/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001970 * Set SDP answer.
1971 */
1972PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1973 const pjmedia_sdp_session *sdp )
1974{
1975 pj_status_t status;
1976
1977 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1978
1979 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono40d62b62009-08-12 17:53:47 +00001980 status = pjmedia_sdp_neg_set_local_answer( inv->pool_prov, inv->neg, sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001981 pjsip_dlg_dec_lock(inv->dlg);
1982
1983 return status;
1984}
1985
1986
1987/*
Benny Prijono268ca612006-02-07 12:34:11 +00001988 * End session.
1989 */
1990PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
1991 int st_code,
1992 const pj_str_t *st_text,
1993 pjsip_tx_data **p_tdata )
1994{
1995 pjsip_tx_data *tdata;
1996 pj_status_t status;
1997
1998 /* Verify arguments. */
1999 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2000
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002001 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002002 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002003
Benny Prijono268ca612006-02-07 12:34:11 +00002004 /* Create appropriate message. */
2005 switch (inv->state) {
2006 case PJSIP_INV_STATE_CALLING:
2007 case PJSIP_INV_STATE_EARLY:
2008 case PJSIP_INV_STATE_INCOMING:
2009
2010 if (inv->role == PJSIP_ROLE_UAC) {
2011
2012 /* For UAC when session has not been confirmed, create CANCEL. */
2013
2014 /* MUST have the original UAC INVITE transaction. */
2015 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
2016
2017 /* But CANCEL should only be called when we have received a
2018 * provisional response. If we haven't received any responses,
2019 * just destroy the transaction.
2020 */
2021 if (inv->invite_tsx->status_code < 100) {
2022
Benny Prijono006a4e82009-04-26 11:30:22 +00002023 /* Do not stop INVITE retransmission, see ticket #506 */
2024 //pjsip_tsx_stop_retransmit(inv->invite_tsx);
Benny Prijono1dc8be02007-05-30 04:26:40 +00002025 inv->cancelling = PJ_TRUE;
2026 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00002027 *p_tdata = NULL;
Benny Prijono006a4e82009-04-26 11:30:22 +00002028 PJ_LOG(4, (inv->obj_name, "Delaying CANCEL since no "
2029 "provisional response is received yet"));
Benny Prijonofccab712006-02-22 22:23:22 +00002030 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002031 }
2032
2033 /* The CSeq here assumes that the dialog is started with an
2034 * INVITE session. This may not be correct; dialog can be
2035 * started as SUBSCRIBE session.
2036 * So fix this!
2037 */
2038 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
2039 inv->invite_tsx->last_tx,
2040 &tdata);
Benny Prijono99b04372009-04-26 11:02:04 +00002041 if (status != PJ_SUCCESS)
2042 return status;
2043
2044 /* Set timeout for the INVITE transaction, in case UAS is not
2045 * able to respond the INVITE with 487 final response. The
2046 * timeout value is 64*T1.
2047 */
2048 pjsip_tsx_set_timeout(inv->invite_tsx, 64 * pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00002049
2050 } else {
2051
2052 /* For UAS, send a final response. */
2053 tdata = inv->invite_tsx->last_tx;
2054 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
2055
Benny Prijono26ff9062006-02-21 23:47:00 +00002056 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
2057 // st_text);
2058 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002059 }
2060 break;
2061
2062 case PJSIP_INV_STATE_CONNECTING:
2063 case PJSIP_INV_STATE_CONFIRMED:
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002064 /* End Session Timer */
2065 pjsip_timer_end_session(inv);
2066
Benny Prijono268ca612006-02-07 12:34:11 +00002067 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002068 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2069 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002070 break;
2071
2072 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00002073 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002074 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00002075
2076 default:
2077 pj_assert("!Invalid operation!");
2078 return PJ_EINVALIDOP;
2079 }
2080
2081 if (status != PJ_SUCCESS)
2082 return status;
2083
2084
2085 /* Done */
2086
Benny Prijono0606e702007-05-22 12:21:40 +00002087 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00002088 *p_tdata = tdata;
2089
2090 return PJ_SUCCESS;
2091}
2092
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002093/* Following redirection recursion, get next target from the target set and
2094 * notify user.
2095 *
2096 * Returns PJ_FALSE if recursion fails (either because there's no more target
2097 * or user rejects the recursion). If we return PJ_FALSE, caller should
2098 * disconnect the session.
2099 *
2100 * Note:
2101 * the event 'e' argument may be NULL.
2102 */
2103static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
2104 const pj_str_t *reason, pjsip_event *e)
2105{
Benny Prijono08a48b82008-11-27 12:42:07 +00002106 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002107 pjsip_target *target;
2108
2109 /* Won't redirect if the callback is not implemented. */
2110 if (mod_inv.cb.on_redirected == NULL)
2111 return PJ_FALSE;
2112
2113 if (reason == NULL)
2114 reason = pjsip_get_status_text(code);
2115
2116 /* Set status of current target */
2117 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
2118 code, reason);
2119
2120 /* Fetch next target from the target set. We only want to
2121 * process SIP/SIPS URI for now.
2122 */
2123 for (;;) {
2124 target = pjsip_target_set_get_next(&inv->dlg->target_set);
2125 if (target == NULL) {
2126 /* No more target. */
2127 return PJ_FALSE;
2128 }
2129
2130 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
2131 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
2132 {
2133 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
2134 reason = pjsip_get_status_text(code);
2135
2136 /* Mark this target as unusable and fetch next target. */
2137 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
2138 } else {
2139 /* Found a target */
2140 break;
2141 }
2142 }
2143
2144 /* We have target in 'target'. Set this target as current target
2145 * and notify callback.
2146 */
2147 pjsip_target_set_set_current(&inv->dlg->target_set, target);
2148
Benny Prijono08a48b82008-11-27 12:42:07 +00002149 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002150
2151
2152 /* Check what the application wants to do now */
2153 switch (op) {
2154 case PJSIP_REDIRECT_ACCEPT:
2155 case PJSIP_REDIRECT_STOP:
2156 /* Must increment session counter, that's the convention of the
2157 * pjsip_inv_process_redirect().
2158 */
2159 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2160
2161 /* Act on the recursion */
2162 pjsip_inv_process_redirect(inv, op, e);
2163 return PJ_TRUE;
2164
2165 case PJSIP_REDIRECT_PENDING:
2166 /* Increment session so that the dialog/session is not destroyed
2167 * while we're waiting for user confirmation.
2168 */
2169 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2170
2171 /* Also clear the invite_tsx variable, otherwise when this tsx is
2172 * terminated, it will also terminate the session.
2173 */
2174 inv->invite_tsx = NULL;
2175
2176 /* Done. The processing will continue once the application calls
2177 * pjsip_inv_process_redirect().
2178 */
2179 return PJ_TRUE;
2180
2181 case PJSIP_REDIRECT_REJECT:
2182 /* Recursively call this function again to fetch next target, if any.
2183 */
2184 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2185
2186 }
2187
2188 pj_assert(!"Should not reach here");
2189 return PJ_FALSE;
2190}
2191
2192
2193/* Process redirection/recursion */
2194PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2195 pjsip_redirect_op op,
2196 pjsip_event *e)
2197{
2198 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2199 pjsip_event usr_event;
2200 pj_status_t status = PJ_SUCCESS;
2201
2202 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2203
2204 if (e == NULL) {
2205 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2206 e = &usr_event;
2207 }
2208
2209 pjsip_dlg_inc_lock(inv->dlg);
2210
2211 /* Decrement session. That's the convention here to prevent the dialog
2212 * or session from being destroyed while we're waiting for user
2213 * confirmation.
2214 */
2215 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2216
2217 /* See what the application wants to do now */
2218 switch (op) {
2219 case PJSIP_REDIRECT_ACCEPT:
2220 /* User accept the redirection. Reset the session and resend the
2221 * INVITE request.
2222 */
2223 {
2224 pjsip_tx_data *tdata;
2225 pjsip_via_hdr *via;
2226
2227 /* Get the original INVITE request. */
2228 tdata = inv->invite_req;
2229 pjsip_tx_data_add_ref(tdata);
2230
2231 /* Restore strict route set.
2232 * See http://trac.pjsip.org/repos/ticket/492
2233 */
2234 pjsip_restore_strict_route_set(tdata);
2235
2236 /* Set target */
Benny Prijono20da7992008-12-18 16:48:43 +00002237 tdata->msg->line.req.uri = (pjsip_uri*)
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002238 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2239
2240 /* Remove branch param in Via header. */
2241 via = (pjsip_via_hdr*)
2242 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2243 via->branch_param.slen = 0;
2244
2245 /* Must invalidate the message! */
2246 pjsip_tx_data_invalidate_msg(tdata);
2247
2248 /* Reset the session */
2249 pjsip_inv_uac_restart(inv, PJ_FALSE);
2250
2251 /* (re)Send the INVITE request */
2252 status = pjsip_inv_send_msg(inv, tdata);
2253 }
2254 break;
2255
2256 case PJSIP_REDIRECT_STOP:
2257 /* User doesn't want the redirection. Disconnect the session now. */
2258 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2259 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2260
2261 /* Caller should expect that the invite session is gone now, so
2262 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2263 */
2264 break;
2265
2266 case PJSIP_REDIRECT_REJECT:
2267 /* Current target is rejected. Fetch next target if any. */
2268 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2269 inv_set_cause(inv, cancel_code,
2270 pjsip_get_status_text(cancel_code));
2271 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2272
2273 /* Tell caller that the invite session is gone now */
2274 status = PJSIP_ESESSIONTERMINATED;
2275 }
2276 break;
2277
2278
2279 case PJSIP_REDIRECT_PENDING:
2280 pj_assert(!"Should not happen");
2281 break;
2282 }
2283
2284
2285 pjsip_dlg_dec_lock(inv->dlg);
2286
2287 return status;
2288}
2289
Benny Prijono268ca612006-02-07 12:34:11 +00002290
2291/*
2292 * Create re-INVITE.
2293 */
2294PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2295 const pj_str_t *new_contact,
2296 const pjmedia_sdp_session *new_offer,
2297 pjsip_tx_data **p_tdata )
2298{
Benny Prijono26ff9062006-02-21 23:47:00 +00002299 pj_status_t status;
2300 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002301
Benny Prijono26ff9062006-02-21 23:47:00 +00002302 /* Check arguments. */
2303 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2304
2305 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002306 if (inv->invite_tsx!=NULL)
2307 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002308
2309
2310 pjsip_dlg_inc_lock(inv->dlg);
2311
2312 if (new_contact) {
2313 pj_str_t tmp;
2314 const pj_str_t STR_CONTACT = { "Contact", 7 };
2315
2316 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002317 contact_hdr = (pjsip_contact_hdr*)
2318 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002319 tmp.ptr, tmp.slen, NULL);
2320 if (!contact_hdr) {
2321 status = PJSIP_EINVALIDURI;
2322 goto on_return;
2323 }
2324 }
2325
2326
2327 if (new_offer) {
2328 if (!inv->neg) {
Benny Prijono40d62b62009-08-12 17:53:47 +00002329 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
2330 new_offer,
Benny Prijono26ff9062006-02-21 23:47:00 +00002331 &inv->neg);
2332 if (status != PJ_SUCCESS)
2333 goto on_return;
2334
2335 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2336
2337 case PJMEDIA_SDP_NEG_STATE_NULL:
2338 pj_assert(!"Unexpected SDP neg state NULL");
2339 status = PJ_EBUG;
2340 goto on_return;
2341
2342 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2343 PJ_LOG(4,(inv->obj_name,
2344 "pjsip_inv_reinvite: already have an offer, new "
2345 "offer is ignored"));
2346 break;
2347
2348 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
Benny Prijono40d62b62009-08-12 17:53:47 +00002349 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov,
2350 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002351 new_offer);
2352 if (status != PJ_SUCCESS)
2353 goto on_return;
2354 break;
2355
2356 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2357 PJ_LOG(4,(inv->obj_name,
2358 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2359 "offer is ignored"));
2360 break;
2361
2362 case PJMEDIA_SDP_NEG_STATE_DONE:
Benny Prijono40d62b62009-08-12 17:53:47 +00002363 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
2364 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002365 new_offer);
2366 if (status != PJ_SUCCESS)
2367 goto on_return;
2368 break;
2369 }
2370 }
2371
2372 if (contact_hdr)
2373 inv->dlg->local.contact = contact_hdr;
2374
2375 status = pjsip_inv_invite(inv, p_tdata);
2376
2377on_return:
2378 pjsip_dlg_dec_lock(inv->dlg);
2379 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002380}
2381
2382/*
2383 * Create UPDATE.
2384 */
2385PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2386 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002387 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002388 pjsip_tx_data **p_tdata )
2389{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002390 pjsip_contact_hdr *contact_hdr = NULL;
2391 pjsip_tx_data *tdata = NULL;
2392 pjmedia_sdp_session *sdp_copy;
2393 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002394
Benny Prijono1f7767b2007-10-03 18:28:49 +00002395 /* Verify arguments. */
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002396 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002397
2398 /* Dialog must have been established */
2399 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2400 PJ_EINVALIDOP);
2401
2402 /* Invite session must not have been disconnected */
2403 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2404 PJ_EINVALIDOP);
2405
2406 /* Lock dialog. */
2407 pjsip_dlg_inc_lock(inv->dlg);
2408
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002409 /* Process offer, if any */
2410 if (offer) {
2411 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2412 PJ_LOG(4,(inv->dlg->obj_name,
2413 "Invalid SDP offer/answer state for UPDATE"));
2414 status = PJ_EINVALIDOP;
2415 goto on_error;
2416 }
2417
2418 /* Notify negotiator about the new offer. This will fix the offer
2419 * with correct SDP origin.
2420 */
2421 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg,
2422 offer);
2423 if (status != PJ_SUCCESS)
2424 goto on_error;
2425
2426 /* Retrieve the "fixed" offer from negotiator */
2427 pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002428 }
2429
Benny Prijono1f7767b2007-10-03 18:28:49 +00002430 /* Update Contact if required */
2431 if (new_contact) {
2432 pj_str_t tmp;
2433 const pj_str_t STR_CONTACT = { "Contact", 7 };
2434
2435 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2436 contact_hdr = (pjsip_contact_hdr*)
2437 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2438 tmp.ptr, tmp.slen, NULL);
2439 if (!contact_hdr) {
2440 status = PJSIP_EINVALIDURI;
2441 goto on_error;
2442 }
2443
2444 inv->dlg->local.contact = contact_hdr;
2445 }
2446
2447 /* Create request */
2448 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2449 -1, &tdata);
2450 if (status != PJ_SUCCESS)
2451 goto on_error;
2452
2453 /* Attach SDP body */
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002454 if (offer) {
2455 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2456 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2457 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00002458
2459 /* Unlock dialog. */
2460 pjsip_dlg_dec_lock(inv->dlg);
2461
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002462 status = pjsip_timer_update_req(inv, tdata);
2463 if (status != PJ_SUCCESS)
2464 goto on_error;
2465
Benny Prijono1f7767b2007-10-03 18:28:49 +00002466 *p_tdata = tdata;
2467
2468 return PJ_SUCCESS;
2469
2470on_error:
2471 if (tdata)
2472 pjsip_tx_data_dec_ref(tdata);
2473
2474 /* Unlock dialog. */
2475 pjsip_dlg_dec_lock(inv->dlg);
2476
2477 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002478}
2479
2480/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002481 * Create an ACK request.
2482 */
2483PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2484 int cseq,
2485 pjsip_tx_data **p_tdata)
2486{
2487 const pjmedia_sdp_session *sdp = NULL;
2488 pj_status_t status;
2489
2490 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2491
2492 /* Lock dialog. */
2493 pjsip_dlg_inc_lock(inv->dlg);
2494
2495 /* Destroy last_ack */
2496 if (inv->last_ack) {
2497 pjsip_tx_data_dec_ref(inv->last_ack);
2498 inv->last_ack = NULL;
2499 }
2500
2501 /* Create new ACK request */
2502 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2503 cseq, &inv->last_ack);
2504 if (status != PJ_SUCCESS) {
2505 pjsip_dlg_dec_lock(inv->dlg);
2506 return status;
2507 }
2508
2509 /* See if we have pending SDP answer to send */
2510 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2511 if (sdp) {
2512 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2513 }
2514
2515 /* Keep this for subsequent response retransmission */
2516 inv->last_ack_cseq = cseq;
2517 pjsip_tx_data_add_ref(inv->last_ack);
2518
2519 /* Done */
2520 *p_tdata = inv->last_ack;
2521
2522 /* Unlock dialog. */
2523 pjsip_dlg_dec_lock(inv->dlg);
2524
2525 return PJ_SUCCESS;
2526}
2527
2528/*
Benny Prijono268ca612006-02-07 12:34:11 +00002529 * Send a request or response message.
2530 */
2531PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002532 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002533{
2534 pj_status_t status;
2535
2536 /* Verify arguments. */
2537 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2538
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002539 PJ_LOG(5,(inv->obj_name, "Sending %s",
2540 pjsip_tx_data_get_info(tdata)));
2541
Benny Prijono268ca612006-02-07 12:34:11 +00002542 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002543 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002544
Benny Prijono64158af2006-04-04 11:06:34 +00002545 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002546
Benny Prijono22e48c92008-03-20 14:40:50 +00002547 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002548 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2549 inv->invite_tsx)
2550 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002551 pjsip_tx_data_dec_ref(tdata);
2552 pjsip_dlg_dec_lock(inv->dlg);
2553 return PJ_EINVALIDOP;
2554 }
2555
2556 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002557 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002558 tsx_inv_data->inv = inv;
2559
Benny Prijono64158af2006-04-04 11:06:34 +00002560 pjsip_dlg_dec_lock(inv->dlg);
2561
2562 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2563 tsx_inv_data);
2564 if (status != PJ_SUCCESS)
2565 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002566
2567 } else {
2568 pjsip_cseq_hdr *cseq;
2569
2570 /* Can only do this to send response to original INVITE
2571 * request.
2572 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002573 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 +00002574 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002575 PJ_EINVALIDOP);
2576
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002577 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002578 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002579 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002580 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002581 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002582 }
2583
Benny Prijono268ca612006-02-07 12:34:11 +00002584 if (status != PJ_SUCCESS)
2585 return status;
2586 }
2587
2588 /* Done (?) */
2589 return PJ_SUCCESS;
2590}
2591
2592
Benny Prijono8ad55352006-02-08 11:16:05 +00002593/*
2594 * Respond to incoming CANCEL request.
2595 */
2596static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2597 pjsip_transaction *cancel_tsx,
2598 pjsip_rx_data *rdata)
2599{
2600 pjsip_tx_data *tdata;
2601 pjsip_transaction *invite_tsx;
2602 pj_str_t key;
2603 pj_status_t status;
2604
2605 /* See if we have matching INVITE server transaction: */
2606
2607 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002608 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002609 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2610
2611 if (invite_tsx == NULL) {
2612
2613 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002614 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002615 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002616 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002617 &tdata);
2618
2619 } else {
2620 /* Always answer CANCEL will 200 (OK) regardless of
2621 * the state of the INVITE transaction.
2622 */
2623 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2624 &tdata);
2625 }
2626
2627 /* See if we have created the response successfully. */
2628 if (status != PJ_SUCCESS) return;
2629
2630 /* Send the CANCEL response */
2631 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2632 if (status != PJ_SUCCESS) return;
2633
2634
2635 /* See if we need to terminate the UAS INVITE transaction
2636 * with 487 (Request Terminated) response.
2637 */
2638 if (invite_tsx && invite_tsx->status_code < 200) {
2639
2640 pj_assert(invite_tsx->last_tx != NULL);
2641
2642 tdata = invite_tsx->last_tx;
2643
2644 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002645 if (status == PJ_SUCCESS) {
2646 /* Remove the message body */
2647 tdata->msg->body = NULL;
Benny Prijono1e08e4f2009-05-13 08:57:38 +00002648 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
2649 status = pjsip_100rel_tx_response(inv, tdata);
2650 } else {
2651 status = pjsip_dlg_send_response(inv->dlg, invite_tsx,
2652 tdata);
2653 }
Benny Prijonofc8bb142007-11-08 09:56:50 +00002654 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002655 }
2656
2657 if (invite_tsx)
2658 pj_mutex_unlock(invite_tsx->mutex);
2659}
2660
2661
2662/*
2663 * Respond to incoming BYE request.
2664 */
2665static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2666 pjsip_transaction *bye_tsx,
2667 pjsip_rx_data *rdata,
2668 pjsip_event *e )
2669{
2670 pj_status_t status;
2671 pjsip_tx_data *tdata;
2672
2673 /* Respond BYE with 200: */
2674
2675 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2676 if (status != PJ_SUCCESS) return;
2677
2678 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2679 if (status != PJ_SUCCESS) return;
2680
2681 /* Terminate session: */
2682
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002683 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002684 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002685 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002686 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002687}
2688
2689/*
Benny Prijono38998232006-02-08 22:44:25 +00002690 * Respond to BYE request.
2691 */
2692static void inv_handle_bye_response( pjsip_inv_session *inv,
2693 pjsip_transaction *tsx,
2694 pjsip_rx_data *rdata,
2695 pjsip_event *e )
2696{
2697 pj_status_t status;
2698
2699 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002700 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002701 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2702 return;
2703 }
2704
2705 /* Handle 401/407 challenge. */
2706 if (tsx->status_code == 401 || tsx->status_code == 407) {
2707
2708 pjsip_tx_data *tdata;
2709
2710 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2711 rdata,
2712 tsx->last_tx,
2713 &tdata);
2714
2715 if (status != PJ_SUCCESS) {
2716
2717 /* Does not have proper credentials.
2718 * End the session anyway.
2719 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002720 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002721 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2722
2723 } else {
2724 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002725 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002726 }
2727
2728 } else {
2729
2730 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002731 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002732 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2733 }
2734
2735}
2736
2737/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002738 * Respond to incoming UPDATE request.
2739 */
2740static void inv_respond_incoming_update(pjsip_inv_session *inv,
2741 pjsip_rx_data *rdata)
2742{
2743 pjmedia_sdp_neg_state neg_state;
2744 pj_status_t status;
2745 pjsip_tx_data *tdata = NULL;
Nanang Izzuddin65add622009-08-11 16:26:20 +00002746 pjsip_status_code st_code;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002747
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002748 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00002749 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002750 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00002751 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002752 NULL, &tdata);
2753 goto on_return;
2754 }
2755
Benny Prijono1f7767b2007-10-03 18:28:49 +00002756 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2757
2758 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2759 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2760 status = pjsip_dlg_create_response(inv->dlg, rdata,
2761 PJSIP_SC_REQUEST_PENDING, NULL,
2762 &tdata);
2763 }
2764 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2765 * receive UPDATE while we haven't sent answer.
2766 */
2767 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2768 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2769 status = pjsip_dlg_create_response(inv->dlg, rdata,
2770 PJSIP_SC_INTERNAL_SERVER_ERROR,
2771 NULL, &tdata);
2772
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002773 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2774 * This is a valid scenario according to session-timer draft.
2775 */
2776 } else if (rdata->msg_info.msg->body == NULL) {
2777
2778 status = pjsip_dlg_create_response(inv->dlg, rdata,
2779 200, NULL, &tdata);
2780
Benny Prijono1f7767b2007-10-03 18:28:49 +00002781 } else {
2782 /* We receive new offer from remote */
2783 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2784
2785 /* Application MUST have supplied the answer by now.
2786 * If so, negotiate the SDP.
2787 */
2788 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2789 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2790 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2791 {
Benny Prijonoab74c902010-06-23 12:21:20 +00002792 /* Negotiation has failed. If negotiator is still
2793 * stuck at non-DONE state, cancel any ongoing offer.
2794 */
2795 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2796 if (neg_state != PJMEDIA_SDP_NEG_STATE_DONE) {
2797 pjmedia_sdp_neg_cancel_offer(inv->neg);
2798 }
2799
Benny Prijono1f7767b2007-10-03 18:28:49 +00002800 status = pjsip_dlg_create_response(inv->dlg, rdata,
2801 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2802 NULL, &tdata);
2803 } else {
2804 /* New media has been negotiated successfully, send 200/OK */
2805 status = pjsip_dlg_create_response(inv->dlg, rdata,
2806 PJSIP_SC_OK, NULL, &tdata);
2807 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002808 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002809 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2810 if (status == PJ_SUCCESS)
2811 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2812 }
2813 }
2814 }
2815
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002816on_return:
2817 /* Invoke Session Timers */
2818 if (status == PJ_SUCCESS)
2819 status = pjsip_timer_update_resp(inv, tdata);
2820
Benny Prijono1f7767b2007-10-03 18:28:49 +00002821 if (status != PJ_SUCCESS) {
2822 if (tdata != NULL) {
2823 pjsip_tx_data_dec_ref(tdata);
2824 tdata = NULL;
2825 }
2826 return;
2827 }
2828
2829 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2830}
2831
2832
2833/*
2834 * Handle incoming response to UAC UPDATE request.
2835 */
2836static void inv_handle_update_response( pjsip_inv_session *inv,
2837 pjsip_event *e)
2838{
2839 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2840 struct tsx_inv_data *tsx_inv_data = NULL;
2841 pj_status_t status = -1;
2842
Benny Prijono48ab2b72007-11-08 09:24:30 +00002843 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002844 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002845 (tsx->status_code == 401 || tsx->status_code == 407))
2846 {
Benny Prijono48ab2b72007-11-08 09:24:30 +00002847 pjsip_tx_data *tdata;
2848
2849 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2850 e->body.tsx_state.src.rdata,
2851 tsx->last_tx,
2852 &tdata);
2853
2854 if (status != PJ_SUCCESS) {
2855
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002856 /* Somehow failed. Probably it's not a good idea to terminate
2857 * the session since this is just a request within dialog. And
2858 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002859 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002860 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002861 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2862 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002863 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002864
2865 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002866 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002867 status = pjsip_inv_send_msg(inv, tdata);
2868 }
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002869 }
2870
2871 /* Process 422 response */
2872 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2873 tsx->status_code == 422)
2874 {
2875 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2876 PJ_FALSE);
2877 }
Benny Prijono48ab2b72007-11-08 09:24:30 +00002878
2879 /* Process 2xx response */
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002880 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002881 tsx->status_code/100 == 2 &&
2882 e->body.tsx_state.src.rdata->msg_info.msg->body)
2883 {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002884 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2885 PJ_FALSE);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002886 status = inv_check_sdp_in_incoming_msg(inv, tsx,
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002887 e->body.tsx_state.src.rdata);
2888 }
2889
2890 /* Get/attach invite session's transaction data */
2891 else
2892 {
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002893 /* Session-Timer needs to see any error responses, to determine
2894 * whether peer supports UPDATE with empty body.
2895 */
2896 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2897 tsx->role == PJSIP_ROLE_UAC)
2898 {
2899 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2900 PJ_FALSE);
2901 }
2902
Benny Prijono1f7767b2007-10-03 18:28:49 +00002903 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2904 if (tsx_inv_data == NULL) {
2905 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2906 tsx_inv_data->inv = inv;
2907 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2908 }
2909 }
2910
Benny Prijonoab74c902010-06-23 12:21:20 +00002911 /* Cancel the negotiation if we don't get successful negotiation by now */
2912 if (pjmedia_sdp_neg_get_state(inv->neg) ==
2913 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002914 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2915 {
2916 pjmedia_sdp_neg_cancel_offer(inv->neg);
2917
2918 /* Prevent from us cancelling different offer! */
2919 tsx_inv_data->sdp_done = PJ_TRUE;
2920 }
2921}
2922
2923
2924/*
2925 * Handle incoming reliable response.
2926 */
2927static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2928 pjsip_rx_data *rdata)
2929{
2930 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002931 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002932 pj_status_t status;
2933
2934 /* Create PRACK */
2935 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2936 if (status != PJ_SUCCESS)
2937 return;
2938
2939 /* See if we need to attach SDP answer on the PRACK request */
2940 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2941 if (sdp) {
2942 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2943 }
2944
2945 /* Send PRACK (must be using 100rel module!) */
2946 pjsip_100rel_send_prack(inv, tdata);
2947}
2948
2949
2950/*
2951 * Handle incoming PRACK.
2952 */
2953static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2954 pjsip_rx_data *rdata)
2955{
2956 pj_status_t status;
2957
2958 /* Run through 100rel module to see if we can accept this
2959 * PRACK request. The 100rel will send 200/OK to PRACK request.
2960 */
2961 status = pjsip_100rel_on_rx_prack(inv, rdata);
2962 if (status != PJ_SUCCESS)
2963 return;
2964
2965 /* Now check for SDP answer in the PRACK request */
2966 if (rdata->msg_info.msg->body) {
2967 status = inv_check_sdp_in_incoming_msg(inv,
2968 pjsip_rdata_get_tsx(rdata), rdata);
2969 } else {
2970 /* No SDP body */
2971 status = -1;
2972 }
2973
2974 /* If SDP negotiation has been successful, also mark the
2975 * SDP negotiation flag in the invite transaction to be
2976 * done too.
2977 */
2978 if (status == PJ_SUCCESS && inv->invite_tsx) {
2979 struct tsx_inv_data *tsx_inv_data;
2980
2981 /* Get/attach invite session's transaction data */
2982 tsx_inv_data = (struct tsx_inv_data*)
2983 inv->invite_tsx->mod_data[mod_inv.mod.id];
2984 if (tsx_inv_data == NULL) {
2985 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2986 struct tsx_inv_data);
2987 tsx_inv_data->inv = inv;
2988 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2989 }
2990
2991 tsx_inv_data->sdp_done = PJ_TRUE;
2992 }
2993}
2994
2995
2996/*
Benny Prijono8ad55352006-02-08 11:16:05 +00002997 * State NULL is before anything is sent/received.
2998 */
2999static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003000{
3001 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3002 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3003
3004 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3005
3006 if (tsx->method.id == PJSIP_INVITE_METHOD) {
3007
Benny Prijono64f851e2006-02-23 13:49:28 +00003008 /* Keep the initial INVITE transaction. */
3009 if (inv->invite_tsx == NULL)
3010 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00003011
Benny Prijono64f851e2006-02-23 13:49:28 +00003012 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00003013
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003014 /* Save the original INVITE request, if on_redirected() callback
3015 * is implemented. We may need to resend the INVITE if we receive
3016 * redirection response.
3017 */
3018 if (mod_inv.cb.on_redirected) {
3019 if (inv->invite_req) {
3020 pjsip_tx_data_dec_ref(inv->invite_req);
3021 inv->invite_req = NULL;
3022 }
3023 inv->invite_req = tsx->last_tx;
3024 pjsip_tx_data_add_ref(inv->invite_req);
3025 }
3026
Benny Prijono268ca612006-02-07 12:34:11 +00003027 switch (tsx->state) {
3028 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003029 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003030 break;
3031 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00003032 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003033 break;
3034 }
3035
3036 } else {
3037 switch (tsx->state) {
3038 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003039 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003040 break;
Benny Prijono38998232006-02-08 22:44:25 +00003041 case PJSIP_TSX_STATE_PROCEEDING:
3042 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3043 if (tsx->status_code > 100)
3044 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
3045 break;
Benny Prijono2285e7e2008-12-17 14:28:18 +00003046 case PJSIP_TSX_STATE_TERMINATED:
3047 /* there is a failure in sending response. */
3048 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3049 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3050 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003051 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00003052 inv_on_state_incoming(inv, e);
3053 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003054 }
3055 }
3056
3057 } else {
3058 pj_assert(!"Unexpected transaction type");
3059 }
3060}
3061
Benny Prijono8ad55352006-02-08 11:16:05 +00003062/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003063 * Generic UAC transaction handler:
3064 * - resend request on 401 or 407 response.
3065 * - terminate dialog on 408 and 481 response.
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003066 * - resend request on 422 response.
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003067 */
3068static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
3069 pjsip_event *e)
3070{
3071 /* RFC 3261 Section 12.2.1.2:
3072 * If the response for a request within a dialog is a 481
3073 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
3074 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
3075 * no response at all is received for the request (the client
3076 * transaction would inform the TU about the timeout.)
3077 *
3078 * For INVITE initiated dialogs, terminating the dialog consists of
3079 * sending a BYE.
3080 *
3081 * Note:
3082 * according to X, this should terminate dialog usage only, not the
3083 * dialog.
3084 */
3085 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3086
3087 pj_assert(tsx->role == PJSIP_UAC_ROLE);
3088
3089 /* Note that 481 response to CANCEL does not terminate dialog usage,
3090 * but only the transaction.
3091 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00003092 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
3093 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003094 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00003095 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3096 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
3097 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003098 {
3099 pjsip_tx_data *bye;
3100 pj_status_t status;
3101
3102 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3103 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3104
3105 /* Send BYE */
3106 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
3107 -1, &bye);
3108 if (status == PJ_SUCCESS) {
3109 pjsip_inv_send_msg(inv, bye);
3110 }
3111
3112 return PJ_TRUE; /* Handled */
3113
3114 }
3115 /* Handle 401/407 challenge. */
3116 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3117 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
3118 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
3119 {
3120
3121 pjsip_tx_data *tdata;
3122 pj_status_t status;
3123
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003124 if (tsx->method.id == PJSIP_INVITE_METHOD)
3125 inv->invite_tsx = NULL;
3126
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003127 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
3128 e->body.tsx_state.src.rdata,
3129 tsx->last_tx, &tdata);
3130
3131 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003132 /* Somehow failed. Probably it's not a good idea to terminate
3133 * the session since this is just a request within dialog. And
3134 * even if we terminate we should send BYE.
3135 */
3136 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003137 inv_set_cause(inv, PJSIP_SC_OK, NULL);
3138 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003139 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003140
3141 } else {
3142 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003143 status = pjsip_inv_send_msg(inv, tdata);
3144 }
3145
3146 return PJ_TRUE; /* Handled */
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003147 }
3148
3149 /* Handle session timer 422 response. */
3150 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3151 tsx->status_code == PJSIP_SC_SESSION_TIMER_TOO_SMALL)
3152 {
3153 handle_timer_response(inv, e->body.tsx_state.src.rdata,
3154 PJ_FALSE);
3155
3156 return PJ_TRUE; /* Handled */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003157
3158 } else {
3159 return PJ_FALSE; /* Unhandled */
3160 }
3161}
3162
3163
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003164/* Handle call rejection, especially with regard to processing call
3165 * redirection. We need to handle the following scenarios:
3166 * - 3xx response is received -- see if on_redirected() callback is
3167 * implemented. If so, add the Contact URIs in the response to the
3168 * target set and notify user.
3169 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
3170 * if so fetch the next target if any and notify the on_redirected()
3171 * callback.
3172 * - for other cases -- disconnect the session.
3173 */
3174static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
3175{
3176 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3177 pj_status_t status;
3178
3179 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
3180
3181 if (mod_inv.cb.on_redirected == NULL) {
3182
3183 /* Redirection callback is not implemented, disconnect the
3184 * call.
3185 */
3186 goto terminate_session;
3187
3188 } else {
3189 const pjsip_msg *res_msg;
3190
3191 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
3192
3193 /* Gather all Contact URI's in the response and add them
3194 * to target set. The function will take care of removing
3195 * duplicate URI's.
3196 */
3197 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
3198 inv->dlg->pool, res_msg);
3199
3200 /* Recurse to alternate targets if application allows us */
3201 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3202 {
3203 /* Recursion fails, terminate session now */
3204 goto terminate_session;
3205 }
3206
3207 /* Done */
3208 }
3209
3210 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
3211 !inv->cancelling)
3212 {
3213
3214 /* Handle authentication failure:
3215 * Resend the request with Authorization header.
3216 */
3217 pjsip_tx_data *tdata;
3218
3219 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
3220 e->body.tsx_state.src.rdata,
3221 tsx->last_tx,
3222 &tdata);
3223
3224 if (status != PJ_SUCCESS) {
3225
3226 /* Does not have proper credentials. If we are currently
3227 * recursing, try the next target. Otherwise end the session.
3228 */
3229 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3230 {
3231 /* Recursion fails, terminate session now */
3232 goto terminate_session;
3233 }
3234
3235 } else {
3236
3237 /* Restart session. */
3238 pjsip_inv_uac_restart(inv, PJ_FALSE);
3239
3240 /* Send the request. */
3241 status = pjsip_inv_send_msg(inv, tdata);
3242 }
3243
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003244 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3245 tsx->status_code == PJSIP_SC_SESSION_TIMER_TOO_SMALL)
3246 {
3247 /* Handle session timer 422 response:
3248 * Resend the request with requested session timer setting.
3249 */
3250 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
3251 PJ_TRUE);
3252
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003253 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3254 /* Global error */
3255 goto terminate_session;
3256
3257 } else {
3258 /* See if we have alternate target to try */
3259 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3260 /* Recursion fails, terminate session now */
3261 goto terminate_session;
3262 }
3263 }
3264 return;
3265
3266terminate_session:
3267 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3268 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3269}
3270
3271
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003272/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003273 * State CALLING is after sending initial INVITE request but before
3274 * any response (with tag) is received.
3275 */
3276static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003277{
3278 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3279 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003280 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003281
3282 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3283
Benny Prijono8ad55352006-02-08 11:16:05 +00003284 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003285
3286 switch (tsx->state) {
3287
Benny Prijono64f851e2006-02-23 13:49:28 +00003288 case PJSIP_TSX_STATE_CALLING:
3289 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3290 break;
3291
Benny Prijono268ca612006-02-07 12:34:11 +00003292 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003293 if (inv->pending_cancel) {
3294 pjsip_tx_data *cancel;
3295
3296 inv->pending_cancel = PJ_FALSE;
3297
3298 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3299 if (status == PJ_SUCCESS && cancel)
3300 status = pjsip_inv_send_msg(inv, cancel);
3301 }
3302
Benny Prijono268ca612006-02-07 12:34:11 +00003303 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003304
Benny Prijono8ad55352006-02-08 11:16:05 +00003305 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003306
3307 inv_check_sdp_in_incoming_msg(inv, tsx,
3308 e->body.tsx_state.src.rdata);
3309
Benny Prijono1f7767b2007-10-03 18:28:49 +00003310 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3311 inv_handle_incoming_reliable_response(
3312 inv, e->body.tsx_state.src.rdata);
3313 }
3314
Benny Prijono268ca612006-02-07 12:34:11 +00003315 } else {
3316 /* Ignore 100 (Trying) response, as it doesn't change
3317 * session state. It only ceases retransmissions.
3318 */
3319 }
3320 break;
3321
3322 case PJSIP_TSX_STATE_COMPLETED:
3323 if (tsx->status_code/100 == 2) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003324
Benny Prijono268ca612006-02-07 12:34:11 +00003325 /* This should not happen.
3326 * When transaction receives 2xx, it should be terminated
3327 */
3328 pj_assert(0);
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003329
3330 /* Process session timer response. */
3331 status = handle_timer_response(inv,
3332 e->body.tsx_state.src.rdata,
3333 PJ_TRUE);
3334 if (status != PJ_SUCCESS)
3335 break;
3336
Benny Prijono8ad55352006-02-08 11:16:05 +00003337 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003338
3339 inv_check_sdp_in_incoming_msg(inv, tsx,
3340 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003341
3342 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003343 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003344 }
3345 break;
3346
3347 case PJSIP_TSX_STATE_TERMINATED:
3348 /* INVITE transaction can be terminated either because UAC
3349 * transaction received 2xx response or because of transport
3350 * error.
3351 */
3352 if (tsx->status_code/100 == 2) {
3353 /* This must be receipt of 2xx response */
3354
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003355 /* Process session timer response. */
3356 status = handle_timer_response(inv,
3357 e->body.tsx_state.src.rdata,
3358 PJ_TRUE);
3359 if (status != PJ_SUCCESS)
3360 break;
3361
Benny Prijono268ca612006-02-07 12:34:11 +00003362 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003363 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003364
Benny Prijonoa66c7152006-02-09 01:26:14 +00003365 inv_check_sdp_in_incoming_msg(inv, tsx,
3366 e->body.tsx_state.src.rdata);
3367
Benny Prijono268ca612006-02-07 12:34:11 +00003368 /* Send ACK */
3369 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3370
Benny Prijonod5f9f422007-11-25 04:40:07 +00003371 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003372
Benny Prijono268ca612006-02-07 12:34:11 +00003373 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003374 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003375 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003376 }
3377 break;
3378
Benny Prijono34a404e2006-02-09 14:38:30 +00003379 default:
3380 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003381 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003382
Benny Prijono1f7767b2007-10-03 18:28:49 +00003383 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003384 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003385 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003386 * Transaction Does Not Exist), 408, or when it's timed out. In these
3387 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003388 * Note that 481 response to CANCEL does not terminate dialog usage,
3389 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003390 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003391 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3392 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003393 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3394 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003395 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003396 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003397 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003398 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3399 }
Benny Prijono268ca612006-02-07 12:34:11 +00003400 }
3401}
3402
Benny Prijono8ad55352006-02-08 11:16:05 +00003403/*
3404 * State INCOMING is after we received the request, but before
3405 * responses with tag are sent.
3406 */
3407static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003408{
3409 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3410 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3411
3412 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3413
Benny Prijono8ad55352006-02-08 11:16:05 +00003414 if (tsx == inv->invite_tsx) {
3415
3416 /*
3417 * Handle the INVITE state transition.
3418 */
3419
Benny Prijono268ca612006-02-07 12:34:11 +00003420 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003421
Benny Prijono64f851e2006-02-23 13:49:28 +00003422 case PJSIP_TSX_STATE_TRYING:
3423 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3424 break;
3425
Benny Prijono268ca612006-02-07 12:34:11 +00003426 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003427 /*
3428 * Transaction sent provisional response.
3429 */
Benny Prijono268ca612006-02-07 12:34:11 +00003430 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003431 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003432 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003433
Benny Prijono268ca612006-02-07 12:34:11 +00003434 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003435 /*
3436 * Transaction sent final response.
3437 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003438 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003439 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003440 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003441 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003442 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003443 }
Benny Prijono268ca612006-02-07 12:34:11 +00003444 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003445
Benny Prijono268ca612006-02-07 12:34:11 +00003446 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003447 /*
3448 * This happens on transport error (e.g. failed to send
3449 * response)
3450 */
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 Prijono268ca612006-02-07 12:34:11 +00003453 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003454
Benny Prijono268ca612006-02-07 12:34:11 +00003455 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003456 pj_assert(!"Unexpected INVITE state");
3457 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003458 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003459
3460 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3461 tsx->role == PJSIP_ROLE_UAS &&
3462 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3463 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3464 {
3465
3466 /*
3467 * Handle incoming CANCEL request.
3468 */
3469
3470 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3471
Benny Prijono268ca612006-02-07 12:34:11 +00003472 }
3473}
3474
Benny Prijono8ad55352006-02-08 11:16:05 +00003475/*
3476 * State EARLY is for both UAS and UAC, after response with To tag
3477 * is sent/received.
3478 */
3479static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003480{
3481 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3482 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3483
3484 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3485
Benny Prijono8ad55352006-02-08 11:16:05 +00003486 if (tsx == inv->invite_tsx) {
3487
3488 /*
3489 * Handle the INVITE state progress.
3490 */
Benny Prijono268ca612006-02-07 12:34:11 +00003491
3492 switch (tsx->state) {
3493
3494 case PJSIP_TSX_STATE_PROCEEDING:
3495 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003496 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003497
3498 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3499 inv_check_sdp_in_incoming_msg(inv, tsx,
3500 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003501
3502 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3503 inv_handle_incoming_reliable_response(
3504 inv, e->body.tsx_state.src.rdata);
3505 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003506 }
Benny Prijono268ca612006-02-07 12:34:11 +00003507 break;
3508
3509 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003510 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003511 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003512 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003513 pj_status_t status;
3514
3515 /* Process session timer response. */
3516 status = handle_timer_response(inv,
3517 e->body.tsx_state.src.rdata,
3518 PJ_TRUE);
3519 if (status != PJ_SUCCESS)
3520 break;
3521
Benny Prijonoa66c7152006-02-09 01:26:14 +00003522 inv_check_sdp_in_incoming_msg(inv, tsx,
3523 e->body.tsx_state.src.rdata);
3524 }
3525
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003526 } else if (tsx->role == PJSIP_ROLE_UAC) {
3527
3528 handle_uac_call_rejection(inv, e);
3529
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003530 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003531 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003532 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003533 }
Benny Prijono268ca612006-02-07 12:34:11 +00003534 break;
3535
Benny Prijonof3195072006-02-14 21:15:30 +00003536 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003537 /* For some reason can go here (maybe when ACK for 2xx has
3538 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003539
Benny Prijono268ca612006-02-07 12:34:11 +00003540 case PJSIP_TSX_STATE_TERMINATED:
3541 /* INVITE transaction can be terminated either because UAC
3542 * transaction received 2xx response or because of transport
3543 * error.
3544 */
3545 if (tsx->status_code/100 == 2) {
3546
3547 /* This must be receipt of 2xx response */
3548
3549 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003550 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003551
Benny Prijonoa66c7152006-02-09 01:26:14 +00003552 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003553 pj_status_t status;
3554
3555 /* Process session timer response. */
3556 status = handle_timer_response(inv,
3557 e->body.tsx_state.src.rdata,
3558 PJ_TRUE);
3559 if (status != PJ_SUCCESS)
3560 break;
3561
Benny Prijonoa66c7152006-02-09 01:26:14 +00003562 inv_check_sdp_in_incoming_msg(inv, tsx,
3563 e->body.tsx_state.src.rdata);
3564 }
3565
Benny Prijono268ca612006-02-07 12:34:11 +00003566 /* if UAC, send ACK and move state to confirmed. */
3567 if (tsx->role == PJSIP_ROLE_UAC) {
3568 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3569
Benny Prijonod5f9f422007-11-25 04:40:07 +00003570 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003571 }
3572
3573 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003574 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003575 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003576 }
3577 break;
3578
3579 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003580 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003581 }
3582
Benny Prijono8ad55352006-02-08 11:16:05 +00003583 } else if (inv->role == PJSIP_ROLE_UAS &&
3584 tsx->role == PJSIP_ROLE_UAS &&
3585 tsx->method.id == PJSIP_CANCEL_METHOD &&
3586 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3587 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3588 {
Benny Prijono268ca612006-02-07 12:34:11 +00003589
Benny Prijono8ad55352006-02-08 11:16:05 +00003590 /*
3591 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003592 */
3593
Benny Prijono8ad55352006-02-08 11:16:05 +00003594 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3595
Benny Prijono1f7767b2007-10-03 18:28:49 +00003596 } else if (tsx->role == PJSIP_ROLE_UAS &&
3597 tsx->state == PJSIP_TSX_STATE_TRYING &&
3598 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003599 {
3600 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003601 * Handle incoming UPDATE
3602 */
3603 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3604
3605
3606 } else if (tsx->role == PJSIP_ROLE_UAC &&
3607 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3608 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3609 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3610 {
3611 /*
3612 * Handle response to outgoing UPDATE request.
3613 */
3614 inv_handle_update_response(inv, e);
3615
3616 } else if (tsx->role == PJSIP_ROLE_UAS &&
3617 tsx->state == PJSIP_TSX_STATE_TRYING &&
3618 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3619 {
3620 /*
3621 * Handle incoming PRACK
3622 */
3623 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3624
3625 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003626
3627 /* Generic handling for UAC tsx completion */
3628 handle_uac_tsx_response(inv, e);
Benny Prijono7efa2d62009-04-27 12:50:16 +00003629
3630 } else if (tsx->role == PJSIP_ROLE_UAS &&
3631 tsx->method.id == PJSIP_BYE_METHOD &&
3632 tsx->status_code < 200 &&
3633 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3634 {
3635 /* Received BYE before the 2xx/OK response to INVITE.
3636 * Assume that the 2xx/OK response is lost and the BYE
3637 * arrives earlier.
3638 */
3639 inv_respond_incoming_bye(inv, tsx, e->body.tsx_state.src.rdata, e);
3640
3641 /* Set timer just in case we will never get the final response
3642 * for INVITE.
3643 */
3644 pjsip_tsx_set_timeout(inv->invite_tsx, 64*pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00003645 }
3646}
3647
Benny Prijono8ad55352006-02-08 11:16:05 +00003648/*
3649 * State CONNECTING is after 2xx response to INVITE is sent/received.
3650 */
3651static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003652{
3653 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3654 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3655
3656 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3657
Benny Prijono8ad55352006-02-08 11:16:05 +00003658 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003659
Benny Prijono8ad55352006-02-08 11:16:05 +00003660 /*
3661 * Handle INVITE state progression.
3662 */
Benny Prijono268ca612006-02-07 12:34:11 +00003663 switch (tsx->state) {
3664
3665 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003666 /* It can only go here if incoming ACK request has the same Via
3667 * branch parameter as the INVITE transaction.
3668 */
3669 if (tsx->status_code/100 == 2) {
3670 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3671 inv_check_sdp_in_incoming_msg(inv, tsx,
3672 e->body.tsx_state.src.rdata);
3673 }
3674
Benny Prijono38998232006-02-08 22:44:25 +00003675 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003676 }
Benny Prijono268ca612006-02-07 12:34:11 +00003677 break;
3678
3679 case PJSIP_TSX_STATE_TERMINATED:
3680 /* INVITE transaction can be terminated either because UAC
3681 * transaction received 2xx response or because of transport
3682 * error.
3683 */
3684 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003685 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003686 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003687 }
3688 break;
3689
3690 case PJSIP_TSX_STATE_DESTROYED:
3691 /* Do nothing. */
3692 break;
3693
3694 default:
3695 pj_assert(!"Unexpected state");
3696 }
3697
Benny Prijono8ad55352006-02-08 11:16:05 +00003698 } else if (tsx->role == PJSIP_ROLE_UAS &&
3699 tsx->method.id == PJSIP_BYE_METHOD &&
3700 tsx->status_code < 200 &&
3701 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3702 {
3703
3704 /*
3705 * Handle incoming BYE.
3706 */
3707
3708 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3709
Benny Prijono38998232006-02-08 22:44:25 +00003710 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3711 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003712 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3713 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003714 {
3715
3716 /*
3717 * Outgoing BYE
3718 */
3719 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3720
Benny Prijono268ca612006-02-07 12:34:11 +00003721 }
Benny Prijono70127222006-07-02 14:53:05 +00003722 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3723 tsx->role == PJSIP_ROLE_UAS &&
3724 tsx->status_code < 200 &&
3725 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3726 {
Benny Prijono38998232006-02-08 22:44:25 +00003727
Benny Prijono70127222006-07-02 14:53:05 +00003728 /*
3729 * Handle strandled incoming CANCEL.
3730 */
3731 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3732 pjsip_tx_data *tdata;
3733 pj_status_t status;
3734
3735 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3736 if (status != PJ_SUCCESS) return;
3737
3738 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3739 if (status != PJ_SUCCESS) return;
3740
Benny Prijono1f7767b2007-10-03 18:28:49 +00003741 } else if (tsx->role == PJSIP_ROLE_UAS &&
3742 tsx->state == PJSIP_TSX_STATE_TRYING &&
3743 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3744 {
3745 /*
3746 * Handle incoming UPDATE
3747 */
3748 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3749
3750
3751 } else if (tsx->role == PJSIP_ROLE_UAC &&
3752 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3753 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3754 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3755 {
3756 /*
3757 * Handle response to outgoing UPDATE request.
3758 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003759 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003760 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003761
3762 } else if (tsx->role == PJSIP_ROLE_UAS &&
3763 tsx->state == PJSIP_TSX_STATE_TRYING &&
3764 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3765 {
3766 /*
3767 * Handle incoming PRACK
3768 */
3769 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3770
3771 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono87402382008-02-21 19:28:21 +00003772
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003773 /* Generic handling for UAC tsx completion */
3774 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003775 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003776
Benny Prijono268ca612006-02-07 12:34:11 +00003777}
3778
Benny Prijono8ad55352006-02-08 11:16:05 +00003779/*
3780 * State CONFIRMED is after ACK is sent/received.
3781 */
3782static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003783{
3784 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3785 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3786
3787 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3788
Benny Prijono268ca612006-02-07 12:34:11 +00003789
Benny Prijono8ad55352006-02-08 11:16:05 +00003790 if (tsx->method.id == PJSIP_BYE_METHOD &&
3791 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003792 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3793 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003794 {
Benny Prijono38998232006-02-08 22:44:25 +00003795
Benny Prijono8ad55352006-02-08 11:16:05 +00003796 /*
Benny Prijono38998232006-02-08 22:44:25 +00003797 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003798 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003799
Benny Prijonoa66c7152006-02-09 01:26:14 +00003800 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003801
Benny Prijono8ad55352006-02-08 11:16:05 +00003802 }
3803 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3804 tsx->role == PJSIP_ROLE_UAS &&
3805 tsx->status_code < 200 &&
3806 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3807 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003808
Benny Prijono8ad55352006-02-08 11:16:05 +00003809 /*
3810 * Handle incoming BYE.
3811 */
Benny Prijono268ca612006-02-07 12:34:11 +00003812
Benny Prijono8ad55352006-02-08 11:16:05 +00003813 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3814
Benny Prijono268ca612006-02-07 12:34:11 +00003815 }
Benny Prijono70127222006-07-02 14:53:05 +00003816 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3817 tsx->role == PJSIP_ROLE_UAS &&
3818 tsx->status_code < 200 &&
3819 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3820 {
3821
3822 /*
3823 * Handle strandled incoming CANCEL.
3824 */
3825 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3826 pjsip_tx_data *tdata;
3827 pj_status_t status;
3828
3829 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3830 if (status != PJ_SUCCESS) return;
3831
3832 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3833 if (status != PJ_SUCCESS) return;
3834
3835 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003836 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3837 tsx->role == PJSIP_ROLE_UAS)
3838 {
3839
3840 /*
3841 * Handle incoming re-INVITE
3842 */
3843 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3844
3845 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3846 pjsip_tx_data *tdata;
3847 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00003848 pjsip_status_code st_code;
Benny Prijono26ff9062006-02-21 23:47:00 +00003849
3850 /* Check if we have INVITE pending. */
3851 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003852 pj_str_t reason;
3853
3854 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003855
3856 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003857 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3858 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003859 if (status != PJ_SUCCESS)
3860 return;
3861
3862 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3863
3864
3865 return;
3866 }
3867
3868 /* Save the invite transaction. */
3869 inv->invite_tsx = tsx;
3870
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003871 /* Process session timers headers in the re-INVITE */
Nanang Izzuddin65add622009-08-11 16:26:20 +00003872 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003873 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00003874 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
3875 NULL, &tdata);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003876 if (status != PJ_SUCCESS)
3877 return;
3878
3879 pjsip_timer_update_resp(inv, tdata);
3880 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3881 return;
3882 }
3883
Benny Prijono26ff9062006-02-21 23:47:00 +00003884 /* Process SDP in incoming message. */
3885 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3886
3887 if (status != PJ_SUCCESS) {
3888
3889 /* Not Acceptable */
3890 const pjsip_hdr *accept;
3891
3892 status = pjsip_dlg_create_response(inv->dlg, rdata,
3893 488, NULL, &tdata);
3894 if (status != PJ_SUCCESS)
3895 return;
3896
3897
3898 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3899 NULL);
3900 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003901 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003902 pjsip_hdr_clone(tdata->pool, accept));
3903 }
3904
3905 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3906
3907 return;
3908 }
3909
3910 /* Create 2xx ANSWER */
3911 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3912 if (status != PJ_SUCCESS)
3913 return;
3914
Benny Prijono7d910092007-06-20 04:19:46 +00003915 /* If the INVITE request has SDP body, send answer.
3916 * Otherwise generate offer from local active SDP.
3917 */
3918 if (rdata->msg_info.msg->body != NULL) {
3919 status = process_answer(inv, 200, tdata, NULL);
3920 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003921 /* INVITE does not have SDP.
3922 * If on_create_offer() callback is implemented, ask app.
3923 * to generate an offer, otherwise just send active local
3924 * SDP to signal that nothing gets modified.
3925 */
3926 pjmedia_sdp_session *sdp = NULL;
3927
3928 if (mod_inv.cb.on_create_offer) {
3929 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3930 if (sdp) {
Benny Prijono60e31fc2009-04-23 11:50:25 +00003931 /* Notify negotiator about the new offer. This will
3932 * fix the offer with correct SDP origin.
3933 */
Benny Prijono40d62b62009-08-12 17:53:47 +00003934 status =
3935 pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
3936 inv->neg,
3937 sdp);
Benny Prijono60e31fc2009-04-23 11:50:25 +00003938
3939 /* Retrieve the "fixed" offer from negotiator */
Benny Prijonoc8fe3df2009-04-29 20:56:57 +00003940 if (status==PJ_SUCCESS) {
3941 const pjmedia_sdp_session *lsdp = NULL;
3942 pjmedia_sdp_neg_get_neg_local(inv->neg, &lsdp);
3943 sdp = (pjmedia_sdp_session*)lsdp;
3944 }
Benny Prijono77998ce2007-06-20 10:03:46 +00003945 }
3946 }
3947
3948 if (sdp == NULL) {
3949 const pjmedia_sdp_session *active_sdp = NULL;
Benny Prijono40d62b62009-08-12 17:53:47 +00003950 status = pjmedia_sdp_neg_send_local_offer(inv->pool_prov,
Benny Prijono77998ce2007-06-20 10:03:46 +00003951 inv->neg,
3952 &active_sdp);
3953 if (status == PJ_SUCCESS)
3954 sdp = (pjmedia_sdp_session*) active_sdp;
3955 }
3956
3957 if (sdp) {
3958 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003959 }
3960 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003961
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003962 if (status != PJ_SUCCESS) {
3963 /*
3964 * SDP negotiation has failed.
3965 */
3966 pj_status_t rc;
3967 pj_str_t reason;
3968
3969 /* Delete the 2xx answer */
3970 pjsip_tx_data_dec_ref(tdata);
3971
3972 /* Create 500 response */
3973 reason = pj_str("SDP negotiation failed");
3974 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3975 &tdata);
3976 if (rc == PJ_SUCCESS) {
3977 pjsip_warning_hdr *w;
3978 const pj_str_t *endpt_name;
3979
3980 endpt_name = pjsip_endpt_name(dlg->endpt);
3981 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3982 endpt_name,
3983 status);
3984 if (w)
3985 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3986
3987 pjsip_inv_send_msg(inv, tdata);
3988 }
3989 return;
3990 }
3991
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003992 /* Invoke Session Timers */
3993 pjsip_timer_update_resp(inv, tdata);
3994
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003995 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003996 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003997
Benny Prijono7d910092007-06-20 04:19:46 +00003998 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
3999 /* This is the case where ACK has the same branch as
4000 * the INVITE request.
4001 */
4002 if (tsx->status_code/100 == 2 &&
4003 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
4004 {
4005 inv_check_sdp_in_incoming_msg(inv, tsx,
4006 e->body.tsx_state.src.rdata);
Nanang Izzuddin0fd92672010-06-16 15:26:18 +00004007
4008 /* Check if local offer got no SDP answer */
4009 if (pjmedia_sdp_neg_get_state(inv->neg)==
4010 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
4011 {
4012 pjmedia_sdp_neg_cancel_offer(inv->neg);
4013 }
Benny Prijono7d910092007-06-20 04:19:46 +00004014 }
4015
Benny Prijono26ff9062006-02-21 23:47:00 +00004016 }
4017
4018 }
4019 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
4020 tsx->role == PJSIP_ROLE_UAC)
4021 {
Benny Prijono22e48c92008-03-20 14:40:50 +00004022
Benny Prijono26ff9062006-02-21 23:47:00 +00004023 /*
4024 * Handle outgoing re-INVITE
4025 */
Benny Prijono22e48c92008-03-20 14:40:50 +00004026 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
4027
Benny Prijono61fc5e62008-06-25 18:35:31 +00004028 /* Must not have other pending INVITE transaction */
4029 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
4030
Benny Prijono22e48c92008-03-20 14:40:50 +00004031 /* Save pending invite transaction */
4032 inv->invite_tsx = tsx;
4033
4034 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
4035 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00004036 {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004037 pj_status_t status;
Benny Prijono26ff9062006-02-21 23:47:00 +00004038
4039 /* Re-INVITE was accepted. */
4040
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004041 /* Process session timer response. */
4042 status = handle_timer_response(inv,
4043 e->body.tsx_state.src.rdata,
4044 PJ_TRUE);
4045 if (status != PJ_SUCCESS)
4046 return;
4047
Benny Prijono26ff9062006-02-21 23:47:00 +00004048 /* Process SDP */
4049 inv_check_sdp_in_incoming_msg(inv, tsx,
4050 e->body.tsx_state.src.rdata);
4051
Nanang Izzuddin0fd92672010-06-16 15:26:18 +00004052 /* Check if local offer got no SDP answer */
4053 if (pjmedia_sdp_neg_get_state(inv->neg)==
4054 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
4055 {
4056 pjmedia_sdp_neg_cancel_offer(inv->neg);
4057 }
4058
Benny Prijono26ff9062006-02-21 23:47:00 +00004059 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00004060 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00004061
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004062 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00004063
4064 /* Handle response that terminates dialog */
4065 /* Nothing to do (already handled) */
4066
Benny Prijono77998ce2007-06-20 10:03:46 +00004067 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
4068
4069 pjmedia_sdp_neg_state neg_state;
4070
4071 /* Outgoing INVITE transaction has failed, cancel SDP nego */
4072 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
4073 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
4074 pjmedia_sdp_neg_cancel_offer(inv->neg);
4075 }
Benny Prijonoe641a742009-05-01 12:01:28 +00004076
4077 if (tsx == inv->invite_tsx)
4078 inv->invite_tsx = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00004079 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00004080
4081 } else if (tsx->role == PJSIP_ROLE_UAS &&
4082 tsx->state == PJSIP_TSX_STATE_TRYING &&
4083 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
4084 {
4085 /*
4086 * Handle incoming UPDATE
4087 */
4088 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
4089
4090 } else if (tsx->role == PJSIP_ROLE_UAC &&
4091 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
4092 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
4093 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
4094 {
4095 /*
4096 * Handle response to outgoing UPDATE request.
4097 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004098 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00004099 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00004100
4101 } else if (tsx->role == PJSIP_ROLE_UAS &&
4102 tsx->state == PJSIP_TSX_STATE_TRYING &&
4103 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
4104 {
4105 /*
4106 * Handle strandled incoming PRACK
4107 */
4108 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
4109
4110 } else if (tsx->role == PJSIP_ROLE_UAC) {
4111 /*
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004112 * Handle 401/407/408/481/422 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00004113 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004114 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00004115 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00004116
Benny Prijono268ca612006-02-07 12:34:11 +00004117}
4118
Benny Prijono8ad55352006-02-08 11:16:05 +00004119/*
4120 * After session has been terminated, but before dialog is destroyed
4121 * (because dialog has other usages, or because dialog is waiting for
4122 * the last transaction to terminate).
4123 */
4124static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00004125{
Benny Prijono8ad55352006-02-08 11:16:05 +00004126 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4127 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00004128
Benny Prijono8ad55352006-02-08 11:16:05 +00004129 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
4130
Benny Prijono70127222006-07-02 14:53:05 +00004131 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00004132 tsx->status_code < 200 &&
4133 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
4134 {
Benny Prijono70127222006-07-02 14:53:05 +00004135 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00004136
4137 /*
Benny Prijono70127222006-07-02 14:53:05 +00004138 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00004139 */
Benny Prijono70127222006-07-02 14:53:05 +00004140 if (tsx->method.id == PJSIP_BYE_METHOD) {
4141 inv_respond_incoming_bye( inv, tsx, rdata, e );
4142 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
4143 /*
4144 * Respond CANCEL with 200/OK too.
4145 */
4146 pjsip_tx_data *tdata;
4147 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00004148
Benny Prijono70127222006-07-02 14:53:05 +00004149 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
4150 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00004151
Benny Prijono70127222006-07-02 14:53:05 +00004152 status = pjsip_dlg_send_response(dlg, tsx, tdata);
4153 if (status != PJ_SUCCESS) return;
4154
4155 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00004156
4157 } else if (tsx->role == PJSIP_ROLE_UAC) {
4158 /*
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004159 * Handle 401/407/408/481/422 response
Benny Prijono61fc5e62008-06-25 18:35:31 +00004160 */
4161 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00004162 }
Benny Prijono268ca612006-02-07 12:34:11 +00004163}
4164