blob: e7eb1c5893c5f9ff84a85cfc3a6299a7cc6adb3f [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
Benny Prijono8ad55352006-02-08 11:16:05 +0000111static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
Benny Prijono268ca612006-02-07 12:34:11 +0000112{
113 &inv_on_state_null,
114 &inv_on_state_calling,
115 &inv_on_state_incoming,
116 &inv_on_state_early,
117 &inv_on_state_connecting,
118 &inv_on_state_confirmed,
119 &inv_on_state_disconnected,
Benny Prijono268ca612006-02-07 12:34:11 +0000120};
121
122static struct mod_inv
123{
124 pjsip_module mod;
125 pjsip_endpoint *endpt;
126 pjsip_inv_callback cb;
Benny Prijono268ca612006-02-07 12:34:11 +0000127} mod_inv =
128{
129 {
Benny Prijono2f8992b2006-02-25 21:16:36 +0000130 NULL, NULL, /* prev, next. */
131 { "mod-invite", 10 }, /* Name. */
132 -1, /* Id */
133 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
134 &mod_inv_load, /* load() */
135 NULL, /* start() */
136 NULL, /* stop() */
137 &mod_inv_unload, /* unload() */
138 &mod_inv_on_rx_request, /* on_rx_request() */
139 &mod_inv_on_rx_response, /* on_rx_response() */
140 NULL, /* on_tx_request. */
141 NULL, /* on_tx_response() */
142 &mod_inv_on_tsx_state, /* on_tsx_state() */
Benny Prijono268ca612006-02-07 12:34:11 +0000143 }
144};
145
146
Benny Prijonoa66c7152006-02-09 01:26:14 +0000147/* Invite session data to be attached to transaction. */
148struct tsx_inv_data
149{
Benny Prijono8fcb4332008-10-31 18:01:48 +0000150 pjsip_inv_session *inv; /* The invite session */
151 pj_bool_t sdp_done; /* SDP negotiation done for this tsx? */
152 pj_str_t done_tag; /* To tag in RX response with answer */
153 pj_bool_t done_early;/* Negotiation was done for early med? */
Benny Prijonoa66c7152006-02-09 01:26:14 +0000154};
155
Benny Prijono8ad55352006-02-08 11:16:05 +0000156/*
157 * Module load()
158 */
Benny Prijono268ca612006-02-07 12:34:11 +0000159static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
160{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000161 pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},
162 { "UPDATE", 6}};
Benny Prijono56315612006-07-18 14:39:40 +0000163 pj_str_t accepted = { "application/sdp", 15 };
Benny Prijono268ca612006-02-07 12:34:11 +0000164
Benny Prijono1f7767b2007-10-03 18:28:49 +0000165 /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */
Benny Prijono268ca612006-02-07 12:34:11 +0000166 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
167 PJ_ARRAY_SIZE(allowed), allowed);
168
Benny Prijono56315612006-07-18 14:39:40 +0000169 /* Register "application/sdp" in Accept header */
170 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
171 1, &accepted);
172
Benny Prijono268ca612006-02-07 12:34:11 +0000173 return PJ_SUCCESS;
174}
175
Benny Prijono8ad55352006-02-08 11:16:05 +0000176/*
177 * Module unload()
178 */
Benny Prijono268ca612006-02-07 12:34:11 +0000179static pj_status_t mod_inv_unload(void)
180{
181 /* Should remove capability here */
182 return PJ_SUCCESS;
183}
184
Benny Prijono8ad55352006-02-08 11:16:05 +0000185/*
Benny Prijono38998232006-02-08 22:44:25 +0000186 * Set session state.
187 */
188void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
189 pjsip_event *e)
190{
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000191 pjsip_inv_state prev_state = inv->state;
Benny Prijono7d910092007-06-20 04:19:46 +0000192 pj_status_t status;
193
194
195 /* If state is confirmed, check that SDP negotiation is done,
196 * otherwise disconnect the session.
197 */
198 if (state == PJSIP_INV_STATE_CONFIRMED) {
199 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
200 pjsip_tx_data *bye;
201
202 PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
203 "session"));
204
205 status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
206 NULL, &bye);
207 if (status == PJ_SUCCESS && bye)
208 status = pjsip_inv_send_msg(inv, bye);
209
210 return;
211 }
212 }
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000213
214 /* Set state. */
Benny Prijono38998232006-02-08 22:44:25 +0000215 inv->state = state;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000216
217 /* If state is DISCONNECTED, cause code MUST have been set. */
218 pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
219 inv->cause != 0);
220
221 /* Call on_state_changed() callback. */
222 if (mod_inv.cb.on_state_changed && inv->notify)
Benny Prijono38998232006-02-08 22:44:25 +0000223 (*mod_inv.cb.on_state_changed)(inv, e);
224
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000225 /* Only decrement when previous state is not already DISCONNECTED */
226 if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
227 prev_state != PJSIP_INV_STATE_DISCONNECTED)
228 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000229 if (inv->last_ack) {
230 pjsip_tx_data_dec_ref(inv->last_ack);
231 inv->last_ack = NULL;
232 }
Benny Prijono5e51a4e2008-11-27 00:06:46 +0000233 if (inv->invite_req) {
234 pjsip_tx_data_dec_ref(inv->invite_req);
235 inv->invite_req = NULL;
236 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000237 pjsip_100rel_end_session(inv);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000238 pjsip_timer_end_session(inv);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000239 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
Benny Prijono40d62b62009-08-12 17:53:47 +0000240
241 /* Release the flip-flop pools */
242 pj_pool_release(inv->pool_prov);
243 pj_pool_release(inv->pool_active);
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000244 }
Benny Prijono38998232006-02-08 22:44:25 +0000245}
246
247
248/*
Benny Prijono0b6340c2006-06-13 22:21:23 +0000249 * Set cause code.
250 */
251void inv_set_cause(pjsip_inv_session *inv, int cause_code,
252 const pj_str_t *cause_text)
253{
254 if (cause_code > inv->cause) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000255 inv->cause = (pjsip_status_code) cause_code;
Benny Prijono0b6340c2006-06-13 22:21:23 +0000256 if (cause_text)
257 pj_strdup(inv->pool, &inv->cause_text, cause_text);
258 else if (cause_code/100 == 2)
259 inv->cause_text = pj_str("Normal call clearing");
260 else
261 inv->cause_text = *pjsip_get_status_text(cause_code);
262 }
263}
264
265
Benny Prijono1f7767b2007-10-03 18:28:49 +0000266/*
267 * Check if outgoing request needs to have SDP answer.
268 * This applies for both ACK and PRACK requests.
269 */
Benny Prijono9569a0b2007-10-04 15:35:26 +0000270static const pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv,
271 pjsip_transaction *tsx)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000272{
273 pjmedia_sdp_neg_state neg_state;
Benny Prijono9569a0b2007-10-04 15:35:26 +0000274 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000275 pj_status_t status;
276
277 /* If SDP negotiator is ready, start negotiation. */
278
279 /* Start nego when appropriate. */
280 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
281 PJMEDIA_SDP_NEG_STATE_NULL;
282
283 if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) {
284
285 /* Nothing to do */
286
287 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
288 pjmedia_sdp_neg_has_local_answer(inv->neg) )
289 {
290 struct tsx_inv_data *tsx_inv_data;
Benny Prijonod5f9f422007-11-25 04:40:07 +0000291 struct tsx_inv_data dummy;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000292
Benny Prijonod5f9f422007-11-25 04:40:07 +0000293 /* Get invite session's transaction data.
294 * Note that tsx may be NULL, for example when application sends
295 * delayed ACK request (at this time, the original INVITE
296 * transaction may have been destroyed.
297 */
298 if (tsx) {
299 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
300 } else {
301 tsx_inv_data = &dummy;
302 pj_bzero(&dummy, sizeof(dummy));
303 dummy.inv = inv;
304 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000305
306 status = inv_negotiate_sdp(inv);
307 if (status != PJ_SUCCESS)
308 return NULL;
309
310 /* Mark this transaction has having SDP offer/answer done. */
311 tsx_inv_data->sdp_done = 1;
312
313 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
314
315 } else {
316 /* This remark is only valid for ACK.
317 PJ_LOG(4,(inv->dlg->obj_name,
318 "FYI, the SDP negotiator state (%s) is in a mess "
319 "when sending this ACK/PRACK request",
320 pjmedia_sdp_neg_state_str(neg_state)));
321 */
322 }
323
324 return sdp;
325}
326
Benny Prijono0b6340c2006-06-13 22:21:23 +0000327
328/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000329 * Send ACK for 2xx response.
330 */
Benny Prijonod5f9f422007-11-25 04:40:07 +0000331static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +0000332{
Benny Prijonod5f9f422007-11-25 04:40:07 +0000333 pjsip_rx_data *rdata;
Benny Prijono268ca612006-02-07 12:34:11 +0000334 pj_status_t status;
335
Benny Prijonod5f9f422007-11-25 04:40:07 +0000336 if (e->type == PJSIP_EVENT_TSX_STATE)
337 rdata = e->body.tsx_state.src.rdata;
338 else if (e->type == PJSIP_EVENT_RX_MSG)
339 rdata = e->body.rx_msg.rdata;
340 else {
341 pj_assert(!"Unsupported event type");
342 return PJ_EBUG;
343 }
344
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000345 PJ_LOG(5,(inv->obj_name, "Received %s, sending ACK",
346 pjsip_rx_data_get_info(rdata)));
347
Benny Prijono1f7767b2007-10-03 18:28:49 +0000348 /* Check if we have cached ACK request */
349 if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000350
Benny Prijono1f7767b2007-10-03 18:28:49 +0000351 pjsip_tx_data_add_ref(inv->last_ack);
Benny Prijonod5f9f422007-11-25 04:40:07 +0000352
353 } else if (mod_inv.cb.on_send_ack) {
354 /* If application handles ACK transmission manually, just notify the
355 * callback
356 */
357 PJ_LOG(5,(inv->obj_name, "Received %s, notifying application callback",
358 pjsip_rx_data_get_info(rdata)));
359
360 (*mod_inv.cb.on_send_ack)(inv, rdata);
361 return PJ_SUCCESS;
362
Benny Prijono1f7767b2007-10-03 18:28:49 +0000363 } else {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000364 status = pjsip_inv_create_ack(inv, rdata->msg_info.cseq->cseq,
365 &inv->last_ack);
Benny Prijono268ca612006-02-07 12:34:11 +0000366 }
367
Benny Prijono1f7767b2007-10-03 18:28:49 +0000368 /* Send ACK */
369 status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000370 if (status != PJ_SUCCESS) {
371 /* Better luck next time */
372 pj_assert(!"Unable to send ACK!");
373 return status;
374 }
375
Benny Prijonod5f9f422007-11-25 04:40:07 +0000376
Benny Prijonoe6da48a2008-09-22 14:36:00 +0000377 /* Set state to CONFIRMED (if we're not in CONFIRMED yet).
378 * But don't set it to CONFIRMED if we're already DISCONNECTED
379 * (this may have been a late 200/OK response.
380 */
381 if (inv->state < PJSIP_INV_STATE_CONFIRMED) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000382 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
383 }
384
Benny Prijono268ca612006-02-07 12:34:11 +0000385 return PJ_SUCCESS;
386}
387
Benny Prijono8ad55352006-02-08 11:16:05 +0000388/*
389 * Module on_rx_request()
390 *
391 * This callback is called for these events:
392 * - endpoint receives request which was unhandled by higher priority
393 * modules (e.g. transaction layer, dialog layer).
394 * - dialog distributes incoming request to its usages.
395 */
396static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
397{
398 pjsip_method *method;
Benny Prijono38998232006-02-08 22:44:25 +0000399 pjsip_dialog *dlg;
400 pjsip_inv_session *inv;
Benny Prijono8ad55352006-02-08 11:16:05 +0000401
402 /* Only wants to receive request from a dialog. */
Benny Prijono38998232006-02-08 22:44:25 +0000403 dlg = pjsip_rdata_get_dlg(rdata);
404 if (dlg == NULL)
Benny Prijono8ad55352006-02-08 11:16:05 +0000405 return PJ_FALSE;
406
Benny Prijonoa1e69682007-05-11 15:14:34 +0000407 inv = (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono38998232006-02-08 22:44:25 +0000408
Benny Prijono8ad55352006-02-08 11:16:05 +0000409 /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
410 * If we need to send response, it will be sent in the state
411 * handlers.
412 */
413 method = &rdata->msg_info.msg->line.req.method;
414
Benny Prijono70127222006-07-02 14:53:05 +0000415 if (method->id == PJSIP_INVITE_METHOD) {
416 return PJ_TRUE;
417 }
418
419 /* BYE and CANCEL must have existing invite session */
420 if (method->id == PJSIP_BYE_METHOD ||
421 method->id == PJSIP_CANCEL_METHOD)
Benny Prijono8ad55352006-02-08 11:16:05 +0000422 {
Benny Prijono70127222006-07-02 14:53:05 +0000423 if (inv == NULL)
424 return PJ_FALSE;
425
Benny Prijono8ad55352006-02-08 11:16:05 +0000426 return PJ_TRUE;
427 }
428
Benny Prijono38998232006-02-08 22:44:25 +0000429 /* On receipt ACK request, when state is CONNECTING,
430 * move state to CONFIRMED.
431 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000432 if (method->id == PJSIP_ACK_METHOD && inv) {
Benny Prijono38998232006-02-08 22:44:25 +0000433
Benny Prijonof521eb02006-08-06 23:07:25 +0000434 /* Ignore ACK if pending INVITE transaction has not finished. */
435 if (inv->invite_tsx &&
436 inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
437 {
438 return PJ_TRUE;
439 }
440
Benny Prijono5eff0432006-02-09 14:14:21 +0000441 /* Terminate INVITE transaction, if it's still present. */
442 if (inv->invite_tsx &&
443 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
444 {
Benny Prijono7d910092007-06-20 04:19:46 +0000445 /* Before we terminate INVITE transaction, process the SDP
Benny Prijono59e9e952008-09-21 22:55:43 +0000446 * in the ACK request, if any.
447 * Only do this when invite state is not already disconnected
448 * (http://trac.pjsip.org/repos/ticket/640).
Benny Prijono7d910092007-06-20 04:19:46 +0000449 */
Benny Prijono59e9e952008-09-21 22:55:43 +0000450 if (inv->state < PJSIP_INV_STATE_DISCONNECTED) {
451 inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
452 }
Benny Prijono7d910092007-06-20 04:19:46 +0000453
454 /* Now we can terminate the INVITE transaction */
Benny Prijonof521eb02006-08-06 23:07:25 +0000455 pj_assert(inv->invite_tsx->status_code >= 200);
Benny Prijono5eff0432006-02-09 14:14:21 +0000456 pjsip_tsx_terminate(inv->invite_tsx,
457 inv->invite_tsx->status_code);
458 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000459 if (inv->last_answer) {
460 pjsip_tx_data_dec_ref(inv->last_answer);
461 inv->last_answer = NULL;
462 }
Benny Prijono5eff0432006-02-09 14:14:21 +0000463 }
464
Benny Prijono32ac8fe2006-03-02 21:16:55 +0000465 /* On receipt of ACK, only set state to confirmed when state
466 * is CONNECTING (e.g. we don't want to set the state to confirmed
467 * when we receive ACK retransmission after sending non-2xx!)
468 */
469 if (inv->state == PJSIP_INV_STATE_CONNECTING) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000470 pjsip_event event;
471
472 PJSIP_EVENT_INIT_RX_MSG(event, rdata);
473 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
474 }
Benny Prijono38998232006-02-08 22:44:25 +0000475 }
476
Benny Prijono8ad55352006-02-08 11:16:05 +0000477 return PJ_FALSE;
478}
479
480/*
481 * Module on_rx_response().
482 *
483 * This callback is called for these events:
484 * - dialog distributes incoming 2xx response to INVITE (outside
485 * transaction) to its usages.
486 * - endpoint distributes strayed responses.
487 */
Benny Prijono268ca612006-02-07 12:34:11 +0000488static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
489{
490 pjsip_dialog *dlg;
491 pjsip_inv_session *inv;
492 pjsip_msg *msg = rdata->msg_info.msg;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000493 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +0000494 pjsip_status_code st_code;
Benny Prijono268ca612006-02-07 12:34:11 +0000495
496 dlg = pjsip_rdata_get_dlg(rdata);
497
498 /* Ignore responses outside dialog */
499 if (dlg == NULL)
500 return PJ_FALSE;
501
502 /* Ignore responses not belonging to invite session */
503 inv = pjsip_dlg_get_inv_session(dlg);
504 if (inv == NULL)
505 return PJ_FALSE;
506
507 /* This MAY be retransmission of 2xx response to INVITE.
508 * If it is, we need to send ACK.
509 */
510 if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
Benny Prijono26ff9062006-02-21 23:47:00 +0000511 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
512 inv->invite_tsx == NULL)
513 {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000514 pjsip_event e;
Benny Prijono268ca612006-02-07 12:34:11 +0000515
Benny Prijonod5f9f422007-11-25 04:40:07 +0000516 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
517 inv_send_ack(inv, &e);
Benny Prijono268ca612006-02-07 12:34:11 +0000518 return PJ_TRUE;
519
520 }
521
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000522 /* Pass response to timer session module */
Nanang Izzuddin65add622009-08-11 16:26:20 +0000523 status = pjsip_timer_process_resp(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000524 if (status != PJ_SUCCESS) {
525 pjsip_event e;
526 pjsip_tx_data *tdata;
527
528 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
529 inv_send_ack(inv, &e);
530
Nanang Izzuddin65add622009-08-11 16:26:20 +0000531 status = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000532 if (tdata && status == PJ_SUCCESS)
533 pjsip_inv_send_msg(inv, tdata);
534
535 return PJ_TRUE;
536 }
537
Benny Prijono268ca612006-02-07 12:34:11 +0000538 /* No other processing needs to be done here. */
539 return PJ_FALSE;
540}
541
Benny Prijono8ad55352006-02-08 11:16:05 +0000542/*
543 * Module on_tsx_state()
544 *
545 * This callback is called by dialog framework for all transactions
546 * inside the dialog for all its dialog usages.
547 */
Benny Prijono268ca612006-02-07 12:34:11 +0000548static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
549{
550 pjsip_dialog *dlg;
551 pjsip_inv_session *inv;
552
553 dlg = pjsip_tsx_get_dlg(tsx);
554 if (dlg == NULL)
555 return;
556
557 inv = pjsip_dlg_get_inv_session(dlg);
558 if (inv == NULL)
559 return;
560
561 /* Call state handler for the invite session. */
562 (*inv_state_handler[inv->state])(inv, e);
563
564 /* Call on_tsx_state */
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000565 if (mod_inv.cb.on_tsx_state_changed && inv->notify)
Benny Prijono268ca612006-02-07 12:34:11 +0000566 (*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
567
Benny Prijono46249942007-02-19 22:23:14 +0000568 /* Clear invite transaction when tsx is confirmed.
569 * Previously we set invite_tsx to NULL only when transaction has
570 * terminated, but this didn't work when ACK has the same Via branch
571 * value as the INVITE (see http://www.pjsip.org/trac/ticket/113)
572 */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000573 if (tsx->state>=PJSIP_TSX_STATE_CONFIRMED && tsx == inv->invite_tsx) {
Benny Prijono46249942007-02-19 22:23:14 +0000574 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000575 if (inv->last_answer) {
576 pjsip_tx_data_dec_ref(inv->last_answer);
577 inv->last_answer = NULL;
578 }
579 }
Benny Prijono268ca612006-02-07 12:34:11 +0000580}
581
Benny Prijono8ad55352006-02-08 11:16:05 +0000582
583/*
584 * Initialize the invite module.
585 */
Benny Prijono268ca612006-02-07 12:34:11 +0000586PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
Benny Prijono268ca612006-02-07 12:34:11 +0000587 const pjsip_inv_callback *cb)
588{
589 pj_status_t status;
590
591 /* Check arguments. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000592 PJ_ASSERT_RETURN(endpt && cb, PJ_EINVAL);
Benny Prijono268ca612006-02-07 12:34:11 +0000593
594 /* Some callbacks are mandatory */
595 PJ_ASSERT_RETURN(cb->on_state_changed && cb->on_new_session, PJ_EINVAL);
596
597 /* Check if module already registered. */
598 PJ_ASSERT_RETURN(mod_inv.mod.id == -1, PJ_EINVALIDOP);
599
600 /* Copy param. */
601 pj_memcpy(&mod_inv.cb, cb, sizeof(pjsip_inv_callback));
602
603 mod_inv.endpt = endpt;
Benny Prijono268ca612006-02-07 12:34:11 +0000604
605 /* Register the module. */
606 status = pjsip_endpt_register_module(endpt, &mod_inv.mod);
Benny Prijono053f5222006-11-11 16:16:04 +0000607 if (status != PJ_SUCCESS)
608 return status;
Benny Prijono268ca612006-02-07 12:34:11 +0000609
Benny Prijono053f5222006-11-11 16:16:04 +0000610 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +0000611}
612
Benny Prijono8ad55352006-02-08 11:16:05 +0000613/*
614 * Get the instance of invite module.
615 */
Benny Prijono268ca612006-02-07 12:34:11 +0000616PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
617{
618 return &mod_inv.mod;
619}
620
621
Benny Prijono632ce712006-02-09 14:01:40 +0000622
Benny Prijono8ad55352006-02-08 11:16:05 +0000623/*
624 * Return the invite session for the specified dialog.
625 */
Benny Prijono268ca612006-02-07 12:34:11 +0000626PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
627{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000628 return (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono268ca612006-02-07 12:34:11 +0000629}
630
Benny Prijono8ad55352006-02-08 11:16:05 +0000631
Benny Prijono268ca612006-02-07 12:34:11 +0000632/*
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000633 * Get INVITE state name.
634 */
635PJ_DEF(const char *) pjsip_inv_state_name(pjsip_inv_state state)
636{
637 PJ_ASSERT_RETURN(state >= PJSIP_INV_STATE_NULL &&
638 state <= PJSIP_INV_STATE_DISCONNECTED,
639 "??");
640
641 return inv_state_names[state];
642}
643
644/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000645 * Create UAC invite session.
Benny Prijono268ca612006-02-07 12:34:11 +0000646 */
647PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
648 const pjmedia_sdp_session *local_sdp,
649 unsigned options,
650 pjsip_inv_session **p_inv)
651{
652 pjsip_inv_session *inv;
653 pj_status_t status;
654
655 /* Verify arguments. */
656 PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
657
Benny Prijono8eae8382006-08-10 21:44:26 +0000658 /* Must lock dialog first */
659 pjsip_dlg_inc_lock(dlg);
660
Benny Prijono268ca612006-02-07 12:34:11 +0000661 /* Normalize options */
662 if (options & PJSIP_INV_REQUIRE_100REL)
663 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000664 if (options & PJSIP_INV_REQUIRE_TIMER)
665 options |= PJSIP_INV_SUPPORT_TIMER;
666
667 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000668 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +0000669 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000670
671 inv->pool = dlg->pool;
672 inv->role = PJSIP_ROLE_UAC;
673 inv->state = PJSIP_INV_STATE_NULL;
674 inv->dlg = dlg;
675 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000676 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000677 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +0000678
Benny Prijono40d62b62009-08-12 17:53:47 +0000679 /* Create flip-flop pool (see ticket #877) */
680 /* (using inv->obj_name as temporary variable for pool names */
681 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg->pool);
682 inv->pool_prov = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
683 POOL_INIT_SIZE, POOL_INC_SIZE);
684 inv->pool_active = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
685 POOL_INIT_SIZE, POOL_INC_SIZE);
686
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000687 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +0000688 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000689
Benny Prijono268ca612006-02-07 12:34:11 +0000690 /* Create negotiator if local_sdp is specified. */
691 if (local_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +0000692 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
693 local_sdp, &inv->neg);
Benny Prijono8eae8382006-08-10 21:44:26 +0000694 if (status != PJ_SUCCESS) {
695 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000696 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000697 }
Benny Prijono268ca612006-02-07 12:34:11 +0000698 }
699
700 /* Register invite as dialog usage. */
701 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +0000702 if (status != PJ_SUCCESS) {
703 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000704 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000705 }
Benny Prijono268ca612006-02-07 12:34:11 +0000706
707 /* Increment dialog session */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000708 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +0000709
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000710 /* Create 100rel handler */
711 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000712
Benny Prijono268ca612006-02-07 12:34:11 +0000713 /* Done */
714 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000715
Benny Prijono8eae8382006-08-10 21:44:26 +0000716 pjsip_dlg_dec_lock(dlg);
717
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000718 PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
719 dlg->obj_name));
720
Benny Prijono268ca612006-02-07 12:34:11 +0000721 return PJ_SUCCESS;
722}
723
724/*
725 * Verify incoming INVITE request.
726 */
Benny Prijono87a90212008-01-23 20:29:30 +0000727PJ_DEF(pj_status_t) pjsip_inv_verify_request2(pjsip_rx_data *rdata,
728 unsigned *options,
729 const pjmedia_sdp_session *r_sdp,
730 const pjmedia_sdp_session *l_sdp,
731 pjsip_dialog *dlg,
732 pjsip_endpoint *endpt,
733 pjsip_tx_data **p_tdata)
Benny Prijono268ca612006-02-07 12:34:11 +0000734{
735 pjsip_msg *msg;
736 pjsip_allow_hdr *allow;
737 pjsip_supported_hdr *sup_hdr;
738 pjsip_require_hdr *req_hdr;
739 int code = 200;
740 unsigned rem_option = 0;
741 pj_status_t status = PJ_SUCCESS;
742 pjsip_hdr res_hdr_list;
743
744 /* Init return arguments. */
745 if (p_tdata) *p_tdata = NULL;
746
747 /* Verify arguments. */
748 PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);
749
750 /* Normalize options */
751 if (*options & PJSIP_INV_REQUIRE_100REL)
752 *options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000753 if (*options & PJSIP_INV_REQUIRE_TIMER)
754 *options |= PJSIP_INV_SUPPORT_TIMER;
755
756 /* Get the message in rdata */
757 msg = rdata->msg_info.msg;
758
759 /* Must be INVITE request. */
760 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
761 msg->line.req.method.id == PJSIP_INVITE_METHOD,
762 PJ_EINVAL);
763
764 /* If tdata is specified, then either dlg or endpt must be specified */
765 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
766
767 /* Get the endpoint */
768 endpt = endpt ? endpt : dlg->endpt;
769
770 /* Init response header list */
771 pj_list_init(&res_hdr_list);
772
Benny Prijono87a90212008-01-23 20:29:30 +0000773 /* Check the request body, see if it's something that we support,
774 * only when the body hasn't been parsed before.
Benny Prijono268ca612006-02-07 12:34:11 +0000775 */
Benny Prijono87a90212008-01-23 20:29:30 +0000776 if (r_sdp==NULL && msg->body) {
Benny Prijono268ca612006-02-07 12:34:11 +0000777 pjsip_msg_body *body = msg->body;
778 pj_str_t str_application = {"application", 11};
779 pj_str_t str_sdp = { "sdp", 3 };
780 pjmedia_sdp_session *sdp;
781
782 /* Check content type. */
783 if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||
784 pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)
785 {
786 /* Not "application/sdp" */
787 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
788 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
789
790 if (p_tdata) {
791 /* Add Accept header to response */
792 pjsip_accept_hdr *acc;
793
794 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
795 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
796 acc->values[acc->count++] = pj_str("application/sdp");
797 pj_list_push_back(&res_hdr_list, acc);
798 }
799
800 goto on_return;
801 }
802
803 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000804 status = pjmedia_sdp_parse(rdata->tp_info.pool,
805 (char*)body->data, body->len, &sdp);
Benny Prijono268ca612006-02-07 12:34:11 +0000806 if (status == PJ_SUCCESS)
807 status = pjmedia_sdp_validate(sdp);
808
809 if (status != PJ_SUCCESS) {
810 /* Unparseable or invalid SDP */
811 code = PJSIP_SC_BAD_REQUEST;
812
813 if (p_tdata) {
814 /* Add Warning header. */
815 pjsip_warning_hdr *w;
816
817 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
818 pjsip_endpt_name(endpt),
819 status);
820 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
821
822 pj_list_push_back(&res_hdr_list, w);
823 }
824
825 goto on_return;
826 }
827
Benny Prijono87a90212008-01-23 20:29:30 +0000828 r_sdp = sdp;
829 }
830
831 if (r_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +0000832 /* Negotiate with local SDP */
833 if (l_sdp) {
834 pjmedia_sdp_neg *neg;
835
836 /* Local SDP must be valid! */
837 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
838 status);
839
840 /* Create SDP negotiator */
841 status = pjmedia_sdp_neg_create_w_remote_offer(
Benny Prijono87a90212008-01-23 20:29:30 +0000842 rdata->tp_info.pool, l_sdp, r_sdp, &neg);
Benny Prijono268ca612006-02-07 12:34:11 +0000843 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
844
845 /* Negotiate SDP */
846 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
847 if (status != PJ_SUCCESS) {
848
849 /* Incompatible media */
850 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000851
852 if (p_tdata) {
853 pjsip_accept_hdr *acc;
854 pjsip_warning_hdr *w;
855
856 /* Add Warning header. */
857 w = pjsip_warning_hdr_create_from_status(
858 rdata->tp_info.pool,
859 pjsip_endpt_name(endpt), status);
860 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
861
862 pj_list_push_back(&res_hdr_list, w);
863
864 /* Add Accept header to response */
865 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
866 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
867 acc->values[acc->count++] = pj_str("application/sdp");
868 pj_list_push_back(&res_hdr_list, acc);
869
870 }
871
872 goto on_return;
873 }
874 }
875 }
876
877 /* Check supported methods, see if peer supports UPDATE.
878 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
879 * implicitly by sending this INVITE.
880 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000881 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000882 if (allow) {
883 unsigned i;
884 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
885
886 for (i=0; i<allow->count; ++i) {
887 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
888 break;
889 }
890
891 if (i != allow->count) {
892 /* UPDATE is present in Allow */
893 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
894 }
895
896 }
897
898 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000899 sup_hdr = (pjsip_supported_hdr*)
900 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000901 if (sup_hdr) {
902 unsigned i;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000903 const pj_str_t STR_100REL = { "100rel", 6};
904 const pj_str_t STR_TIMER = { "timer", 5};
Benny Prijono268ca612006-02-07 12:34:11 +0000905
906 for (i=0; i<sup_hdr->count; ++i) {
907 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
908 rem_option |= PJSIP_INV_SUPPORT_100REL;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000909 if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000910 rem_option |= PJSIP_INV_SUPPORT_TIMER;
911 }
912 }
913
914 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000915 req_hdr = (pjsip_require_hdr*)
916 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000917 if (req_hdr) {
918 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +0000919 const pj_str_t STR_100REL = { "100rel", 6};
Benny Prijono053f5222006-11-11 16:16:04 +0000920 const pj_str_t STR_REPLACES = { "replaces", 8 };
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000921 const pj_str_t STR_TIMER = { "timer", 5 };
Benny Prijono268ca612006-02-07 12:34:11 +0000922 unsigned unsupp_cnt = 0;
923 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
924
925 for (i=0; i<req_hdr->count; ++i) {
926 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
927 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
928 {
929 rem_option |= PJSIP_INV_REQUIRE_100REL;
930
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000931 } else if ((*options & PJSIP_INV_SUPPORT_TIMER) &&
932 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +0000933 {
934 rem_option |= PJSIP_INV_REQUIRE_TIMER;
935
Benny Prijono053f5222006-11-11 16:16:04 +0000936 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
937 pj_bool_t supp;
938
939 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
940 NULL, &STR_REPLACES);
941 if (!supp)
942 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
943
Nanang Izzuddin5d5a20e2009-08-06 16:04:20 +0000944 } else if (!pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
945 NULL, &req_hdr->values[i]))
946 {
Benny Prijono268ca612006-02-07 12:34:11 +0000947 /* Unknown/unsupported extension tag! */
948 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
949 }
950 }
951
952 /* Check if there are required tags that we don't support */
953 if (unsupp_cnt) {
954
955 code = PJSIP_SC_BAD_EXTENSION;
956 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
957
958 if (p_tdata) {
959 pjsip_unsupported_hdr *unsupp_hdr;
960 const pjsip_hdr *h;
961
962 /* Add Unsupported header. */
963 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
964 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
965
966 unsupp_hdr->count = unsupp_cnt;
967 for (i=0; i<unsupp_cnt; ++i)
968 unsupp_hdr->values[i] = unsupp_tags[i];
969
970 pj_list_push_back(&res_hdr_list, unsupp_hdr);
971
972 /* Add Supported header. */
973 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
974 NULL);
975 pj_assert(h);
976 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000977 sup_hdr = (pjsip_supported_hdr*)
978 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000979 pj_list_push_back(&res_hdr_list, sup_hdr);
980 }
981 }
982
983 goto on_return;
984 }
985 }
986
987 /* Check if there are local requirements that are not supported
988 * by peer.
989 */
990 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
991 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
Nanang Izzuddin65add622009-08-11 16:26:20 +0000992 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
993 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
Benny Prijono268ca612006-02-07 12:34:11 +0000994 {
995 code = PJSIP_SC_EXTENSION_REQUIRED;
996 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
997
998 if (p_tdata) {
999 const pjsip_hdr *h;
1000
1001 /* Add Require header. */
1002 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
1003 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
1004
1005 if (*options & PJSIP_INV_REQUIRE_100REL)
1006 req_hdr->values[req_hdr->count++] = pj_str("100rel");
Benny Prijono268ca612006-02-07 12:34:11 +00001007 if (*options & PJSIP_INV_REQUIRE_TIMER)
1008 req_hdr->values[req_hdr->count++] = pj_str("timer");
1009
1010 pj_list_push_back(&res_hdr_list, req_hdr);
1011
1012 /* Add Supported header. */
1013 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
1014 NULL);
1015 pj_assert(h);
1016 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001017 sup_hdr = (pjsip_supported_hdr*)
1018 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001019 pj_list_push_back(&res_hdr_list, sup_hdr);
1020 }
1021
1022 }
1023
1024 goto on_return;
1025 }
1026
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001027 /* If remote Require something that we support, make us Require
1028 * that feature too.
1029 */
1030 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
1031 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
1032 *options |= PJSIP_INV_REQUIRE_100REL;
1033 }
1034 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1035 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1036 *options |= PJSIP_INV_REQUIRE_TIMER;
1037 }
1038
Benny Prijono268ca612006-02-07 12:34:11 +00001039on_return:
1040
1041 /* Create response if necessary */
1042 if (code != 200 && p_tdata) {
1043 pjsip_tx_data *tdata;
1044 const pjsip_hdr *h;
1045
1046 if (dlg) {
1047 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1048 &tdata);
1049 } else {
1050 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1051 &tdata);
1052 }
1053
1054 if (status != PJ_SUCCESS)
1055 return status;
1056
1057 /* Add response headers. */
1058 h = res_hdr_list.next;
1059 while (h != &res_hdr_list) {
1060 pjsip_hdr *cloned;
1061
Benny Prijonoa1e69682007-05-11 15:14:34 +00001062 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001063 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1064
1065 pjsip_msg_add_hdr(tdata->msg, cloned);
1066
1067 h = h->next;
1068 }
1069
1070 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001071
1072 /* Can not return PJ_SUCCESS when response message is produced.
1073 * Ref: PROTOS test ~#2490
1074 */
1075 if (status == PJ_SUCCESS)
1076 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1077
Benny Prijono268ca612006-02-07 12:34:11 +00001078 }
1079
1080 return status;
1081}
1082
Benny Prijono87a90212008-01-23 20:29:30 +00001083
1084/*
1085 * Verify incoming INVITE request.
1086 */
1087PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1088 unsigned *options,
1089 const pjmedia_sdp_session *l_sdp,
1090 pjsip_dialog *dlg,
1091 pjsip_endpoint *endpt,
1092 pjsip_tx_data **p_tdata)
1093{
1094 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1095 endpt, p_tdata);
1096}
1097
Benny Prijono268ca612006-02-07 12:34:11 +00001098/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001099 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001100 */
1101PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1102 pjsip_rx_data *rdata,
1103 const pjmedia_sdp_session *local_sdp,
1104 unsigned options,
1105 pjsip_inv_session **p_inv)
1106{
1107 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001108 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001109 pjsip_msg *msg;
1110 pjmedia_sdp_session *rem_sdp = NULL;
1111 pj_status_t status;
1112
1113 /* Verify arguments. */
1114 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1115
1116 /* Dialog MUST have been initialised. */
1117 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1118
1119 msg = rdata->msg_info.msg;
1120
1121 /* rdata MUST contain INVITE request */
1122 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1123 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1124 PJ_EINVALIDOP);
1125
Benny Prijono8eae8382006-08-10 21:44:26 +00001126 /* Lock dialog */
1127 pjsip_dlg_inc_lock(dlg);
1128
Benny Prijono268ca612006-02-07 12:34:11 +00001129 /* Normalize options */
1130 if (options & PJSIP_INV_REQUIRE_100REL)
1131 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +00001132 if (options & PJSIP_INV_REQUIRE_TIMER)
1133 options |= PJSIP_INV_SUPPORT_TIMER;
1134
1135 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001136 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001137 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001138
1139 inv->pool = dlg->pool;
1140 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001141 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001142 inv->dlg = dlg;
1143 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001144 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001145 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001146
Benny Prijono40d62b62009-08-12 17:53:47 +00001147 /* Create flip-flop pool (see ticket #877) */
1148 /* (using inv->obj_name as temporary variable for pool names */
1149 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg->pool);
1150 inv->pool_prov = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1151 POOL_INIT_SIZE, POOL_INC_SIZE);
1152 inv->pool_active = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1153 POOL_INIT_SIZE, POOL_INC_SIZE);
1154
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001155 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001156 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001157
Benny Prijono268ca612006-02-07 12:34:11 +00001158 /* Parse SDP in message body, if present. */
1159 if (msg->body) {
1160 pjsip_msg_body *body = msg->body;
1161
1162 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001163 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001164 &rem_sdp);
1165 if (status == PJ_SUCCESS)
1166 status = pjmedia_sdp_validate(rem_sdp);
1167
Benny Prijono8eae8382006-08-10 21:44:26 +00001168 if (status != PJ_SUCCESS) {
1169 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001170 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001171 }
Benny Prijono268ca612006-02-07 12:34:11 +00001172 }
1173
1174 /* Create negotiator. */
1175 if (rem_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001176 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool,
1177 local_sdp, rem_sdp,
1178 &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001179
1180 } else if (local_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001181 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1182 local_sdp, &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001183 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001184 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001185 }
1186
Benny Prijono8eae8382006-08-10 21:44:26 +00001187 if (status != PJ_SUCCESS) {
1188 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001189 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001190 }
Benny Prijono268ca612006-02-07 12:34:11 +00001191
1192 /* Register invite as dialog usage. */
1193 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001194 if (status != PJ_SUCCESS) {
1195 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001196 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001197 }
Benny Prijono268ca612006-02-07 12:34:11 +00001198
1199 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001200 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001201
1202 /* Save the invite transaction. */
1203 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001204
1205 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001206 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001207 tsx_inv_data->inv = inv;
1208 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001209
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001210 /* Create 100rel handler */
1211 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001212 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001213 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001214
Benny Prijono268ca612006-02-07 12:34:11 +00001215 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001216 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001217 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001218
1219 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1220 dlg->obj_name));
1221
Benny Prijono268ca612006-02-07 12:34:11 +00001222 return PJ_SUCCESS;
1223}
1224
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001225/*
1226 * Forcefully terminate the session.
1227 */
1228PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1229 int st_code,
1230 pj_bool_t notify)
1231{
1232 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1233
1234 /* Lock dialog. */
1235 pjsip_dlg_inc_lock(inv->dlg);
1236
1237 /* Set callback notify flag. */
1238 inv->notify = notify;
1239
1240 /* If there's pending transaction, terminate the transaction.
1241 * This may subsequently set the INVITE session state to
1242 * disconnected.
1243 */
1244 if (inv->invite_tsx &&
1245 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1246 {
1247 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1248
1249 }
1250
1251 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001252 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001253
1254 /* Forcefully terminate the session if state is not DISCONNECTED */
1255 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1256 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1257 }
1258
1259 /* Done.
1260 * The dec_lock() below will actually destroys the dialog if it
1261 * has no other session.
1262 */
1263 pjsip_dlg_dec_lock(inv->dlg);
1264
1265 return PJ_SUCCESS;
1266}
1267
1268
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001269/*
1270 * Restart UAC session, possibly because app or us wants to re-send the
1271 * INVITE request due to 401/407 challenge or 3xx response.
1272 */
1273PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1274 pj_bool_t new_offer)
1275{
1276 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1277
1278 inv->state = PJSIP_INV_STATE_NULL;
1279 inv->invite_tsx = NULL;
1280 if (inv->last_answer) {
1281 pjsip_tx_data_dec_ref(inv->last_answer);
1282 inv->last_answer = NULL;
1283 }
1284
1285 if (new_offer && inv->neg) {
1286 pjmedia_sdp_neg_state neg_state;
1287
1288 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1289 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1290 pjmedia_sdp_neg_cancel_offer(inv->neg);
1291 }
1292 }
1293
1294 return PJ_SUCCESS;
1295}
1296
1297
Benny Prijono268ca612006-02-07 12:34:11 +00001298static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1299{
1300 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001301 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001302}
1303
1304static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1305{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001306 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001307}
1308
Benny Prijono56315612006-07-18 14:39:40 +00001309
1310PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1311 pjmedia_sdp_session *sdp,
1312 pjsip_msg_body **p_body)
1313{
1314 const pj_str_t STR_APPLICATION = { "application", 11};
1315 const pj_str_t STR_SDP = { "sdp", 3 };
1316 pjsip_msg_body *body;
1317
Benny Prijonoa1e69682007-05-11 15:14:34 +00001318 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001319 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1320
1321 body->content_type.type = STR_APPLICATION;
1322 body->content_type.subtype = STR_SDP;
1323 body->data = sdp;
1324 body->len = 0;
1325 body->clone_data = &clone_sdp;
1326 body->print_body = &print_sdp;
1327
1328 *p_body = body;
1329
1330 return PJ_SUCCESS;
1331}
1332
Benny Prijono268ca612006-02-07 12:34:11 +00001333static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1334 const pjmedia_sdp_session *c_sdp)
1335{
1336 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001337 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001338
Benny Prijono56315612006-07-18 14:39:40 +00001339 status = pjsip_create_sdp_body(pool,
1340 pjmedia_sdp_session_clone(pool, c_sdp),
1341 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001342
Benny Prijono56315612006-07-18 14:39:40 +00001343 if (status != PJ_SUCCESS)
1344 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001345
1346 return body;
1347}
1348
1349/*
1350 * Create initial INVITE request.
1351 */
1352PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1353 pjsip_tx_data **p_tdata )
1354{
1355 pjsip_tx_data *tdata;
1356 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001357 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001358 pj_status_t status;
1359
1360 /* Verify arguments. */
1361 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1362
Benny Prijono26ff9062006-02-21 23:47:00 +00001363 /* State MUST be NULL or CONFIRMED. */
1364 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1365 inv->state == PJSIP_INV_STATE_CONFIRMED,
1366 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001367
Benny Prijono64f851e2006-02-23 13:49:28 +00001368 /* Lock dialog. */
1369 pjsip_dlg_inc_lock(inv->dlg);
1370
Benny Prijono268ca612006-02-07 12:34:11 +00001371 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001372 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001373 &tdata);
1374 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001375 goto on_return;
1376
Benny Prijono268ca612006-02-07 12:34:11 +00001377
Benny Prijono26ff9062006-02-21 23:47:00 +00001378 /* If this is the first INVITE, then copy the headers from inv_hdr.
1379 * These are the headers parsed from the request URI when the
1380 * dialog was created.
1381 */
1382 if (inv->state == PJSIP_INV_STATE_NULL) {
1383 hdr = inv->dlg->inv_hdr.next;
1384
1385 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001386 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001387 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1388 hdr = hdr->next;
1389 }
1390 }
1391
1392 /* See if we have SDP to send. */
1393 if (inv->neg) {
1394 pjmedia_sdp_neg_state neg_state;
1395
1396 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1397
1398 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1399 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1400 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1401
1402
1403 } else {
1404 has_sdp = PJ_FALSE;
1405 }
1406
Benny Prijono268ca612006-02-07 12:34:11 +00001407 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001408 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001409 const pjmedia_sdp_session *offer;
1410
1411 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono176a11f2009-04-14 11:14:51 +00001412 if (status != PJ_SUCCESS) {
1413 pjsip_tx_data_dec_ref(tdata);
Benny Prijono64f851e2006-02-23 13:49:28 +00001414 goto on_return;
Benny Prijono176a11f2009-04-14 11:14:51 +00001415 }
Benny Prijono268ca612006-02-07 12:34:11 +00001416
1417 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1418 }
1419
1420 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001421 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001422 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1423 if (hdr) {
1424 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1425 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1426 }
Benny Prijono268ca612006-02-07 12:34:11 +00001427 }
1428
1429 /* Add Supported header */
1430 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1431 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001432 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001433 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1434 }
1435
1436 /* Add Require header. */
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001437 if ((inv->options & PJSIP_INV_REQUIRE_100REL) ||
1438 (inv->options & PJSIP_INV_REQUIRE_TIMER))
1439 {
1440 pjsip_require_hdr *hreq;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001441
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001442 hreq = pjsip_require_hdr_create(tdata->pool);
1443
1444 if (inv->options & PJSIP_INV_REQUIRE_100REL)
1445 hreq->values[hreq->count++] = pj_str("100rel");
1446 if (inv->options & PJSIP_INV_REQUIRE_TIMER)
1447 hreq->values[hreq->count++] = pj_str("timer");
1448
1449 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001450 }
Benny Prijono268ca612006-02-07 12:34:11 +00001451
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001452 status = pjsip_timer_update_req(inv, tdata);
1453 if (status != PJ_SUCCESS)
1454 goto on_return;
1455
Benny Prijono268ca612006-02-07 12:34:11 +00001456 /* Done. */
1457 *p_tdata = tdata;
1458
Benny Prijono64f851e2006-02-23 13:49:28 +00001459
1460on_return:
1461 pjsip_dlg_dec_lock(inv->dlg);
1462 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001463}
1464
1465
Benny Prijono40d62b62009-08-12 17:53:47 +00001466/* Util: swap pool */
1467static void swap_pool(pj_pool_t **p1, pj_pool_t **p2)
1468{
1469 pj_pool_t *tmp = *p1;
1470 *p1 = *p2;
1471 *p2 = tmp;
1472}
1473
Benny Prijono268ca612006-02-07 12:34:11 +00001474/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001475 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001476 */
1477static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1478{
1479 pj_status_t status;
1480
1481 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1482 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1483 PJMEDIA_SDPNEG_EINSTATE);
1484
Benny Prijono40d62b62009-08-12 17:53:47 +00001485 status = pjmedia_sdp_neg_negotiate(inv->pool_prov, inv->neg, 0);
Benny Prijono95196582006-02-09 00:13:40 +00001486
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001487 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1488
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001489 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001490 (*mod_inv.cb.on_media_update)(inv, status);
1491
Benny Prijono40d62b62009-08-12 17:53:47 +00001492 /* Swap the flip-flop pool, and reset the new provisional pool */
1493 swap_pool(&inv->pool_prov, &inv->pool_active);
1494 pj_pool_reset(inv->pool_prov);
1495
Benny Prijono95196582006-02-09 00:13:40 +00001496 return status;
1497}
1498
1499/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001500 * Check in incoming message for SDP offer/answer.
1501 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001502static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1503 pjsip_transaction *tsx,
1504 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001505{
1506 struct tsx_inv_data *tsx_inv_data;
1507 static const pj_str_t str_application = { "application", 11 };
1508 static const pj_str_t str_sdp = { "sdp", 3 };
1509 pj_status_t status;
1510 pjsip_msg *msg;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001511 pjmedia_sdp_session *rem_sdp;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001512
1513 /* Check if SDP is present in the message. */
1514
1515 msg = rdata->msg_info.msg;
1516 if (msg->body == NULL) {
1517 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001518 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001519 }
1520
1521 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1522 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1523 {
1524 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001525 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001526 }
1527
Benny Prijono8fcb4332008-10-31 18:01:48 +00001528 /* Get/attach invite session's transaction data */
1529 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1530 if (tsx_inv_data == NULL) {
1531 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1532 tsx_inv_data->inv = inv;
1533 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1534 }
1535
1536 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1537 * EXCEPT if:
1538 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1539 * - the previous negotiation was done on an early media (18x) and
1540 * this response is a final/2xx response, and
1541 * - the 2xx response has different To tag than the 18x response
1542 * (i.e. the request has forked).
1543 *
1544 * The exception above is to add a rudimentary support for early media
1545 * forking (sample case: custom ringback). See this ticket for more
1546 * info: http://trac.pjsip.org/repos/ticket/657
1547 */
1548 if (tsx_inv_data->sdp_done) {
1549 pj_str_t res_tag;
1550
1551 res_tag = rdata->msg_info.to->tag;
1552
1553 /* Allow final response after SDP has been negotiated in early
1554 * media, IF this response is a final response with different
1555 * tag.
1556 */
1557 if (tsx->role == PJSIP_ROLE_UAC &&
1558 rdata->msg_info.msg->line.status.code/100 == 2 &&
1559 tsx_inv_data->done_early &&
1560 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1561 {
1562 const pjmedia_sdp_session *reoffer_sdp = NULL;
1563
1564 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1565 "after SDP negotiation has been done in early "
1566 "media. Renegotiating SDP.."));
1567
1568 /* Retrieve original SDP offer from INVITE request */
1569 reoffer_sdp = (const pjmedia_sdp_session*)
1570 tsx->last_tx->msg->body->data;
1571
1572 /* Feed the original offer to negotiator */
Benny Prijono40d62b62009-08-12 17:53:47 +00001573 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
1574 inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001575 reoffer_sdp);
1576 if (status != PJ_SUCCESS) {
1577 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1578 "forked 2xx response (err=%d)", status));
1579 return status;
1580 }
1581
1582 } else {
1583
1584 if (rdata->msg_info.msg->body) {
1585 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1586 "body is ignored"));
1587 }
1588 return PJ_SUCCESS;
1589 }
1590 }
1591
Benny Prijonoa66c7152006-02-09 01:26:14 +00001592 /* Parse the SDP body. */
1593
Benny Prijonoa1e69682007-05-11 15:14:34 +00001594 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1595 (char*)msg->body->data,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001596 msg->body->len, &rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001597 if (status == PJ_SUCCESS)
Benny Prijono8fcb4332008-10-31 18:01:48 +00001598 status = pjmedia_sdp_validate(rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001599
Benny Prijonoa66c7152006-02-09 01:26:14 +00001600 if (status != PJ_SUCCESS) {
1601 char errmsg[PJ_ERR_MSG_SIZE];
1602 pj_strerror(status, errmsg, sizeof(errmsg));
1603 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1604 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001605 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001606 }
1607
1608 /* The SDP can be an offer or answer, depending on negotiator's state */
1609
1610 if (inv->neg == NULL ||
1611 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1612 {
1613
1614 /* This is an offer. */
1615
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001616 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1617 pjsip_rx_data_get_info(rdata)));
1618
Benny Prijonoa66c7152006-02-09 01:26:14 +00001619 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001620 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001621 rem_sdp, &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001622 } else {
Benny Prijono40d62b62009-08-12 17:53:47 +00001623 status=pjmedia_sdp_neg_set_remote_offer(inv->pool_prov, inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001624 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001625 }
1626
1627 if (status != PJ_SUCCESS) {
1628 char errmsg[PJ_ERR_MSG_SIZE];
1629 pj_strerror(status, errmsg, sizeof(errmsg));
1630 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1631 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001632 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001633 }
1634
1635 /* Inform application about remote offer. */
1636
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001637 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001638
Benny Prijono8fcb4332008-10-31 18:01:48 +00001639 (*mod_inv.cb.on_rx_offer)(inv, rem_sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001640
1641 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001642
1643 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1644 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1645 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001646 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001647
1648 /* This is an answer.
1649 * Process and negotiate remote answer.
1650 */
1651
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001652 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1653 pjsip_rx_data_get_info(rdata)));
1654
Benny Prijono40d62b62009-08-12 17:53:47 +00001655 status = pjmedia_sdp_neg_set_remote_answer(inv->pool_prov, inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001656 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001657
1658 if (status != PJ_SUCCESS) {
1659 char errmsg[PJ_ERR_MSG_SIZE];
1660 pj_strerror(status, errmsg, sizeof(errmsg));
1661 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1662 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001663 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001664 }
1665
1666 /* Negotiate SDP */
1667
1668 inv_negotiate_sdp(inv);
1669
Benny Prijono8fcb4332008-10-31 18:01:48 +00001670 /* Mark this transaction has having SDP offer/answer done, and
1671 * save the reference to the To tag
1672 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001673
1674 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001675 status_code = rdata->msg_info.msg->line.status.code;
1676 tsx_inv_data->done_early = (status_code/100==1);
1677 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1678 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001679
1680 } else {
1681
1682 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1683 pjsip_rx_data_get_info(rdata),
1684 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1685 }
1686
Benny Prijono26ff9062006-02-21 23:47:00 +00001687 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001688}
1689
1690
Benny Prijono26ff9062006-02-21 23:47:00 +00001691/*
1692 * Process INVITE answer, for both initial and subsequent re-INVITE
1693 */
1694static pj_status_t process_answer( pjsip_inv_session *inv,
1695 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001696 pjsip_tx_data *tdata,
1697 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001698{
1699 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001700 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001701
Benny Prijono64f851e2006-02-23 13:49:28 +00001702 /* If local_sdp is specified, then we MUST NOT have answered the
1703 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001704 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001705 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1706
1707 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001708 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1709 local_sdp,
Benny Prijono64f851e2006-02-23 13:49:28 +00001710 &inv->neg);
1711 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1712 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1713 {
Benny Prijono40d62b62009-08-12 17:53:47 +00001714 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov, inv->neg,
Benny Prijono64f851e2006-02-23 13:49:28 +00001715 local_sdp);
1716 } else {
1717
1718 /* Can not specify local SDP at this state. */
1719 pj_assert(0);
1720 status = PJMEDIA_SDPNEG_EINSTATE;
1721 }
1722
1723 if (status != PJ_SUCCESS)
1724 return status;
1725
1726 }
1727
1728
1729 /* If SDP negotiator is ready, start negotiation. */
1730 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001731
1732 pjmedia_sdp_neg_state neg_state;
1733
Benny Prijono64f851e2006-02-23 13:49:28 +00001734 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001735 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1736 PJMEDIA_SDP_NEG_STATE_NULL;
1737
1738 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1739
1740 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1741
1742 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1743 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1744 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001745 struct tsx_inv_data *tsx_inv_data;
1746
1747 /* Get invite session's transaction data */
1748 tsx_inv_data = (struct tsx_inv_data*)
1749 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001750
1751 status = inv_negotiate_sdp(inv);
1752 if (status != PJ_SUCCESS)
1753 return status;
1754
Benny Prijono77998ce2007-06-20 10:03:46 +00001755 /* Mark this transaction has having SDP offer/answer done. */
1756 tsx_inv_data->sdp_done = 1;
1757
Benny Prijono26ff9062006-02-21 23:47:00 +00001758 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1759 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001760 }
1761
Benny Prijono64f851e2006-02-23 13:49:28 +00001762 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001763 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001764 *
1765 * Note note:
1766 * - When offer/answer has been completed in reliable 183, we MUST NOT
1767 * send SDP in 2xx response. So if we don't have SDP to send, clear
1768 * the SDP in the message body ONLY if 100rel is active in this
1769 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001770 */
1771 if (sdp) {
1772 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001773 } else {
1774 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1775 tdata->msg->body = NULL;
1776 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001777 }
1778
Benny Prijono26ff9062006-02-21 23:47:00 +00001779
1780 return PJ_SUCCESS;
1781}
1782
Benny Prijonoa66c7152006-02-09 01:26:14 +00001783
1784/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001785 * Create first response to INVITE
1786 */
1787PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1788 pjsip_rx_data *rdata,
1789 int st_code,
1790 const pj_str_t *st_text,
1791 const pjmedia_sdp_session *sdp,
1792 pjsip_tx_data **p_tdata)
1793{
1794 pjsip_tx_data *tdata;
1795 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00001796 pjsip_status_code st_code2;
Benny Prijono64f851e2006-02-23 13:49:28 +00001797
1798 /* Verify arguments. */
1799 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1800
1801 /* Must have INVITE transaction. */
1802 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1803
1804 pjsip_dlg_inc_lock(inv->dlg);
1805
1806 /* Create response */
1807 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1808 &tdata);
1809 if (status != PJ_SUCCESS)
1810 goto on_return;
1811
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001812 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00001813 status = pjsip_timer_process_req(inv, rdata, &st_code2);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001814 if (status != PJ_SUCCESS) {
1815 pj_status_t status2;
1816
Nanang Izzuddin65add622009-08-11 16:26:20 +00001817 status2 = pjsip_dlg_modify_response(inv->dlg, tdata, st_code2, NULL);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001818 if (status2 != PJ_SUCCESS) {
1819 pjsip_tx_data_dec_ref(tdata);
1820 goto on_return;
1821 }
1822 status2 = pjsip_timer_update_resp(inv, tdata);
1823 if (status2 == PJ_SUCCESS)
1824 *p_tdata = tdata;
1825 else
1826 pjsip_tx_data_dec_ref(tdata);
1827
1828 goto on_return;
1829 }
1830
Benny Prijono64f851e2006-02-23 13:49:28 +00001831 /* Process SDP in answer */
1832 status = process_answer(inv, st_code, tdata, sdp);
1833 if (status != PJ_SUCCESS) {
1834 pjsip_tx_data_dec_ref(tdata);
1835 goto on_return;
1836 }
1837
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001838 /* Save this answer */
1839 inv->last_answer = tdata;
1840 pjsip_tx_data_add_ref(inv->last_answer);
1841 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1842 pjsip_tx_data_get_info(inv->last_answer)));
1843
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001844 /* Invoke Session Timers */
1845 pjsip_timer_update_resp(inv, tdata);
1846
Benny Prijono64f851e2006-02-23 13:49:28 +00001847 *p_tdata = tdata;
1848
1849on_return:
1850 pjsip_dlg_dec_lock(inv->dlg);
1851 return status;
1852}
1853
1854
1855/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001856 * Answer initial INVITE
1857 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001858 */
1859PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1860 int st_code,
1861 const pj_str_t *st_text,
1862 const pjmedia_sdp_session *local_sdp,
1863 pjsip_tx_data **p_tdata )
1864{
1865 pjsip_tx_data *last_res;
1866 pj_status_t status;
1867
1868 /* Verify arguments. */
1869 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1870
1871 /* Must have INVITE transaction. */
1872 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1873
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001874 /* Must have created an answer before */
1875 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001876
Benny Prijono64f851e2006-02-23 13:49:28 +00001877 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001878
1879 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001880 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001881 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1882 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001883 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001884
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001885 /* For non-2xx final response, strip message body */
1886 if (st_code >= 300) {
1887 last_res->msg->body = NULL;
1888 }
Benny Prijono268ca612006-02-07 12:34:11 +00001889
Benny Prijono26ff9062006-02-21 23:47:00 +00001890 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001891 status = process_answer(inv, st_code, last_res, local_sdp);
1892 if (status != PJ_SUCCESS) {
1893 pjsip_tx_data_dec_ref(last_res);
1894 goto on_return;
1895 }
Benny Prijono268ca612006-02-07 12:34:11 +00001896
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001897 /* Invoke Session Timers */
1898 pjsip_timer_update_resp(inv, last_res);
Benny Prijono268ca612006-02-07 12:34:11 +00001899
1900 *p_tdata = last_res;
1901
Benny Prijono64f851e2006-02-23 13:49:28 +00001902on_return:
1903 pjsip_dlg_dec_lock(inv->dlg);
1904 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001905}
1906
1907
1908/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001909 * Set SDP answer.
1910 */
1911PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1912 const pjmedia_sdp_session *sdp )
1913{
1914 pj_status_t status;
1915
1916 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1917
1918 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono40d62b62009-08-12 17:53:47 +00001919 status = pjmedia_sdp_neg_set_local_answer( inv->pool_prov, inv->neg, sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001920 pjsip_dlg_dec_lock(inv->dlg);
1921
1922 return status;
1923}
1924
1925
1926/*
Benny Prijono268ca612006-02-07 12:34:11 +00001927 * End session.
1928 */
1929PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
1930 int st_code,
1931 const pj_str_t *st_text,
1932 pjsip_tx_data **p_tdata )
1933{
1934 pjsip_tx_data *tdata;
1935 pj_status_t status;
1936
1937 /* Verify arguments. */
1938 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1939
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001940 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001941 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001942
Benny Prijono268ca612006-02-07 12:34:11 +00001943 /* Create appropriate message. */
1944 switch (inv->state) {
1945 case PJSIP_INV_STATE_CALLING:
1946 case PJSIP_INV_STATE_EARLY:
1947 case PJSIP_INV_STATE_INCOMING:
1948
1949 if (inv->role == PJSIP_ROLE_UAC) {
1950
1951 /* For UAC when session has not been confirmed, create CANCEL. */
1952
1953 /* MUST have the original UAC INVITE transaction. */
1954 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
1955
1956 /* But CANCEL should only be called when we have received a
1957 * provisional response. If we haven't received any responses,
1958 * just destroy the transaction.
1959 */
1960 if (inv->invite_tsx->status_code < 100) {
1961
Benny Prijono006a4e82009-04-26 11:30:22 +00001962 /* Do not stop INVITE retransmission, see ticket #506 */
1963 //pjsip_tsx_stop_retransmit(inv->invite_tsx);
Benny Prijono1dc8be02007-05-30 04:26:40 +00001964 inv->cancelling = PJ_TRUE;
1965 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00001966 *p_tdata = NULL;
Benny Prijono006a4e82009-04-26 11:30:22 +00001967 PJ_LOG(4, (inv->obj_name, "Delaying CANCEL since no "
1968 "provisional response is received yet"));
Benny Prijonofccab712006-02-22 22:23:22 +00001969 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001970 }
1971
1972 /* The CSeq here assumes that the dialog is started with an
1973 * INVITE session. This may not be correct; dialog can be
1974 * started as SUBSCRIBE session.
1975 * So fix this!
1976 */
1977 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
1978 inv->invite_tsx->last_tx,
1979 &tdata);
Benny Prijono99b04372009-04-26 11:02:04 +00001980 if (status != PJ_SUCCESS)
1981 return status;
1982
1983 /* Set timeout for the INVITE transaction, in case UAS is not
1984 * able to respond the INVITE with 487 final response. The
1985 * timeout value is 64*T1.
1986 */
1987 pjsip_tsx_set_timeout(inv->invite_tsx, 64 * pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00001988
1989 } else {
1990
1991 /* For UAS, send a final response. */
1992 tdata = inv->invite_tsx->last_tx;
1993 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
1994
Benny Prijono26ff9062006-02-21 23:47:00 +00001995 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
1996 // st_text);
1997 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001998 }
1999 break;
2000
2001 case PJSIP_INV_STATE_CONNECTING:
2002 case PJSIP_INV_STATE_CONFIRMED:
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002003 /* End Session Timer */
2004 pjsip_timer_end_session(inv);
2005
Benny Prijono268ca612006-02-07 12:34:11 +00002006 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002007 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2008 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002009 break;
2010
2011 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00002012 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002013 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00002014
2015 default:
2016 pj_assert("!Invalid operation!");
2017 return PJ_EINVALIDOP;
2018 }
2019
2020 if (status != PJ_SUCCESS)
2021 return status;
2022
2023
2024 /* Done */
2025
Benny Prijono0606e702007-05-22 12:21:40 +00002026 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00002027 *p_tdata = tdata;
2028
2029 return PJ_SUCCESS;
2030}
2031
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002032/* Following redirection recursion, get next target from the target set and
2033 * notify user.
2034 *
2035 * Returns PJ_FALSE if recursion fails (either because there's no more target
2036 * or user rejects the recursion). If we return PJ_FALSE, caller should
2037 * disconnect the session.
2038 *
2039 * Note:
2040 * the event 'e' argument may be NULL.
2041 */
2042static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
2043 const pj_str_t *reason, pjsip_event *e)
2044{
Benny Prijono08a48b82008-11-27 12:42:07 +00002045 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002046 pjsip_target *target;
2047
2048 /* Won't redirect if the callback is not implemented. */
2049 if (mod_inv.cb.on_redirected == NULL)
2050 return PJ_FALSE;
2051
2052 if (reason == NULL)
2053 reason = pjsip_get_status_text(code);
2054
2055 /* Set status of current target */
2056 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
2057 code, reason);
2058
2059 /* Fetch next target from the target set. We only want to
2060 * process SIP/SIPS URI for now.
2061 */
2062 for (;;) {
2063 target = pjsip_target_set_get_next(&inv->dlg->target_set);
2064 if (target == NULL) {
2065 /* No more target. */
2066 return PJ_FALSE;
2067 }
2068
2069 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
2070 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
2071 {
2072 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
2073 reason = pjsip_get_status_text(code);
2074
2075 /* Mark this target as unusable and fetch next target. */
2076 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
2077 } else {
2078 /* Found a target */
2079 break;
2080 }
2081 }
2082
2083 /* We have target in 'target'. Set this target as current target
2084 * and notify callback.
2085 */
2086 pjsip_target_set_set_current(&inv->dlg->target_set, target);
2087
Benny Prijono08a48b82008-11-27 12:42:07 +00002088 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002089
2090
2091 /* Check what the application wants to do now */
2092 switch (op) {
2093 case PJSIP_REDIRECT_ACCEPT:
2094 case PJSIP_REDIRECT_STOP:
2095 /* Must increment session counter, that's the convention of the
2096 * pjsip_inv_process_redirect().
2097 */
2098 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2099
2100 /* Act on the recursion */
2101 pjsip_inv_process_redirect(inv, op, e);
2102 return PJ_TRUE;
2103
2104 case PJSIP_REDIRECT_PENDING:
2105 /* Increment session so that the dialog/session is not destroyed
2106 * while we're waiting for user confirmation.
2107 */
2108 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2109
2110 /* Also clear the invite_tsx variable, otherwise when this tsx is
2111 * terminated, it will also terminate the session.
2112 */
2113 inv->invite_tsx = NULL;
2114
2115 /* Done. The processing will continue once the application calls
2116 * pjsip_inv_process_redirect().
2117 */
2118 return PJ_TRUE;
2119
2120 case PJSIP_REDIRECT_REJECT:
2121 /* Recursively call this function again to fetch next target, if any.
2122 */
2123 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2124
2125 }
2126
2127 pj_assert(!"Should not reach here");
2128 return PJ_FALSE;
2129}
2130
2131
2132/* Process redirection/recursion */
2133PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2134 pjsip_redirect_op op,
2135 pjsip_event *e)
2136{
2137 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2138 pjsip_event usr_event;
2139 pj_status_t status = PJ_SUCCESS;
2140
2141 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2142
2143 if (e == NULL) {
2144 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2145 e = &usr_event;
2146 }
2147
2148 pjsip_dlg_inc_lock(inv->dlg);
2149
2150 /* Decrement session. That's the convention here to prevent the dialog
2151 * or session from being destroyed while we're waiting for user
2152 * confirmation.
2153 */
2154 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2155
2156 /* See what the application wants to do now */
2157 switch (op) {
2158 case PJSIP_REDIRECT_ACCEPT:
2159 /* User accept the redirection. Reset the session and resend the
2160 * INVITE request.
2161 */
2162 {
2163 pjsip_tx_data *tdata;
2164 pjsip_via_hdr *via;
2165
2166 /* Get the original INVITE request. */
2167 tdata = inv->invite_req;
2168 pjsip_tx_data_add_ref(tdata);
2169
2170 /* Restore strict route set.
2171 * See http://trac.pjsip.org/repos/ticket/492
2172 */
2173 pjsip_restore_strict_route_set(tdata);
2174
2175 /* Set target */
Benny Prijono20da7992008-12-18 16:48:43 +00002176 tdata->msg->line.req.uri = (pjsip_uri*)
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002177 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2178
2179 /* Remove branch param in Via header. */
2180 via = (pjsip_via_hdr*)
2181 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2182 via->branch_param.slen = 0;
2183
2184 /* Must invalidate the message! */
2185 pjsip_tx_data_invalidate_msg(tdata);
2186
2187 /* Reset the session */
2188 pjsip_inv_uac_restart(inv, PJ_FALSE);
2189
2190 /* (re)Send the INVITE request */
2191 status = pjsip_inv_send_msg(inv, tdata);
2192 }
2193 break;
2194
2195 case PJSIP_REDIRECT_STOP:
2196 /* User doesn't want the redirection. Disconnect the session now. */
2197 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2198 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2199
2200 /* Caller should expect that the invite session is gone now, so
2201 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2202 */
2203 break;
2204
2205 case PJSIP_REDIRECT_REJECT:
2206 /* Current target is rejected. Fetch next target if any. */
2207 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2208 inv_set_cause(inv, cancel_code,
2209 pjsip_get_status_text(cancel_code));
2210 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2211
2212 /* Tell caller that the invite session is gone now */
2213 status = PJSIP_ESESSIONTERMINATED;
2214 }
2215 break;
2216
2217
2218 case PJSIP_REDIRECT_PENDING:
2219 pj_assert(!"Should not happen");
2220 break;
2221 }
2222
2223
2224 pjsip_dlg_dec_lock(inv->dlg);
2225
2226 return status;
2227}
2228
Benny Prijono268ca612006-02-07 12:34:11 +00002229
2230/*
2231 * Create re-INVITE.
2232 */
2233PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2234 const pj_str_t *new_contact,
2235 const pjmedia_sdp_session *new_offer,
2236 pjsip_tx_data **p_tdata )
2237{
Benny Prijono26ff9062006-02-21 23:47:00 +00002238 pj_status_t status;
2239 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002240
Benny Prijono26ff9062006-02-21 23:47:00 +00002241 /* Check arguments. */
2242 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2243
2244 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002245 if (inv->invite_tsx!=NULL)
2246 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002247
2248
2249 pjsip_dlg_inc_lock(inv->dlg);
2250
2251 if (new_contact) {
2252 pj_str_t tmp;
2253 const pj_str_t STR_CONTACT = { "Contact", 7 };
2254
2255 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002256 contact_hdr = (pjsip_contact_hdr*)
2257 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002258 tmp.ptr, tmp.slen, NULL);
2259 if (!contact_hdr) {
2260 status = PJSIP_EINVALIDURI;
2261 goto on_return;
2262 }
2263 }
2264
2265
2266 if (new_offer) {
2267 if (!inv->neg) {
Benny Prijono40d62b62009-08-12 17:53:47 +00002268 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
2269 new_offer,
Benny Prijono26ff9062006-02-21 23:47:00 +00002270 &inv->neg);
2271 if (status != PJ_SUCCESS)
2272 goto on_return;
2273
2274 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2275
2276 case PJMEDIA_SDP_NEG_STATE_NULL:
2277 pj_assert(!"Unexpected SDP neg state NULL");
2278 status = PJ_EBUG;
2279 goto on_return;
2280
2281 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2282 PJ_LOG(4,(inv->obj_name,
2283 "pjsip_inv_reinvite: already have an offer, new "
2284 "offer is ignored"));
2285 break;
2286
2287 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
Benny Prijono40d62b62009-08-12 17:53:47 +00002288 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov,
2289 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002290 new_offer);
2291 if (status != PJ_SUCCESS)
2292 goto on_return;
2293 break;
2294
2295 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2296 PJ_LOG(4,(inv->obj_name,
2297 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2298 "offer is ignored"));
2299 break;
2300
2301 case PJMEDIA_SDP_NEG_STATE_DONE:
Benny Prijono40d62b62009-08-12 17:53:47 +00002302 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
2303 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002304 new_offer);
2305 if (status != PJ_SUCCESS)
2306 goto on_return;
2307 break;
2308 }
2309 }
2310
2311 if (contact_hdr)
2312 inv->dlg->local.contact = contact_hdr;
2313
2314 status = pjsip_inv_invite(inv, p_tdata);
2315
2316on_return:
2317 pjsip_dlg_dec_lock(inv->dlg);
2318 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002319}
2320
2321/*
2322 * Create UPDATE.
2323 */
2324PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2325 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002326 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002327 pjsip_tx_data **p_tdata )
2328{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002329 pjsip_contact_hdr *contact_hdr = NULL;
2330 pjsip_tx_data *tdata = NULL;
2331 pjmedia_sdp_session *sdp_copy;
2332 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002333
Benny Prijono1f7767b2007-10-03 18:28:49 +00002334 /* Verify arguments. */
2335 PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL);
2336
2337 /* Dialog must have been established */
2338 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2339 PJ_EINVALIDOP);
2340
2341 /* Invite session must not have been disconnected */
2342 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2343 PJ_EINVALIDOP);
2344
2345 /* Lock dialog. */
2346 pjsip_dlg_inc_lock(inv->dlg);
2347
2348 /* Process offer */
2349 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2350 PJ_LOG(4,(inv->dlg->obj_name,
2351 "Invalid SDP offer/answer state for UPDATE"));
2352 status = PJ_EINVALIDOP;
2353 goto on_error;
2354 }
2355
Benny Prijono60e31fc2009-04-23 11:50:25 +00002356 /* Notify negotiator about the new offer. This will fix the offer
2357 * with correct SDP origin.
2358 */
Benny Prijono40d62b62009-08-12 17:53:47 +00002359 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002360 offer);
2361 if (status != PJ_SUCCESS)
2362 goto on_error;
2363
Benny Prijono60e31fc2009-04-23 11:50:25 +00002364 /* Retrieve the "fixed" offer from negotiator */
2365 pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002366
2367 /* Update Contact if required */
2368 if (new_contact) {
2369 pj_str_t tmp;
2370 const pj_str_t STR_CONTACT = { "Contact", 7 };
2371
2372 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2373 contact_hdr = (pjsip_contact_hdr*)
2374 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2375 tmp.ptr, tmp.slen, NULL);
2376 if (!contact_hdr) {
2377 status = PJSIP_EINVALIDURI;
2378 goto on_error;
2379 }
2380
2381 inv->dlg->local.contact = contact_hdr;
2382 }
2383
2384 /* Create request */
2385 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2386 -1, &tdata);
2387 if (status != PJ_SUCCESS)
2388 goto on_error;
2389
2390 /* Attach SDP body */
2391 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2392 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2393
2394 /* Unlock dialog. */
2395 pjsip_dlg_dec_lock(inv->dlg);
2396
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002397 status = pjsip_timer_update_req(inv, tdata);
2398 if (status != PJ_SUCCESS)
2399 goto on_error;
2400
Benny Prijono1f7767b2007-10-03 18:28:49 +00002401 *p_tdata = tdata;
2402
2403 return PJ_SUCCESS;
2404
2405on_error:
2406 if (tdata)
2407 pjsip_tx_data_dec_ref(tdata);
2408
2409 /* Unlock dialog. */
2410 pjsip_dlg_dec_lock(inv->dlg);
2411
2412 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002413}
2414
2415/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002416 * Create an ACK request.
2417 */
2418PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2419 int cseq,
2420 pjsip_tx_data **p_tdata)
2421{
2422 const pjmedia_sdp_session *sdp = NULL;
2423 pj_status_t status;
2424
2425 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2426
2427 /* Lock dialog. */
2428 pjsip_dlg_inc_lock(inv->dlg);
2429
2430 /* Destroy last_ack */
2431 if (inv->last_ack) {
2432 pjsip_tx_data_dec_ref(inv->last_ack);
2433 inv->last_ack = NULL;
2434 }
2435
2436 /* Create new ACK request */
2437 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2438 cseq, &inv->last_ack);
2439 if (status != PJ_SUCCESS) {
2440 pjsip_dlg_dec_lock(inv->dlg);
2441 return status;
2442 }
2443
2444 /* See if we have pending SDP answer to send */
2445 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2446 if (sdp) {
2447 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2448 }
2449
2450 /* Keep this for subsequent response retransmission */
2451 inv->last_ack_cseq = cseq;
2452 pjsip_tx_data_add_ref(inv->last_ack);
2453
2454 /* Done */
2455 *p_tdata = inv->last_ack;
2456
2457 /* Unlock dialog. */
2458 pjsip_dlg_dec_lock(inv->dlg);
2459
2460 return PJ_SUCCESS;
2461}
2462
2463/*
Benny Prijono268ca612006-02-07 12:34:11 +00002464 * Send a request or response message.
2465 */
2466PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002467 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002468{
2469 pj_status_t status;
2470
2471 /* Verify arguments. */
2472 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2473
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002474 PJ_LOG(5,(inv->obj_name, "Sending %s",
2475 pjsip_tx_data_get_info(tdata)));
2476
Benny Prijono268ca612006-02-07 12:34:11 +00002477 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002478 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002479
Benny Prijono64158af2006-04-04 11:06:34 +00002480 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002481
Benny Prijono22e48c92008-03-20 14:40:50 +00002482 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002483 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2484 inv->invite_tsx)
2485 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002486 pjsip_tx_data_dec_ref(tdata);
2487 pjsip_dlg_dec_lock(inv->dlg);
2488 return PJ_EINVALIDOP;
2489 }
2490
2491 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002492 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002493 tsx_inv_data->inv = inv;
2494
Benny Prijono64158af2006-04-04 11:06:34 +00002495 pjsip_dlg_dec_lock(inv->dlg);
2496
2497 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2498 tsx_inv_data);
2499 if (status != PJ_SUCCESS)
2500 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002501
2502 } else {
2503 pjsip_cseq_hdr *cseq;
2504
2505 /* Can only do this to send response to original INVITE
2506 * request.
2507 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002508 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 +00002509 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002510 PJ_EINVALIDOP);
2511
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002512 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002513 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002514 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002515 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002516 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002517 }
2518
Benny Prijono268ca612006-02-07 12:34:11 +00002519 if (status != PJ_SUCCESS)
2520 return status;
2521 }
2522
2523 /* Done (?) */
2524 return PJ_SUCCESS;
2525}
2526
2527
Benny Prijono8ad55352006-02-08 11:16:05 +00002528/*
2529 * Respond to incoming CANCEL request.
2530 */
2531static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2532 pjsip_transaction *cancel_tsx,
2533 pjsip_rx_data *rdata)
2534{
2535 pjsip_tx_data *tdata;
2536 pjsip_transaction *invite_tsx;
2537 pj_str_t key;
2538 pj_status_t status;
2539
2540 /* See if we have matching INVITE server transaction: */
2541
2542 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002543 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002544 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2545
2546 if (invite_tsx == NULL) {
2547
2548 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002549 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002550 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002551 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002552 &tdata);
2553
2554 } else {
2555 /* Always answer CANCEL will 200 (OK) regardless of
2556 * the state of the INVITE transaction.
2557 */
2558 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2559 &tdata);
2560 }
2561
2562 /* See if we have created the response successfully. */
2563 if (status != PJ_SUCCESS) return;
2564
2565 /* Send the CANCEL response */
2566 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2567 if (status != PJ_SUCCESS) return;
2568
2569
2570 /* See if we need to terminate the UAS INVITE transaction
2571 * with 487 (Request Terminated) response.
2572 */
2573 if (invite_tsx && invite_tsx->status_code < 200) {
2574
2575 pj_assert(invite_tsx->last_tx != NULL);
2576
2577 tdata = invite_tsx->last_tx;
2578
2579 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002580 if (status == PJ_SUCCESS) {
2581 /* Remove the message body */
2582 tdata->msg->body = NULL;
Benny Prijono1e08e4f2009-05-13 08:57:38 +00002583 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
2584 status = pjsip_100rel_tx_response(inv, tdata);
2585 } else {
2586 status = pjsip_dlg_send_response(inv->dlg, invite_tsx,
2587 tdata);
2588 }
Benny Prijonofc8bb142007-11-08 09:56:50 +00002589 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002590 }
2591
2592 if (invite_tsx)
2593 pj_mutex_unlock(invite_tsx->mutex);
2594}
2595
2596
2597/*
2598 * Respond to incoming BYE request.
2599 */
2600static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2601 pjsip_transaction *bye_tsx,
2602 pjsip_rx_data *rdata,
2603 pjsip_event *e )
2604{
2605 pj_status_t status;
2606 pjsip_tx_data *tdata;
2607
2608 /* Respond BYE with 200: */
2609
2610 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2611 if (status != PJ_SUCCESS) return;
2612
2613 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2614 if (status != PJ_SUCCESS) return;
2615
2616 /* Terminate session: */
2617
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002618 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002619 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002620 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002621 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002622}
2623
2624/*
Benny Prijono38998232006-02-08 22:44:25 +00002625 * Respond to BYE request.
2626 */
2627static void inv_handle_bye_response( pjsip_inv_session *inv,
2628 pjsip_transaction *tsx,
2629 pjsip_rx_data *rdata,
2630 pjsip_event *e )
2631{
2632 pj_status_t status;
2633
2634 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002635 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002636 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2637 return;
2638 }
2639
2640 /* Handle 401/407 challenge. */
2641 if (tsx->status_code == 401 || tsx->status_code == 407) {
2642
2643 pjsip_tx_data *tdata;
2644
2645 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2646 rdata,
2647 tsx->last_tx,
2648 &tdata);
2649
2650 if (status != PJ_SUCCESS) {
2651
2652 /* Does not have proper credentials.
2653 * End the session anyway.
2654 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002655 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002656 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2657
2658 } else {
2659 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002660 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002661 }
2662
2663 } else {
2664
2665 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002666 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002667 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2668 }
2669
2670}
2671
2672/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002673 * Respond to incoming UPDATE request.
2674 */
2675static void inv_respond_incoming_update(pjsip_inv_session *inv,
2676 pjsip_rx_data *rdata)
2677{
2678 pjmedia_sdp_neg_state neg_state;
2679 pj_status_t status;
2680 pjsip_tx_data *tdata = NULL;
Nanang Izzuddin65add622009-08-11 16:26:20 +00002681 pjsip_status_code st_code;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002682
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002683 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00002684 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002685 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00002686 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002687 NULL, &tdata);
2688 goto on_return;
2689 }
2690
Benny Prijono1f7767b2007-10-03 18:28:49 +00002691 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2692
2693 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2694 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2695 status = pjsip_dlg_create_response(inv->dlg, rdata,
2696 PJSIP_SC_REQUEST_PENDING, NULL,
2697 &tdata);
2698 }
2699 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2700 * receive UPDATE while we haven't sent answer.
2701 */
2702 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2703 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2704 status = pjsip_dlg_create_response(inv->dlg, rdata,
2705 PJSIP_SC_INTERNAL_SERVER_ERROR,
2706 NULL, &tdata);
2707
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002708 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2709 * This is a valid scenario according to session-timer draft.
2710 */
2711 } else if (rdata->msg_info.msg->body == NULL) {
2712
2713 status = pjsip_dlg_create_response(inv->dlg, rdata,
2714 200, NULL, &tdata);
2715
Benny Prijono1f7767b2007-10-03 18:28:49 +00002716 } else {
2717 /* We receive new offer from remote */
2718 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2719
2720 /* Application MUST have supplied the answer by now.
2721 * If so, negotiate the SDP.
2722 */
2723 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2724 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2725 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2726 {
2727 /* Negotiation has failed */
2728 status = pjsip_dlg_create_response(inv->dlg, rdata,
2729 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2730 NULL, &tdata);
2731 } else {
2732 /* New media has been negotiated successfully, send 200/OK */
2733 status = pjsip_dlg_create_response(inv->dlg, rdata,
2734 PJSIP_SC_OK, NULL, &tdata);
2735 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002736 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002737 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2738 if (status == PJ_SUCCESS)
2739 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2740 }
2741 }
2742 }
2743
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002744on_return:
2745 /* Invoke Session Timers */
2746 if (status == PJ_SUCCESS)
2747 status = pjsip_timer_update_resp(inv, tdata);
2748
Benny Prijono1f7767b2007-10-03 18:28:49 +00002749 if (status != PJ_SUCCESS) {
2750 if (tdata != NULL) {
2751 pjsip_tx_data_dec_ref(tdata);
2752 tdata = NULL;
2753 }
2754 return;
2755 }
2756
2757 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2758}
2759
2760
2761/*
2762 * Handle incoming response to UAC UPDATE request.
2763 */
2764static void inv_handle_update_response( pjsip_inv_session *inv,
2765 pjsip_event *e)
2766{
2767 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2768 struct tsx_inv_data *tsx_inv_data = NULL;
2769 pj_status_t status = -1;
2770
Benny Prijono48ab2b72007-11-08 09:24:30 +00002771 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002772 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono48ab2b72007-11-08 09:24:30 +00002773 (tsx->status_code == 401 || tsx->status_code == 407)) {
2774
2775 pjsip_tx_data *tdata;
2776
2777 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2778 e->body.tsx_state.src.rdata,
2779 tsx->last_tx,
2780 &tdata);
2781
2782 if (status != PJ_SUCCESS) {
2783
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002784 /* Somehow failed. Probably it's not a good idea to terminate
2785 * the session since this is just a request within dialog. And
2786 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002787 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002788 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002789 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2790 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002791 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002792
2793 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002794 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002795 status = pjsip_inv_send_msg(inv, tdata);
2796 }
2797
2798 /* Process 2xx response */
2799 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002800 tsx->status_code/100 == 2 &&
2801 e->body.tsx_state.src.rdata->msg_info.msg->body)
2802 {
2803 status = inv_check_sdp_in_incoming_msg(inv, tsx,
2804 e->body.tsx_state.src.rdata);
2805
2806 } else {
2807 /* Get/attach invite session's transaction data */
2808 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2809 if (tsx_inv_data == NULL) {
2810 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2811 tsx_inv_data->inv = inv;
2812 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2813 }
2814 }
2815
2816 /* Otherwise if we don't get successful response, cancel
2817 * our negotiator.
2818 */
2819 if (status != PJ_SUCCESS &&
2820 pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
2821 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2822 {
2823 pjmedia_sdp_neg_cancel_offer(inv->neg);
2824
2825 /* Prevent from us cancelling different offer! */
2826 tsx_inv_data->sdp_done = PJ_TRUE;
2827 }
2828}
2829
2830
2831/*
2832 * Handle incoming reliable response.
2833 */
2834static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2835 pjsip_rx_data *rdata)
2836{
2837 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002838 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002839 pj_status_t status;
2840
2841 /* Create PRACK */
2842 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2843 if (status != PJ_SUCCESS)
2844 return;
2845
2846 /* See if we need to attach SDP answer on the PRACK request */
2847 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2848 if (sdp) {
2849 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2850 }
2851
2852 /* Send PRACK (must be using 100rel module!) */
2853 pjsip_100rel_send_prack(inv, tdata);
2854}
2855
2856
2857/*
2858 * Handle incoming PRACK.
2859 */
2860static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2861 pjsip_rx_data *rdata)
2862{
2863 pj_status_t status;
2864
2865 /* Run through 100rel module to see if we can accept this
2866 * PRACK request. The 100rel will send 200/OK to PRACK request.
2867 */
2868 status = pjsip_100rel_on_rx_prack(inv, rdata);
2869 if (status != PJ_SUCCESS)
2870 return;
2871
2872 /* Now check for SDP answer in the PRACK request */
2873 if (rdata->msg_info.msg->body) {
2874 status = inv_check_sdp_in_incoming_msg(inv,
2875 pjsip_rdata_get_tsx(rdata), rdata);
2876 } else {
2877 /* No SDP body */
2878 status = -1;
2879 }
2880
2881 /* If SDP negotiation has been successful, also mark the
2882 * SDP negotiation flag in the invite transaction to be
2883 * done too.
2884 */
2885 if (status == PJ_SUCCESS && inv->invite_tsx) {
2886 struct tsx_inv_data *tsx_inv_data;
2887
2888 /* Get/attach invite session's transaction data */
2889 tsx_inv_data = (struct tsx_inv_data*)
2890 inv->invite_tsx->mod_data[mod_inv.mod.id];
2891 if (tsx_inv_data == NULL) {
2892 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2893 struct tsx_inv_data);
2894 tsx_inv_data->inv = inv;
2895 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2896 }
2897
2898 tsx_inv_data->sdp_done = PJ_TRUE;
2899 }
2900}
2901
2902
2903/*
Benny Prijono8ad55352006-02-08 11:16:05 +00002904 * State NULL is before anything is sent/received.
2905 */
2906static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002907{
2908 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2909 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2910
2911 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2912
2913 if (tsx->method.id == PJSIP_INVITE_METHOD) {
2914
Benny Prijono64f851e2006-02-23 13:49:28 +00002915 /* Keep the initial INVITE transaction. */
2916 if (inv->invite_tsx == NULL)
2917 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00002918
Benny Prijono64f851e2006-02-23 13:49:28 +00002919 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00002920
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002921 /* Save the original INVITE request, if on_redirected() callback
2922 * is implemented. We may need to resend the INVITE if we receive
2923 * redirection response.
2924 */
2925 if (mod_inv.cb.on_redirected) {
2926 if (inv->invite_req) {
2927 pjsip_tx_data_dec_ref(inv->invite_req);
2928 inv->invite_req = NULL;
2929 }
2930 inv->invite_req = tsx->last_tx;
2931 pjsip_tx_data_add_ref(inv->invite_req);
2932 }
2933
Benny Prijono268ca612006-02-07 12:34:11 +00002934 switch (tsx->state) {
2935 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002936 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002937 break;
2938 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002939 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002940 break;
2941 }
2942
2943 } else {
2944 switch (tsx->state) {
2945 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002946 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002947 break;
Benny Prijono38998232006-02-08 22:44:25 +00002948 case PJSIP_TSX_STATE_PROCEEDING:
2949 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
2950 if (tsx->status_code > 100)
2951 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
2952 break;
Benny Prijono2285e7e2008-12-17 14:28:18 +00002953 case PJSIP_TSX_STATE_TERMINATED:
2954 /* there is a failure in sending response. */
2955 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2956 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2957 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002958 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002959 inv_on_state_incoming(inv, e);
2960 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002961 }
2962 }
2963
2964 } else {
2965 pj_assert(!"Unexpected transaction type");
2966 }
2967}
2968
Benny Prijono8ad55352006-02-08 11:16:05 +00002969/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002970 * Generic UAC transaction handler:
2971 * - resend request on 401 or 407 response.
2972 * - terminate dialog on 408 and 481 response.
2973 */
2974static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
2975 pjsip_event *e)
2976{
2977 /* RFC 3261 Section 12.2.1.2:
2978 * If the response for a request within a dialog is a 481
2979 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
2980 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
2981 * no response at all is received for the request (the client
2982 * transaction would inform the TU about the timeout.)
2983 *
2984 * For INVITE initiated dialogs, terminating the dialog consists of
2985 * sending a BYE.
2986 *
2987 * Note:
2988 * according to X, this should terminate dialog usage only, not the
2989 * dialog.
2990 */
2991 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2992
2993 pj_assert(tsx->role == PJSIP_UAC_ROLE);
2994
2995 /* Note that 481 response to CANCEL does not terminate dialog usage,
2996 * but only the transaction.
2997 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00002998 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
2999 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003000 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00003001 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3002 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
3003 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003004 {
3005 pjsip_tx_data *bye;
3006 pj_status_t status;
3007
3008 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3009 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3010
3011 /* Send BYE */
3012 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
3013 -1, &bye);
3014 if (status == PJ_SUCCESS) {
3015 pjsip_inv_send_msg(inv, bye);
3016 }
3017
3018 return PJ_TRUE; /* Handled */
3019
3020 }
3021 /* Handle 401/407 challenge. */
3022 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3023 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
3024 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
3025 {
3026
3027 pjsip_tx_data *tdata;
3028 pj_status_t status;
3029
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003030 if (tsx->method.id == PJSIP_INVITE_METHOD)
3031 inv->invite_tsx = NULL;
3032
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003033 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
3034 e->body.tsx_state.src.rdata,
3035 tsx->last_tx, &tdata);
3036
3037 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003038 /* Somehow failed. Probably it's not a good idea to terminate
3039 * the session since this is just a request within dialog. And
3040 * even if we terminate we should send BYE.
3041 */
3042 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003043 inv_set_cause(inv, PJSIP_SC_OK, NULL);
3044 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003045 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003046
3047 } else {
3048 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003049 status = pjsip_inv_send_msg(inv, tdata);
3050 }
3051
3052 return PJ_TRUE; /* Handled */
3053
3054 } else {
3055 return PJ_FALSE; /* Unhandled */
3056 }
3057}
3058
3059
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003060/* Handle call rejection, especially with regard to processing call
3061 * redirection. We need to handle the following scenarios:
3062 * - 3xx response is received -- see if on_redirected() callback is
3063 * implemented. If so, add the Contact URIs in the response to the
3064 * target set and notify user.
3065 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
3066 * if so fetch the next target if any and notify the on_redirected()
3067 * callback.
3068 * - for other cases -- disconnect the session.
3069 */
3070static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
3071{
3072 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3073 pj_status_t status;
3074
3075 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
3076
3077 if (mod_inv.cb.on_redirected == NULL) {
3078
3079 /* Redirection callback is not implemented, disconnect the
3080 * call.
3081 */
3082 goto terminate_session;
3083
3084 } else {
3085 const pjsip_msg *res_msg;
3086
3087 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
3088
3089 /* Gather all Contact URI's in the response and add them
3090 * to target set. The function will take care of removing
3091 * duplicate URI's.
3092 */
3093 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
3094 inv->dlg->pool, res_msg);
3095
3096 /* Recurse to alternate targets if application allows us */
3097 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3098 {
3099 /* Recursion fails, terminate session now */
3100 goto terminate_session;
3101 }
3102
3103 /* Done */
3104 }
3105
3106 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
3107 !inv->cancelling)
3108 {
3109
3110 /* Handle authentication failure:
3111 * Resend the request with Authorization header.
3112 */
3113 pjsip_tx_data *tdata;
3114
3115 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
3116 e->body.tsx_state.src.rdata,
3117 tsx->last_tx,
3118 &tdata);
3119
3120 if (status != PJ_SUCCESS) {
3121
3122 /* Does not have proper credentials. If we are currently
3123 * recursing, try the next target. Otherwise end the session.
3124 */
3125 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3126 {
3127 /* Recursion fails, terminate session now */
3128 goto terminate_session;
3129 }
3130
3131 } else {
3132
3133 /* Restart session. */
3134 pjsip_inv_uac_restart(inv, PJ_FALSE);
3135
3136 /* Send the request. */
3137 status = pjsip_inv_send_msg(inv, tdata);
3138 }
3139
3140 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3141 /* Global error */
3142 goto terminate_session;
3143
3144 } else {
3145 /* See if we have alternate target to try */
3146 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3147 /* Recursion fails, terminate session now */
3148 goto terminate_session;
3149 }
3150 }
3151 return;
3152
3153terminate_session:
3154 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3155 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3156}
3157
3158
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003159/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003160 * State CALLING is after sending initial INVITE request but before
3161 * any response (with tag) is received.
3162 */
3163static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003164{
3165 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3166 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003167 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003168
3169 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3170
Benny Prijono8ad55352006-02-08 11:16:05 +00003171 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003172
3173 switch (tsx->state) {
3174
Benny Prijono64f851e2006-02-23 13:49:28 +00003175 case PJSIP_TSX_STATE_CALLING:
3176 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3177 break;
3178
Benny Prijono268ca612006-02-07 12:34:11 +00003179 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003180 if (inv->pending_cancel) {
3181 pjsip_tx_data *cancel;
3182
3183 inv->pending_cancel = PJ_FALSE;
3184
3185 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3186 if (status == PJ_SUCCESS && cancel)
3187 status = pjsip_inv_send_msg(inv, cancel);
3188 }
3189
Benny Prijono268ca612006-02-07 12:34:11 +00003190 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003191
Benny Prijono8ad55352006-02-08 11:16:05 +00003192 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003193
3194 inv_check_sdp_in_incoming_msg(inv, tsx,
3195 e->body.tsx_state.src.rdata);
3196
Benny Prijono1f7767b2007-10-03 18:28:49 +00003197 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3198 inv_handle_incoming_reliable_response(
3199 inv, e->body.tsx_state.src.rdata);
3200 }
3201
Benny Prijono268ca612006-02-07 12:34:11 +00003202 } else {
3203 /* Ignore 100 (Trying) response, as it doesn't change
3204 * session state. It only ceases retransmissions.
3205 */
3206 }
3207 break;
3208
3209 case PJSIP_TSX_STATE_COMPLETED:
3210 if (tsx->status_code/100 == 2) {
3211
3212 /* This should not happen.
3213 * When transaction receives 2xx, it should be terminated
3214 */
3215 pj_assert(0);
Benny Prijono8ad55352006-02-08 11:16:05 +00003216 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003217
3218 inv_check_sdp_in_incoming_msg(inv, tsx,
3219 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003220
3221 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003222 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003223 }
3224 break;
3225
3226 case PJSIP_TSX_STATE_TERMINATED:
3227 /* INVITE transaction can be terminated either because UAC
3228 * transaction received 2xx response or because of transport
3229 * error.
3230 */
3231 if (tsx->status_code/100 == 2) {
3232 /* This must be receipt of 2xx response */
3233
3234 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003235 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003236
Benny Prijonoa66c7152006-02-09 01:26:14 +00003237 inv_check_sdp_in_incoming_msg(inv, tsx,
3238 e->body.tsx_state.src.rdata);
3239
Benny Prijono268ca612006-02-07 12:34:11 +00003240 /* Send ACK */
3241 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3242
Benny Prijonod5f9f422007-11-25 04:40:07 +00003243 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003244
Benny Prijono268ca612006-02-07 12:34:11 +00003245 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003246 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003247 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003248 }
3249 break;
3250
Benny Prijono34a404e2006-02-09 14:38:30 +00003251 default:
3252 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003253 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003254
Benny Prijono1f7767b2007-10-03 18:28:49 +00003255 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003256 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003257 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003258 * Transaction Does Not Exist), 408, or when it's timed out. In these
3259 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003260 * Note that 481 response to CANCEL does not terminate dialog usage,
3261 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003262 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003263 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3264 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003265 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3266 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003267 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003268 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003269 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003270 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3271 }
Benny Prijono268ca612006-02-07 12:34:11 +00003272 }
3273}
3274
Benny Prijono8ad55352006-02-08 11:16:05 +00003275/*
3276 * State INCOMING is after we received the request, but before
3277 * responses with tag are sent.
3278 */
3279static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003280{
3281 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3282 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3283
3284 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3285
Benny Prijono8ad55352006-02-08 11:16:05 +00003286 if (tsx == inv->invite_tsx) {
3287
3288 /*
3289 * Handle the INVITE state transition.
3290 */
3291
Benny Prijono268ca612006-02-07 12:34:11 +00003292 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003293
Benny Prijono64f851e2006-02-23 13:49:28 +00003294 case PJSIP_TSX_STATE_TRYING:
3295 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3296 break;
3297
Benny Prijono268ca612006-02-07 12:34:11 +00003298 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003299 /*
3300 * Transaction sent provisional response.
3301 */
Benny Prijono268ca612006-02-07 12:34:11 +00003302 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003303 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003304 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003305
Benny Prijono268ca612006-02-07 12:34:11 +00003306 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003307 /*
3308 * Transaction sent final response.
3309 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003310 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003311 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003312 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003313 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003314 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003315 }
Benny Prijono268ca612006-02-07 12:34:11 +00003316 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003317
Benny Prijono268ca612006-02-07 12:34:11 +00003318 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003319 /*
3320 * This happens on transport error (e.g. failed to send
3321 * response)
3322 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003323 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003324 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003325 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003326
Benny Prijono268ca612006-02-07 12:34:11 +00003327 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003328 pj_assert(!"Unexpected INVITE state");
3329 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003330 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003331
3332 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3333 tsx->role == PJSIP_ROLE_UAS &&
3334 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3335 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3336 {
3337
3338 /*
3339 * Handle incoming CANCEL request.
3340 */
3341
3342 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3343
Benny Prijono268ca612006-02-07 12:34:11 +00003344 }
3345}
3346
Benny Prijono8ad55352006-02-08 11:16:05 +00003347/*
3348 * State EARLY is for both UAS and UAC, after response with To tag
3349 * is sent/received.
3350 */
3351static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003352{
3353 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3354 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3355
3356 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3357
Benny Prijono8ad55352006-02-08 11:16:05 +00003358 if (tsx == inv->invite_tsx) {
3359
3360 /*
3361 * Handle the INVITE state progress.
3362 */
Benny Prijono268ca612006-02-07 12:34:11 +00003363
3364 switch (tsx->state) {
3365
3366 case PJSIP_TSX_STATE_PROCEEDING:
3367 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003368 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003369
3370 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3371 inv_check_sdp_in_incoming_msg(inv, tsx,
3372 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003373
3374 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3375 inv_handle_incoming_reliable_response(
3376 inv, e->body.tsx_state.src.rdata);
3377 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003378 }
Benny Prijono268ca612006-02-07 12:34:11 +00003379 break;
3380
3381 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003382 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003383 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003384 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3385 inv_check_sdp_in_incoming_msg(inv, tsx,
3386 e->body.tsx_state.src.rdata);
3387 }
3388
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003389 } else if (tsx->role == PJSIP_ROLE_UAC) {
3390
3391 handle_uac_call_rejection(inv, e);
3392
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003393 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003394 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003395 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003396 }
Benny Prijono268ca612006-02-07 12:34:11 +00003397 break;
3398
Benny Prijonof3195072006-02-14 21:15:30 +00003399 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003400 /* For some reason can go here (maybe when ACK for 2xx has
3401 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003402
Benny Prijono268ca612006-02-07 12:34:11 +00003403 case PJSIP_TSX_STATE_TERMINATED:
3404 /* INVITE transaction can be terminated either because UAC
3405 * transaction received 2xx response or because of transport
3406 * error.
3407 */
3408 if (tsx->status_code/100 == 2) {
3409
3410 /* This must be receipt of 2xx response */
3411
3412 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003413 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003414
Benny Prijonoa66c7152006-02-09 01:26:14 +00003415 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3416 inv_check_sdp_in_incoming_msg(inv, tsx,
3417 e->body.tsx_state.src.rdata);
3418 }
3419
Benny Prijono268ca612006-02-07 12:34:11 +00003420 /* if UAC, send ACK and move state to confirmed. */
3421 if (tsx->role == PJSIP_ROLE_UAC) {
3422 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3423
Benny Prijonod5f9f422007-11-25 04:40:07 +00003424 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003425 }
3426
3427 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003428 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003429 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003430 }
3431 break;
3432
3433 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003434 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003435 }
3436
Benny Prijono8ad55352006-02-08 11:16:05 +00003437 } else if (inv->role == PJSIP_ROLE_UAS &&
3438 tsx->role == PJSIP_ROLE_UAS &&
3439 tsx->method.id == PJSIP_CANCEL_METHOD &&
3440 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3441 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3442 {
Benny Prijono268ca612006-02-07 12:34:11 +00003443
Benny Prijono8ad55352006-02-08 11:16:05 +00003444 /*
3445 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003446 */
3447
Benny Prijono8ad55352006-02-08 11:16:05 +00003448 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3449
Benny Prijono1f7767b2007-10-03 18:28:49 +00003450 } else if (tsx->role == PJSIP_ROLE_UAS &&
3451 tsx->state == PJSIP_TSX_STATE_TRYING &&
3452 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003453 {
3454 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003455 * Handle incoming UPDATE
3456 */
3457 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3458
3459
3460 } else if (tsx->role == PJSIP_ROLE_UAC &&
3461 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3462 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3463 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3464 {
3465 /*
3466 * Handle response to outgoing UPDATE request.
3467 */
3468 inv_handle_update_response(inv, e);
3469
3470 } else if (tsx->role == PJSIP_ROLE_UAS &&
3471 tsx->state == PJSIP_TSX_STATE_TRYING &&
3472 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3473 {
3474 /*
3475 * Handle incoming PRACK
3476 */
3477 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3478
3479 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003480
3481 /* Generic handling for UAC tsx completion */
3482 handle_uac_tsx_response(inv, e);
Benny Prijono7efa2d62009-04-27 12:50:16 +00003483
3484 } else if (tsx->role == PJSIP_ROLE_UAS &&
3485 tsx->method.id == PJSIP_BYE_METHOD &&
3486 tsx->status_code < 200 &&
3487 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3488 {
3489 /* Received BYE before the 2xx/OK response to INVITE.
3490 * Assume that the 2xx/OK response is lost and the BYE
3491 * arrives earlier.
3492 */
3493 inv_respond_incoming_bye(inv, tsx, e->body.tsx_state.src.rdata, e);
3494
3495 /* Set timer just in case we will never get the final response
3496 * for INVITE.
3497 */
3498 pjsip_tsx_set_timeout(inv->invite_tsx, 64*pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00003499 }
3500}
3501
Benny Prijono8ad55352006-02-08 11:16:05 +00003502/*
3503 * State CONNECTING is after 2xx response to INVITE is sent/received.
3504 */
3505static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003506{
3507 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3508 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3509
3510 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3511
Benny Prijono8ad55352006-02-08 11:16:05 +00003512 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003513
Benny Prijono8ad55352006-02-08 11:16:05 +00003514 /*
3515 * Handle INVITE state progression.
3516 */
Benny Prijono268ca612006-02-07 12:34:11 +00003517 switch (tsx->state) {
3518
3519 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003520 /* It can only go here if incoming ACK request has the same Via
3521 * branch parameter as the INVITE transaction.
3522 */
3523 if (tsx->status_code/100 == 2) {
3524 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3525 inv_check_sdp_in_incoming_msg(inv, tsx,
3526 e->body.tsx_state.src.rdata);
3527 }
3528
Benny Prijono38998232006-02-08 22:44:25 +00003529 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003530 }
Benny Prijono268ca612006-02-07 12:34:11 +00003531 break;
3532
3533 case PJSIP_TSX_STATE_TERMINATED:
3534 /* INVITE transaction can be terminated either because UAC
3535 * transaction received 2xx response or because of transport
3536 * error.
3537 */
3538 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003539 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003540 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003541 }
3542 break;
3543
3544 case PJSIP_TSX_STATE_DESTROYED:
3545 /* Do nothing. */
3546 break;
3547
3548 default:
3549 pj_assert(!"Unexpected state");
3550 }
3551
Benny Prijono8ad55352006-02-08 11:16:05 +00003552 } else if (tsx->role == PJSIP_ROLE_UAS &&
3553 tsx->method.id == PJSIP_BYE_METHOD &&
3554 tsx->status_code < 200 &&
3555 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3556 {
3557
3558 /*
3559 * Handle incoming BYE.
3560 */
3561
3562 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3563
Benny Prijono38998232006-02-08 22:44:25 +00003564 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3565 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003566 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3567 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003568 {
3569
3570 /*
3571 * Outgoing BYE
3572 */
3573 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3574
Benny Prijono268ca612006-02-07 12:34:11 +00003575 }
Benny Prijono70127222006-07-02 14:53:05 +00003576 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3577 tsx->role == PJSIP_ROLE_UAS &&
3578 tsx->status_code < 200 &&
3579 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3580 {
Benny Prijono38998232006-02-08 22:44:25 +00003581
Benny Prijono70127222006-07-02 14:53:05 +00003582 /*
3583 * Handle strandled incoming CANCEL.
3584 */
3585 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3586 pjsip_tx_data *tdata;
3587 pj_status_t status;
3588
3589 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3590 if (status != PJ_SUCCESS) return;
3591
3592 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3593 if (status != PJ_SUCCESS) return;
3594
Benny Prijono1f7767b2007-10-03 18:28:49 +00003595 } else if (tsx->role == PJSIP_ROLE_UAS &&
3596 tsx->state == PJSIP_TSX_STATE_TRYING &&
3597 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3598 {
3599 /*
3600 * Handle incoming UPDATE
3601 */
3602 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3603
3604
3605 } else if (tsx->role == PJSIP_ROLE_UAC &&
3606 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3607 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3608 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3609 {
3610 /*
3611 * Handle response to outgoing UPDATE request.
3612 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003613 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003614 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003615
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 Prijono87402382008-02-21 19:28:21 +00003626
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003627 /* Generic handling for UAC tsx completion */
3628 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003629 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003630
Benny Prijono268ca612006-02-07 12:34:11 +00003631}
3632
Benny Prijono8ad55352006-02-08 11:16:05 +00003633/*
3634 * State CONFIRMED is after ACK is sent/received.
3635 */
3636static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003637{
3638 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3639 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3640
3641 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3642
Benny Prijono268ca612006-02-07 12:34:11 +00003643
Benny Prijono8ad55352006-02-08 11:16:05 +00003644 if (tsx->method.id == PJSIP_BYE_METHOD &&
3645 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003646 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3647 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003648 {
Benny Prijono38998232006-02-08 22:44:25 +00003649
Benny Prijono8ad55352006-02-08 11:16:05 +00003650 /*
Benny Prijono38998232006-02-08 22:44:25 +00003651 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003652 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003653
Benny Prijonoa66c7152006-02-09 01:26:14 +00003654 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003655
Benny Prijono8ad55352006-02-08 11:16:05 +00003656 }
3657 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3658 tsx->role == PJSIP_ROLE_UAS &&
3659 tsx->status_code < 200 &&
3660 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3661 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003662
Benny Prijono8ad55352006-02-08 11:16:05 +00003663 /*
3664 * Handle incoming BYE.
3665 */
Benny Prijono268ca612006-02-07 12:34:11 +00003666
Benny Prijono8ad55352006-02-08 11:16:05 +00003667 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3668
Benny Prijono268ca612006-02-07 12:34:11 +00003669 }
Benny Prijono70127222006-07-02 14:53:05 +00003670 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3671 tsx->role == PJSIP_ROLE_UAS &&
3672 tsx->status_code < 200 &&
3673 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3674 {
3675
3676 /*
3677 * Handle strandled incoming CANCEL.
3678 */
3679 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3680 pjsip_tx_data *tdata;
3681 pj_status_t status;
3682
3683 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3684 if (status != PJ_SUCCESS) return;
3685
3686 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3687 if (status != PJ_SUCCESS) return;
3688
3689 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003690 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3691 tsx->role == PJSIP_ROLE_UAS)
3692 {
3693
3694 /*
3695 * Handle incoming re-INVITE
3696 */
3697 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3698
3699 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3700 pjsip_tx_data *tdata;
3701 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00003702 pjsip_status_code st_code;
Benny Prijono26ff9062006-02-21 23:47:00 +00003703
3704 /* Check if we have INVITE pending. */
3705 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003706 pj_str_t reason;
3707
3708 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003709
3710 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003711 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3712 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003713 if (status != PJ_SUCCESS)
3714 return;
3715
3716 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3717
3718
3719 return;
3720 }
3721
3722 /* Save the invite transaction. */
3723 inv->invite_tsx = tsx;
3724
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003725 /* Process session timers headers in the re-INVITE */
Nanang Izzuddin65add622009-08-11 16:26:20 +00003726 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003727 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00003728 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
3729 NULL, &tdata);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003730 if (status != PJ_SUCCESS)
3731 return;
3732
3733 pjsip_timer_update_resp(inv, tdata);
3734 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3735 return;
3736 }
3737
Benny Prijono26ff9062006-02-21 23:47:00 +00003738 /* Process SDP in incoming message. */
3739 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3740
3741 if (status != PJ_SUCCESS) {
3742
3743 /* Not Acceptable */
3744 const pjsip_hdr *accept;
3745
3746 status = pjsip_dlg_create_response(inv->dlg, rdata,
3747 488, NULL, &tdata);
3748 if (status != PJ_SUCCESS)
3749 return;
3750
3751
3752 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3753 NULL);
3754 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003755 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003756 pjsip_hdr_clone(tdata->pool, accept));
3757 }
3758
3759 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3760
3761 return;
3762 }
3763
3764 /* Create 2xx ANSWER */
3765 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3766 if (status != PJ_SUCCESS)
3767 return;
3768
Benny Prijono7d910092007-06-20 04:19:46 +00003769 /* If the INVITE request has SDP body, send answer.
3770 * Otherwise generate offer from local active SDP.
3771 */
3772 if (rdata->msg_info.msg->body != NULL) {
3773 status = process_answer(inv, 200, tdata, NULL);
3774 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003775 /* INVITE does not have SDP.
3776 * If on_create_offer() callback is implemented, ask app.
3777 * to generate an offer, otherwise just send active local
3778 * SDP to signal that nothing gets modified.
3779 */
3780 pjmedia_sdp_session *sdp = NULL;
3781
3782 if (mod_inv.cb.on_create_offer) {
3783 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3784 if (sdp) {
Benny Prijono60e31fc2009-04-23 11:50:25 +00003785 /* Notify negotiator about the new offer. This will
3786 * fix the offer with correct SDP origin.
3787 */
Benny Prijono40d62b62009-08-12 17:53:47 +00003788 status =
3789 pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
3790 inv->neg,
3791 sdp);
Benny Prijono60e31fc2009-04-23 11:50:25 +00003792
3793 /* Retrieve the "fixed" offer from negotiator */
Benny Prijonoc8fe3df2009-04-29 20:56:57 +00003794 if (status==PJ_SUCCESS) {
3795 const pjmedia_sdp_session *lsdp = NULL;
3796 pjmedia_sdp_neg_get_neg_local(inv->neg, &lsdp);
3797 sdp = (pjmedia_sdp_session*)lsdp;
3798 }
Benny Prijono77998ce2007-06-20 10:03:46 +00003799 }
3800 }
3801
3802 if (sdp == NULL) {
3803 const pjmedia_sdp_session *active_sdp = NULL;
Benny Prijono40d62b62009-08-12 17:53:47 +00003804 status = pjmedia_sdp_neg_send_local_offer(inv->pool_prov,
Benny Prijono77998ce2007-06-20 10:03:46 +00003805 inv->neg,
3806 &active_sdp);
3807 if (status == PJ_SUCCESS)
3808 sdp = (pjmedia_sdp_session*) active_sdp;
3809 }
3810
3811 if (sdp) {
3812 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003813 }
3814 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003815
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003816 if (status != PJ_SUCCESS) {
3817 /*
3818 * SDP negotiation has failed.
3819 */
3820 pj_status_t rc;
3821 pj_str_t reason;
3822
3823 /* Delete the 2xx answer */
3824 pjsip_tx_data_dec_ref(tdata);
3825
3826 /* Create 500 response */
3827 reason = pj_str("SDP negotiation failed");
3828 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3829 &tdata);
3830 if (rc == PJ_SUCCESS) {
3831 pjsip_warning_hdr *w;
3832 const pj_str_t *endpt_name;
3833
3834 endpt_name = pjsip_endpt_name(dlg->endpt);
3835 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3836 endpt_name,
3837 status);
3838 if (w)
3839 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3840
3841 pjsip_inv_send_msg(inv, tdata);
3842 }
3843 return;
3844 }
3845
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003846 /* Invoke Session Timers */
3847 pjsip_timer_update_resp(inv, tdata);
3848
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003849 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003850 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003851
Benny Prijono7d910092007-06-20 04:19:46 +00003852 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
3853 /* This is the case where ACK has the same branch as
3854 * the INVITE request.
3855 */
3856 if (tsx->status_code/100 == 2 &&
3857 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3858 {
3859 inv_check_sdp_in_incoming_msg(inv, tsx,
3860 e->body.tsx_state.src.rdata);
3861 }
3862
Benny Prijono26ff9062006-02-21 23:47:00 +00003863 }
3864
3865 }
3866 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3867 tsx->role == PJSIP_ROLE_UAC)
3868 {
Benny Prijono22e48c92008-03-20 14:40:50 +00003869
Benny Prijono26ff9062006-02-21 23:47:00 +00003870 /*
3871 * Handle outgoing re-INVITE
3872 */
Benny Prijono22e48c92008-03-20 14:40:50 +00003873 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
3874
Benny Prijono61fc5e62008-06-25 18:35:31 +00003875 /* Must not have other pending INVITE transaction */
3876 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
3877
Benny Prijono22e48c92008-03-20 14:40:50 +00003878 /* Save pending invite transaction */
3879 inv->invite_tsx = tsx;
3880
3881 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
3882 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00003883 {
3884
3885 /* Re-INVITE was accepted. */
3886
3887 /* Process SDP */
3888 inv_check_sdp_in_incoming_msg(inv, tsx,
3889 e->body.tsx_state.src.rdata);
3890
3891 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00003892 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003893
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003894 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00003895
3896 /* Handle response that terminates dialog */
3897 /* Nothing to do (already handled) */
3898
Benny Prijono77998ce2007-06-20 10:03:46 +00003899 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
3900
3901 pjmedia_sdp_neg_state neg_state;
3902
3903 /* Outgoing INVITE transaction has failed, cancel SDP nego */
3904 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
3905 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
3906 pjmedia_sdp_neg_cancel_offer(inv->neg);
3907 }
Benny Prijonoe641a742009-05-01 12:01:28 +00003908
3909 if (tsx == inv->invite_tsx)
3910 inv->invite_tsx = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00003911 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003912
3913 } else if (tsx->role == PJSIP_ROLE_UAS &&
3914 tsx->state == PJSIP_TSX_STATE_TRYING &&
3915 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3916 {
3917 /*
3918 * Handle incoming UPDATE
3919 */
3920 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3921
3922 } else if (tsx->role == PJSIP_ROLE_UAC &&
3923 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3924 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3925 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3926 {
3927 /*
3928 * Handle response to outgoing UPDATE request.
3929 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003930 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003931 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003932
3933 } else if (tsx->role == PJSIP_ROLE_UAS &&
3934 tsx->state == PJSIP_TSX_STATE_TRYING &&
3935 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3936 {
3937 /*
3938 * Handle strandled incoming PRACK
3939 */
3940 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3941
3942 } else if (tsx->role == PJSIP_ROLE_UAC) {
3943 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003944 * Handle 401/407/408/481 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00003945 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003946 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003947 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003948
Benny Prijono268ca612006-02-07 12:34:11 +00003949}
3950
Benny Prijono8ad55352006-02-08 11:16:05 +00003951/*
3952 * After session has been terminated, but before dialog is destroyed
3953 * (because dialog has other usages, or because dialog is waiting for
3954 * the last transaction to terminate).
3955 */
3956static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003957{
Benny Prijono8ad55352006-02-08 11:16:05 +00003958 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3959 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00003960
Benny Prijono8ad55352006-02-08 11:16:05 +00003961 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3962
Benny Prijono70127222006-07-02 14:53:05 +00003963 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00003964 tsx->status_code < 200 &&
3965 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3966 {
Benny Prijono70127222006-07-02 14:53:05 +00003967 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00003968
3969 /*
Benny Prijono70127222006-07-02 14:53:05 +00003970 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00003971 */
Benny Prijono70127222006-07-02 14:53:05 +00003972 if (tsx->method.id == PJSIP_BYE_METHOD) {
3973 inv_respond_incoming_bye( inv, tsx, rdata, e );
3974 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
3975 /*
3976 * Respond CANCEL with 200/OK too.
3977 */
3978 pjsip_tx_data *tdata;
3979 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00003980
Benny Prijono70127222006-07-02 14:53:05 +00003981 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3982 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00003983
Benny Prijono70127222006-07-02 14:53:05 +00003984 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3985 if (status != PJ_SUCCESS) return;
3986
3987 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00003988
3989 } else if (tsx->role == PJSIP_ROLE_UAC) {
3990 /*
3991 * Handle 401/407/408/481 response
3992 */
3993 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00003994 }
Benny Prijono268ca612006-02-07 12:34:11 +00003995}
3996