blob: a54a5f364d7c722b94902a6e908b47ad2efa8322 [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>
Benny Prijono268ca612006-02-07 12:34:11 +000022#include <pjsip/sip_module.h>
23#include <pjsip/sip_endpoint.h>
24#include <pjsip/sip_event.h>
25#include <pjsip/sip_transaction.h>
26#include <pjmedia/sdp.h>
27#include <pjmedia/sdp_neg.h>
Benny Prijono95196582006-02-09 00:13:40 +000028#include <pjmedia/errno.h>
Benny Prijono268ca612006-02-07 12:34:11 +000029#include <pj/string.h>
30#include <pj/pool.h>
31#include <pj/assert.h>
Benny Prijono8ad55352006-02-08 11:16:05 +000032#include <pj/os.h>
Benny Prijonoa66c7152006-02-09 01:26:14 +000033#include <pj/log.h>
34
Benny Prijono1f7767b2007-10-03 18:28:49 +000035/*
36 * Note on offer/answer:
37 *
38 * The offer/answer framework in this implementation assumes the occurence
39 * of SDP in a particular request/response according to this table:
40
41 offer answer Note:
42 ========================================================================
43 INVITE X INVITE may contain offer
44 18x/INVITE X X Response may contain offer or answer
45 2xx/INVITE X X Response may contain offer or answer
46 ACK X ACK may contain answer
47
48 PRACK X PRACK can only contain answer
49 2xx/PRACK Response may not have offer nor answer
50
51 UPDATE X UPDATE may only contain offer
52 2xx/UPDATE X Response may only contain answer
53 ========================================================================
54
55 *
56 */
Benny Prijono268ca612006-02-07 12:34:11 +000057
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000058#define THIS_FILE "sip_inv.c"
Benny Prijono268ca612006-02-07 12:34:11 +000059
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000060static const char *inv_state_names[] =
61{
Benny Prijono4be63b52006-11-25 14:50:25 +000062 "NULL",
63 "CALLING",
64 "INCOMING",
65 "EARLY",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000066 "CONNECTING",
Benny Prijonoc5055702007-01-13 23:20:18 +000067 "CONFIRMED",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000068 "DISCONNCTD",
69 "TERMINATED",
70};
71
Benny Prijono1f7767b2007-10-03 18:28:49 +000072/* UPDATE method */
73const pjsip_method pjsip_update_method =
74{
75 PJSIP_OTHER_METHOD,
76 { "UPDATE", 6 }
77};
78
Benny Prijono268ca612006-02-07 12:34:11 +000079/*
80 * Static prototypes.
81 */
82static pj_status_t mod_inv_load(pjsip_endpoint *endpt);
83static pj_status_t mod_inv_unload(void);
84static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata);
85static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata);
86static void mod_inv_on_tsx_state(pjsip_transaction*, pjsip_event*);
87
Benny Prijono8ad55352006-02-08 11:16:05 +000088static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e);
89static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e);
90static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e);
91static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e);
92static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e);
93static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e);
94static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e);
Benny Prijono268ca612006-02-07 12:34:11 +000095
Benny Prijono7d910092007-06-20 04:19:46 +000096static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
97 pjsip_transaction *tsx,
98 pjsip_rx_data *rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +000099static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv );
100static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
101 const pjmedia_sdp_session *c_sdp);
Benny Prijono7d910092007-06-20 04:19:46 +0000102static pj_status_t process_answer( pjsip_inv_session *inv,
103 int st_code,
104 pjsip_tx_data *tdata,
105 const pjmedia_sdp_session *local_sdp);
106
Benny Prijono8ad55352006-02-08 11:16:05 +0000107static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
Benny Prijono268ca612006-02-07 12:34:11 +0000108{
109 &inv_on_state_null,
110 &inv_on_state_calling,
111 &inv_on_state_incoming,
112 &inv_on_state_early,
113 &inv_on_state_connecting,
114 &inv_on_state_confirmed,
115 &inv_on_state_disconnected,
Benny Prijono268ca612006-02-07 12:34:11 +0000116};
117
118static struct mod_inv
119{
120 pjsip_module mod;
121 pjsip_endpoint *endpt;
122 pjsip_inv_callback cb;
Benny Prijono268ca612006-02-07 12:34:11 +0000123} mod_inv =
124{
125 {
Benny Prijono2f8992b2006-02-25 21:16:36 +0000126 NULL, NULL, /* prev, next. */
127 { "mod-invite", 10 }, /* Name. */
128 -1, /* Id */
129 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
130 &mod_inv_load, /* load() */
131 NULL, /* start() */
132 NULL, /* stop() */
133 &mod_inv_unload, /* unload() */
134 &mod_inv_on_rx_request, /* on_rx_request() */
135 &mod_inv_on_rx_response, /* on_rx_response() */
136 NULL, /* on_tx_request. */
137 NULL, /* on_tx_response() */
138 &mod_inv_on_tsx_state, /* on_tsx_state() */
Benny Prijono268ca612006-02-07 12:34:11 +0000139 }
140};
141
142
Benny Prijonoa66c7152006-02-09 01:26:14 +0000143/* Invite session data to be attached to transaction. */
144struct tsx_inv_data
145{
Benny Prijono8fcb4332008-10-31 18:01:48 +0000146 pjsip_inv_session *inv; /* The invite session */
147 pj_bool_t sdp_done; /* SDP negotiation done for this tsx? */
148 pj_str_t done_tag; /* To tag in RX response with answer */
149 pj_bool_t done_early;/* Negotiation was done for early med? */
Benny Prijonoa66c7152006-02-09 01:26:14 +0000150};
151
Benny Prijono8ad55352006-02-08 11:16:05 +0000152/*
153 * Module load()
154 */
Benny Prijono268ca612006-02-07 12:34:11 +0000155static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
156{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000157 pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},
158 { "UPDATE", 6}};
Benny Prijono56315612006-07-18 14:39:40 +0000159 pj_str_t accepted = { "application/sdp", 15 };
Benny Prijono268ca612006-02-07 12:34:11 +0000160
Benny Prijono1f7767b2007-10-03 18:28:49 +0000161 /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */
Benny Prijono268ca612006-02-07 12:34:11 +0000162 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
163 PJ_ARRAY_SIZE(allowed), allowed);
164
Benny Prijono56315612006-07-18 14:39:40 +0000165 /* Register "application/sdp" in Accept header */
166 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
167 1, &accepted);
168
Benny Prijono268ca612006-02-07 12:34:11 +0000169 return PJ_SUCCESS;
170}
171
Benny Prijono8ad55352006-02-08 11:16:05 +0000172/*
173 * Module unload()
174 */
Benny Prijono268ca612006-02-07 12:34:11 +0000175static pj_status_t mod_inv_unload(void)
176{
177 /* Should remove capability here */
178 return PJ_SUCCESS;
179}
180
Benny Prijono8ad55352006-02-08 11:16:05 +0000181/*
Benny Prijono38998232006-02-08 22:44:25 +0000182 * Set session state.
183 */
184void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
185 pjsip_event *e)
186{
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000187 pjsip_inv_state prev_state = inv->state;
Benny Prijono7d910092007-06-20 04:19:46 +0000188 pj_status_t status;
189
190
191 /* If state is confirmed, check that SDP negotiation is done,
192 * otherwise disconnect the session.
193 */
194 if (state == PJSIP_INV_STATE_CONFIRMED) {
195 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
196 pjsip_tx_data *bye;
197
198 PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
199 "session"));
200
201 status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
202 NULL, &bye);
203 if (status == PJ_SUCCESS && bye)
204 status = pjsip_inv_send_msg(inv, bye);
205
206 return;
207 }
208 }
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000209
210 /* Set state. */
Benny Prijono38998232006-02-08 22:44:25 +0000211 inv->state = state;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000212
213 /* If state is DISCONNECTED, cause code MUST have been set. */
214 pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
215 inv->cause != 0);
216
217 /* Call on_state_changed() callback. */
218 if (mod_inv.cb.on_state_changed && inv->notify)
Benny Prijono38998232006-02-08 22:44:25 +0000219 (*mod_inv.cb.on_state_changed)(inv, e);
220
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000221 /* Only decrement when previous state is not already DISCONNECTED */
222 if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
223 prev_state != PJSIP_INV_STATE_DISCONNECTED)
224 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000225 if (inv->last_ack) {
226 pjsip_tx_data_dec_ref(inv->last_ack);
227 inv->last_ack = NULL;
228 }
Benny Prijono5e51a4e2008-11-27 00:06:46 +0000229 if (inv->invite_req) {
230 pjsip_tx_data_dec_ref(inv->invite_req);
231 inv->invite_req = NULL;
232 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000233 pjsip_100rel_end_session(inv);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000234 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000235 }
Benny Prijono38998232006-02-08 22:44:25 +0000236}
237
238
239/*
Benny Prijono0b6340c2006-06-13 22:21:23 +0000240 * Set cause code.
241 */
242void inv_set_cause(pjsip_inv_session *inv, int cause_code,
243 const pj_str_t *cause_text)
244{
245 if (cause_code > inv->cause) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000246 inv->cause = (pjsip_status_code) cause_code;
Benny Prijono0b6340c2006-06-13 22:21:23 +0000247 if (cause_text)
248 pj_strdup(inv->pool, &inv->cause_text, cause_text);
249 else if (cause_code/100 == 2)
250 inv->cause_text = pj_str("Normal call clearing");
251 else
252 inv->cause_text = *pjsip_get_status_text(cause_code);
253 }
254}
255
256
Benny Prijono1f7767b2007-10-03 18:28:49 +0000257/*
258 * Check if outgoing request needs to have SDP answer.
259 * This applies for both ACK and PRACK requests.
260 */
Benny Prijono9569a0b2007-10-04 15:35:26 +0000261static const pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv,
262 pjsip_transaction *tsx)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000263{
264 pjmedia_sdp_neg_state neg_state;
Benny Prijono9569a0b2007-10-04 15:35:26 +0000265 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000266 pj_status_t status;
267
268 /* If SDP negotiator is ready, start negotiation. */
269
270 /* Start nego when appropriate. */
271 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
272 PJMEDIA_SDP_NEG_STATE_NULL;
273
274 if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) {
275
276 /* Nothing to do */
277
278 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
279 pjmedia_sdp_neg_has_local_answer(inv->neg) )
280 {
281 struct tsx_inv_data *tsx_inv_data;
Benny Prijonod5f9f422007-11-25 04:40:07 +0000282 struct tsx_inv_data dummy;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000283
Benny Prijonod5f9f422007-11-25 04:40:07 +0000284 /* Get invite session's transaction data.
285 * Note that tsx may be NULL, for example when application sends
286 * delayed ACK request (at this time, the original INVITE
287 * transaction may have been destroyed.
288 */
289 if (tsx) {
290 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
291 } else {
292 tsx_inv_data = &dummy;
293 pj_bzero(&dummy, sizeof(dummy));
294 dummy.inv = inv;
295 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000296
297 status = inv_negotiate_sdp(inv);
298 if (status != PJ_SUCCESS)
299 return NULL;
300
301 /* Mark this transaction has having SDP offer/answer done. */
302 tsx_inv_data->sdp_done = 1;
303
304 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
305
306 } else {
307 /* This remark is only valid for ACK.
308 PJ_LOG(4,(inv->dlg->obj_name,
309 "FYI, the SDP negotiator state (%s) is in a mess "
310 "when sending this ACK/PRACK request",
311 pjmedia_sdp_neg_state_str(neg_state)));
312 */
313 }
314
315 return sdp;
316}
317
Benny Prijono0b6340c2006-06-13 22:21:23 +0000318
319/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000320 * Send ACK for 2xx response.
321 */
Benny Prijonod5f9f422007-11-25 04:40:07 +0000322static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +0000323{
Benny Prijonod5f9f422007-11-25 04:40:07 +0000324 pjsip_rx_data *rdata;
Benny Prijono268ca612006-02-07 12:34:11 +0000325 pj_status_t status;
326
Benny Prijonod5f9f422007-11-25 04:40:07 +0000327 if (e->type == PJSIP_EVENT_TSX_STATE)
328 rdata = e->body.tsx_state.src.rdata;
329 else if (e->type == PJSIP_EVENT_RX_MSG)
330 rdata = e->body.rx_msg.rdata;
331 else {
332 pj_assert(!"Unsupported event type");
333 return PJ_EBUG;
334 }
335
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000336 PJ_LOG(5,(inv->obj_name, "Received %s, sending ACK",
337 pjsip_rx_data_get_info(rdata)));
338
Benny Prijono1f7767b2007-10-03 18:28:49 +0000339 /* Check if we have cached ACK request */
340 if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000341
Benny Prijono1f7767b2007-10-03 18:28:49 +0000342 pjsip_tx_data_add_ref(inv->last_ack);
Benny Prijonod5f9f422007-11-25 04:40:07 +0000343
344 } else if (mod_inv.cb.on_send_ack) {
345 /* If application handles ACK transmission manually, just notify the
346 * callback
347 */
348 PJ_LOG(5,(inv->obj_name, "Received %s, notifying application callback",
349 pjsip_rx_data_get_info(rdata)));
350
351 (*mod_inv.cb.on_send_ack)(inv, rdata);
352 return PJ_SUCCESS;
353
Benny Prijono1f7767b2007-10-03 18:28:49 +0000354 } else {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000355 status = pjsip_inv_create_ack(inv, rdata->msg_info.cseq->cseq,
356 &inv->last_ack);
Benny Prijono268ca612006-02-07 12:34:11 +0000357 }
358
Benny Prijono1f7767b2007-10-03 18:28:49 +0000359 /* Send ACK */
360 status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000361 if (status != PJ_SUCCESS) {
362 /* Better luck next time */
363 pj_assert(!"Unable to send ACK!");
364 return status;
365 }
366
Benny Prijonod5f9f422007-11-25 04:40:07 +0000367
Benny Prijonoe6da48a2008-09-22 14:36:00 +0000368 /* Set state to CONFIRMED (if we're not in CONFIRMED yet).
369 * But don't set it to CONFIRMED if we're already DISCONNECTED
370 * (this may have been a late 200/OK response.
371 */
372 if (inv->state < PJSIP_INV_STATE_CONFIRMED) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000373 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
374 }
375
Benny Prijono268ca612006-02-07 12:34:11 +0000376 return PJ_SUCCESS;
377}
378
Benny Prijono8ad55352006-02-08 11:16:05 +0000379/*
380 * Module on_rx_request()
381 *
382 * This callback is called for these events:
383 * - endpoint receives request which was unhandled by higher priority
384 * modules (e.g. transaction layer, dialog layer).
385 * - dialog distributes incoming request to its usages.
386 */
387static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
388{
389 pjsip_method *method;
Benny Prijono38998232006-02-08 22:44:25 +0000390 pjsip_dialog *dlg;
391 pjsip_inv_session *inv;
Benny Prijono8ad55352006-02-08 11:16:05 +0000392
393 /* Only wants to receive request from a dialog. */
Benny Prijono38998232006-02-08 22:44:25 +0000394 dlg = pjsip_rdata_get_dlg(rdata);
395 if (dlg == NULL)
Benny Prijono8ad55352006-02-08 11:16:05 +0000396 return PJ_FALSE;
397
Benny Prijonoa1e69682007-05-11 15:14:34 +0000398 inv = (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono38998232006-02-08 22:44:25 +0000399
Benny Prijono8ad55352006-02-08 11:16:05 +0000400 /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
401 * If we need to send response, it will be sent in the state
402 * handlers.
403 */
404 method = &rdata->msg_info.msg->line.req.method;
405
Benny Prijono70127222006-07-02 14:53:05 +0000406 if (method->id == PJSIP_INVITE_METHOD) {
407 return PJ_TRUE;
408 }
409
410 /* BYE and CANCEL must have existing invite session */
411 if (method->id == PJSIP_BYE_METHOD ||
412 method->id == PJSIP_CANCEL_METHOD)
Benny Prijono8ad55352006-02-08 11:16:05 +0000413 {
Benny Prijono70127222006-07-02 14:53:05 +0000414 if (inv == NULL)
415 return PJ_FALSE;
416
Benny Prijono8ad55352006-02-08 11:16:05 +0000417 return PJ_TRUE;
418 }
419
Benny Prijono38998232006-02-08 22:44:25 +0000420 /* On receipt ACK request, when state is CONNECTING,
421 * move state to CONFIRMED.
422 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000423 if (method->id == PJSIP_ACK_METHOD && inv) {
Benny Prijono38998232006-02-08 22:44:25 +0000424
Benny Prijonof521eb02006-08-06 23:07:25 +0000425 /* Ignore ACK if pending INVITE transaction has not finished. */
426 if (inv->invite_tsx &&
427 inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
428 {
429 return PJ_TRUE;
430 }
431
Benny Prijono5eff0432006-02-09 14:14:21 +0000432 /* Terminate INVITE transaction, if it's still present. */
433 if (inv->invite_tsx &&
434 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
435 {
Benny Prijono7d910092007-06-20 04:19:46 +0000436 /* Before we terminate INVITE transaction, process the SDP
Benny Prijono59e9e952008-09-21 22:55:43 +0000437 * in the ACK request, if any.
438 * Only do this when invite state is not already disconnected
439 * (http://trac.pjsip.org/repos/ticket/640).
Benny Prijono7d910092007-06-20 04:19:46 +0000440 */
Benny Prijono59e9e952008-09-21 22:55:43 +0000441 if (inv->state < PJSIP_INV_STATE_DISCONNECTED) {
442 inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
443 }
Benny Prijono7d910092007-06-20 04:19:46 +0000444
445 /* Now we can terminate the INVITE transaction */
Benny Prijonof521eb02006-08-06 23:07:25 +0000446 pj_assert(inv->invite_tsx->status_code >= 200);
Benny Prijono5eff0432006-02-09 14:14:21 +0000447 pjsip_tsx_terminate(inv->invite_tsx,
448 inv->invite_tsx->status_code);
449 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000450 if (inv->last_answer) {
451 pjsip_tx_data_dec_ref(inv->last_answer);
452 inv->last_answer = NULL;
453 }
Benny Prijono5eff0432006-02-09 14:14:21 +0000454 }
455
Benny Prijono32ac8fe2006-03-02 21:16:55 +0000456 /* On receipt of ACK, only set state to confirmed when state
457 * is CONNECTING (e.g. we don't want to set the state to confirmed
458 * when we receive ACK retransmission after sending non-2xx!)
459 */
460 if (inv->state == PJSIP_INV_STATE_CONNECTING) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000461 pjsip_event event;
462
463 PJSIP_EVENT_INIT_RX_MSG(event, rdata);
464 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
465 }
Benny Prijono38998232006-02-08 22:44:25 +0000466 }
467
Benny Prijono8ad55352006-02-08 11:16:05 +0000468 return PJ_FALSE;
469}
470
471/*
472 * Module on_rx_response().
473 *
474 * This callback is called for these events:
475 * - dialog distributes incoming 2xx response to INVITE (outside
476 * transaction) to its usages.
477 * - endpoint distributes strayed responses.
478 */
Benny Prijono268ca612006-02-07 12:34:11 +0000479static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
480{
481 pjsip_dialog *dlg;
482 pjsip_inv_session *inv;
483 pjsip_msg *msg = rdata->msg_info.msg;
484
485 dlg = pjsip_rdata_get_dlg(rdata);
486
487 /* Ignore responses outside dialog */
488 if (dlg == NULL)
489 return PJ_FALSE;
490
491 /* Ignore responses not belonging to invite session */
492 inv = pjsip_dlg_get_inv_session(dlg);
493 if (inv == NULL)
494 return PJ_FALSE;
495
496 /* This MAY be retransmission of 2xx response to INVITE.
497 * If it is, we need to send ACK.
498 */
499 if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
Benny Prijono26ff9062006-02-21 23:47:00 +0000500 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
501 inv->invite_tsx == NULL)
502 {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000503 pjsip_event e;
Benny Prijono268ca612006-02-07 12:34:11 +0000504
Benny Prijonod5f9f422007-11-25 04:40:07 +0000505 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
506 inv_send_ack(inv, &e);
Benny Prijono268ca612006-02-07 12:34:11 +0000507 return PJ_TRUE;
508
509 }
510
511 /* No other processing needs to be done here. */
512 return PJ_FALSE;
513}
514
Benny Prijono8ad55352006-02-08 11:16:05 +0000515/*
516 * Module on_tsx_state()
517 *
518 * This callback is called by dialog framework for all transactions
519 * inside the dialog for all its dialog usages.
520 */
Benny Prijono268ca612006-02-07 12:34:11 +0000521static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
522{
523 pjsip_dialog *dlg;
524 pjsip_inv_session *inv;
525
526 dlg = pjsip_tsx_get_dlg(tsx);
527 if (dlg == NULL)
528 return;
529
530 inv = pjsip_dlg_get_inv_session(dlg);
531 if (inv == NULL)
532 return;
533
534 /* Call state handler for the invite session. */
535 (*inv_state_handler[inv->state])(inv, e);
536
537 /* Call on_tsx_state */
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000538 if (mod_inv.cb.on_tsx_state_changed && inv->notify)
Benny Prijono268ca612006-02-07 12:34:11 +0000539 (*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
540
Benny Prijono46249942007-02-19 22:23:14 +0000541 /* Clear invite transaction when tsx is confirmed.
542 * Previously we set invite_tsx to NULL only when transaction has
543 * terminated, but this didn't work when ACK has the same Via branch
544 * value as the INVITE (see http://www.pjsip.org/trac/ticket/113)
545 */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000546 if (tsx->state>=PJSIP_TSX_STATE_CONFIRMED && tsx == inv->invite_tsx) {
Benny Prijono46249942007-02-19 22:23:14 +0000547 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000548 if (inv->last_answer) {
549 pjsip_tx_data_dec_ref(inv->last_answer);
550 inv->last_answer = NULL;
551 }
552 }
Benny Prijono268ca612006-02-07 12:34:11 +0000553}
554
Benny Prijono8ad55352006-02-08 11:16:05 +0000555
556/*
557 * Initialize the invite module.
558 */
Benny Prijono268ca612006-02-07 12:34:11 +0000559PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
Benny Prijono268ca612006-02-07 12:34:11 +0000560 const pjsip_inv_callback *cb)
561{
562 pj_status_t status;
563
564 /* Check arguments. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000565 PJ_ASSERT_RETURN(endpt && cb, PJ_EINVAL);
Benny Prijono268ca612006-02-07 12:34:11 +0000566
567 /* Some callbacks are mandatory */
568 PJ_ASSERT_RETURN(cb->on_state_changed && cb->on_new_session, PJ_EINVAL);
569
570 /* Check if module already registered. */
571 PJ_ASSERT_RETURN(mod_inv.mod.id == -1, PJ_EINVALIDOP);
572
573 /* Copy param. */
574 pj_memcpy(&mod_inv.cb, cb, sizeof(pjsip_inv_callback));
575
576 mod_inv.endpt = endpt;
Benny Prijono268ca612006-02-07 12:34:11 +0000577
578 /* Register the module. */
579 status = pjsip_endpt_register_module(endpt, &mod_inv.mod);
Benny Prijono053f5222006-11-11 16:16:04 +0000580 if (status != PJ_SUCCESS)
581 return status;
Benny Prijono268ca612006-02-07 12:34:11 +0000582
Benny Prijono053f5222006-11-11 16:16:04 +0000583 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +0000584}
585
Benny Prijono8ad55352006-02-08 11:16:05 +0000586/*
587 * Get the instance of invite module.
588 */
Benny Prijono268ca612006-02-07 12:34:11 +0000589PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
590{
591 return &mod_inv.mod;
592}
593
594
Benny Prijono632ce712006-02-09 14:01:40 +0000595
Benny Prijono8ad55352006-02-08 11:16:05 +0000596/*
597 * Return the invite session for the specified dialog.
598 */
Benny Prijono268ca612006-02-07 12:34:11 +0000599PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
600{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000601 return (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono268ca612006-02-07 12:34:11 +0000602}
603
Benny Prijono8ad55352006-02-08 11:16:05 +0000604
Benny Prijono268ca612006-02-07 12:34:11 +0000605/*
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000606 * Get INVITE state name.
607 */
608PJ_DEF(const char *) pjsip_inv_state_name(pjsip_inv_state state)
609{
610 PJ_ASSERT_RETURN(state >= PJSIP_INV_STATE_NULL &&
611 state <= PJSIP_INV_STATE_DISCONNECTED,
612 "??");
613
614 return inv_state_names[state];
615}
616
617/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000618 * Create UAC invite session.
Benny Prijono268ca612006-02-07 12:34:11 +0000619 */
620PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
621 const pjmedia_sdp_session *local_sdp,
622 unsigned options,
623 pjsip_inv_session **p_inv)
624{
625 pjsip_inv_session *inv;
626 pj_status_t status;
627
628 /* Verify arguments. */
629 PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
630
Benny Prijono8eae8382006-08-10 21:44:26 +0000631 /* Must lock dialog first */
632 pjsip_dlg_inc_lock(dlg);
633
Benny Prijono268ca612006-02-07 12:34:11 +0000634 /* Normalize options */
635 if (options & PJSIP_INV_REQUIRE_100REL)
636 options |= PJSIP_INV_SUPPORT_100REL;
637
638 if (options & PJSIP_INV_REQUIRE_TIMER)
639 options |= PJSIP_INV_SUPPORT_TIMER;
640
641 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000642 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +0000643 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000644
645 inv->pool = dlg->pool;
646 inv->role = PJSIP_ROLE_UAC;
647 inv->state = PJSIP_INV_STATE_NULL;
648 inv->dlg = dlg;
649 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000650 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000651 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +0000652
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000653 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +0000654 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000655
Benny Prijono268ca612006-02-07 12:34:11 +0000656 /* Create negotiator if local_sdp is specified. */
657 if (local_sdp) {
658 status = pjmedia_sdp_neg_create_w_local_offer(dlg->pool, local_sdp,
659 &inv->neg);
Benny Prijono8eae8382006-08-10 21:44:26 +0000660 if (status != PJ_SUCCESS) {
661 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000662 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000663 }
Benny Prijono268ca612006-02-07 12:34:11 +0000664 }
665
666 /* Register invite as dialog usage. */
667 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +0000668 if (status != PJ_SUCCESS) {
669 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000670 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000671 }
Benny Prijono268ca612006-02-07 12:34:11 +0000672
673 /* Increment dialog session */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000674 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +0000675
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000676 /* Create 100rel handler */
677 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000678
Benny Prijono268ca612006-02-07 12:34:11 +0000679 /* Done */
680 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000681
Benny Prijono8eae8382006-08-10 21:44:26 +0000682 pjsip_dlg_dec_lock(dlg);
683
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000684 PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
685 dlg->obj_name));
686
Benny Prijono268ca612006-02-07 12:34:11 +0000687 return PJ_SUCCESS;
688}
689
690/*
691 * Verify incoming INVITE request.
692 */
Benny Prijono87a90212008-01-23 20:29:30 +0000693PJ_DEF(pj_status_t) pjsip_inv_verify_request2(pjsip_rx_data *rdata,
694 unsigned *options,
695 const pjmedia_sdp_session *r_sdp,
696 const pjmedia_sdp_session *l_sdp,
697 pjsip_dialog *dlg,
698 pjsip_endpoint *endpt,
699 pjsip_tx_data **p_tdata)
Benny Prijono268ca612006-02-07 12:34:11 +0000700{
701 pjsip_msg *msg;
702 pjsip_allow_hdr *allow;
703 pjsip_supported_hdr *sup_hdr;
704 pjsip_require_hdr *req_hdr;
705 int code = 200;
706 unsigned rem_option = 0;
707 pj_status_t status = PJ_SUCCESS;
708 pjsip_hdr res_hdr_list;
709
710 /* Init return arguments. */
711 if (p_tdata) *p_tdata = NULL;
712
713 /* Verify arguments. */
714 PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);
715
716 /* Normalize options */
717 if (*options & PJSIP_INV_REQUIRE_100REL)
718 *options |= PJSIP_INV_SUPPORT_100REL;
719
720 if (*options & PJSIP_INV_REQUIRE_TIMER)
721 *options |= PJSIP_INV_SUPPORT_TIMER;
722
723 /* Get the message in rdata */
724 msg = rdata->msg_info.msg;
725
726 /* Must be INVITE request. */
727 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
728 msg->line.req.method.id == PJSIP_INVITE_METHOD,
729 PJ_EINVAL);
730
731 /* If tdata is specified, then either dlg or endpt must be specified */
732 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
733
734 /* Get the endpoint */
735 endpt = endpt ? endpt : dlg->endpt;
736
737 /* Init response header list */
738 pj_list_init(&res_hdr_list);
739
Benny Prijono87a90212008-01-23 20:29:30 +0000740 /* Check the request body, see if it's something that we support,
741 * only when the body hasn't been parsed before.
Benny Prijono268ca612006-02-07 12:34:11 +0000742 */
Benny Prijono87a90212008-01-23 20:29:30 +0000743 if (r_sdp==NULL && msg->body) {
Benny Prijono268ca612006-02-07 12:34:11 +0000744 pjsip_msg_body *body = msg->body;
745 pj_str_t str_application = {"application", 11};
746 pj_str_t str_sdp = { "sdp", 3 };
747 pjmedia_sdp_session *sdp;
748
749 /* Check content type. */
750 if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||
751 pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)
752 {
753 /* Not "application/sdp" */
754 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
755 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
756
757 if (p_tdata) {
758 /* Add Accept header to response */
759 pjsip_accept_hdr *acc;
760
761 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
762 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
763 acc->values[acc->count++] = pj_str("application/sdp");
764 pj_list_push_back(&res_hdr_list, acc);
765 }
766
767 goto on_return;
768 }
769
770 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000771 status = pjmedia_sdp_parse(rdata->tp_info.pool,
772 (char*)body->data, body->len, &sdp);
Benny Prijono268ca612006-02-07 12:34:11 +0000773 if (status == PJ_SUCCESS)
774 status = pjmedia_sdp_validate(sdp);
775
776 if (status != PJ_SUCCESS) {
777 /* Unparseable or invalid SDP */
778 code = PJSIP_SC_BAD_REQUEST;
779
780 if (p_tdata) {
781 /* Add Warning header. */
782 pjsip_warning_hdr *w;
783
784 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
785 pjsip_endpt_name(endpt),
786 status);
787 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
788
789 pj_list_push_back(&res_hdr_list, w);
790 }
791
792 goto on_return;
793 }
794
Benny Prijono87a90212008-01-23 20:29:30 +0000795 r_sdp = sdp;
796 }
797
798 if (r_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +0000799 /* Negotiate with local SDP */
800 if (l_sdp) {
801 pjmedia_sdp_neg *neg;
802
803 /* Local SDP must be valid! */
804 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
805 status);
806
807 /* Create SDP negotiator */
808 status = pjmedia_sdp_neg_create_w_remote_offer(
Benny Prijono87a90212008-01-23 20:29:30 +0000809 rdata->tp_info.pool, l_sdp, r_sdp, &neg);
Benny Prijono268ca612006-02-07 12:34:11 +0000810 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
811
812 /* Negotiate SDP */
813 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
814 if (status != PJ_SUCCESS) {
815
816 /* Incompatible media */
817 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000818
819 if (p_tdata) {
820 pjsip_accept_hdr *acc;
821 pjsip_warning_hdr *w;
822
823 /* Add Warning header. */
824 w = pjsip_warning_hdr_create_from_status(
825 rdata->tp_info.pool,
826 pjsip_endpt_name(endpt), status);
827 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
828
829 pj_list_push_back(&res_hdr_list, w);
830
831 /* Add Accept header to response */
832 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
833 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
834 acc->values[acc->count++] = pj_str("application/sdp");
835 pj_list_push_back(&res_hdr_list, acc);
836
837 }
838
839 goto on_return;
840 }
841 }
842 }
843
844 /* Check supported methods, see if peer supports UPDATE.
845 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
846 * implicitly by sending this INVITE.
847 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000848 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000849 if (allow) {
850 unsigned i;
851 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
852
853 for (i=0; i<allow->count; ++i) {
854 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
855 break;
856 }
857
858 if (i != allow->count) {
859 /* UPDATE is present in Allow */
860 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
861 }
862
863 }
864
865 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000866 sup_hdr = (pjsip_supported_hdr*)
867 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000868 if (sup_hdr) {
869 unsigned i;
870 pj_str_t STR_100REL = { "100rel", 6};
871 pj_str_t STR_TIMER = { "timer", 5 };
872
873 for (i=0; i<sup_hdr->count; ++i) {
874 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
875 rem_option |= PJSIP_INV_SUPPORT_100REL;
876 else if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
877 rem_option |= PJSIP_INV_SUPPORT_TIMER;
878 }
879 }
880
881 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000882 req_hdr = (pjsip_require_hdr*)
883 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000884 if (req_hdr) {
885 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +0000886 const pj_str_t STR_100REL = { "100rel", 6};
887 const pj_str_t STR_TIMER = { "timer", 5 };
888 const pj_str_t STR_REPLACES = { "replaces", 8 };
Benny Prijono268ca612006-02-07 12:34:11 +0000889 unsigned unsupp_cnt = 0;
890 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
891
892 for (i=0; i<req_hdr->count; ++i) {
893 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
894 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
895 {
896 rem_option |= PJSIP_INV_REQUIRE_100REL;
897
898 } else if ((*options && PJSIP_INV_SUPPORT_TIMER) &&
899 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
900 {
901 rem_option |= PJSIP_INV_REQUIRE_TIMER;
902
Benny Prijono053f5222006-11-11 16:16:04 +0000903 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
904 pj_bool_t supp;
905
906 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
907 NULL, &STR_REPLACES);
908 if (!supp)
909 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
910
Benny Prijono268ca612006-02-07 12:34:11 +0000911 } else {
912 /* Unknown/unsupported extension tag! */
913 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
914 }
915 }
916
917 /* Check if there are required tags that we don't support */
918 if (unsupp_cnt) {
919
920 code = PJSIP_SC_BAD_EXTENSION;
921 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
922
923 if (p_tdata) {
924 pjsip_unsupported_hdr *unsupp_hdr;
925 const pjsip_hdr *h;
926
927 /* Add Unsupported header. */
928 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
929 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
930
931 unsupp_hdr->count = unsupp_cnt;
932 for (i=0; i<unsupp_cnt; ++i)
933 unsupp_hdr->values[i] = unsupp_tags[i];
934
935 pj_list_push_back(&res_hdr_list, unsupp_hdr);
936
937 /* Add Supported header. */
938 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
939 NULL);
940 pj_assert(h);
941 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000942 sup_hdr = (pjsip_supported_hdr*)
943 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000944 pj_list_push_back(&res_hdr_list, sup_hdr);
945 }
946 }
947
948 goto on_return;
949 }
950 }
951
952 /* Check if there are local requirements that are not supported
953 * by peer.
954 */
955 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
956 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
957 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
958 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
959 {
960 code = PJSIP_SC_EXTENSION_REQUIRED;
961 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
962
963 if (p_tdata) {
964 const pjsip_hdr *h;
965
966 /* Add Require header. */
967 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
968 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
969
970 if (*options & PJSIP_INV_REQUIRE_100REL)
971 req_hdr->values[req_hdr->count++] = pj_str("100rel");
972
973 if (*options & PJSIP_INV_REQUIRE_TIMER)
974 req_hdr->values[req_hdr->count++] = pj_str("timer");
975
976 pj_list_push_back(&res_hdr_list, req_hdr);
977
978 /* Add Supported header. */
979 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
980 NULL);
981 pj_assert(h);
982 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000983 sup_hdr = (pjsip_supported_hdr*)
984 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000985 pj_list_push_back(&res_hdr_list, sup_hdr);
986 }
987
988 }
989
990 goto on_return;
991 }
992
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000993 /* If remote Require something that we support, make us Require
994 * that feature too.
995 */
996 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
997 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
998 *options |= PJSIP_INV_REQUIRE_100REL;
999 }
1000 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1001 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1002 *options |= PJSIP_INV_REQUIRE_TIMER;
1003 }
1004
Benny Prijono268ca612006-02-07 12:34:11 +00001005on_return:
1006
1007 /* Create response if necessary */
1008 if (code != 200 && p_tdata) {
1009 pjsip_tx_data *tdata;
1010 const pjsip_hdr *h;
1011
1012 if (dlg) {
1013 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1014 &tdata);
1015 } else {
1016 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1017 &tdata);
1018 }
1019
1020 if (status != PJ_SUCCESS)
1021 return status;
1022
1023 /* Add response headers. */
1024 h = res_hdr_list.next;
1025 while (h != &res_hdr_list) {
1026 pjsip_hdr *cloned;
1027
Benny Prijonoa1e69682007-05-11 15:14:34 +00001028 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001029 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1030
1031 pjsip_msg_add_hdr(tdata->msg, cloned);
1032
1033 h = h->next;
1034 }
1035
1036 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001037
1038 /* Can not return PJ_SUCCESS when response message is produced.
1039 * Ref: PROTOS test ~#2490
1040 */
1041 if (status == PJ_SUCCESS)
1042 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1043
Benny Prijono268ca612006-02-07 12:34:11 +00001044 }
1045
1046 return status;
1047}
1048
Benny Prijono87a90212008-01-23 20:29:30 +00001049
1050/*
1051 * Verify incoming INVITE request.
1052 */
1053PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1054 unsigned *options,
1055 const pjmedia_sdp_session *l_sdp,
1056 pjsip_dialog *dlg,
1057 pjsip_endpoint *endpt,
1058 pjsip_tx_data **p_tdata)
1059{
1060 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1061 endpt, p_tdata);
1062}
1063
Benny Prijono268ca612006-02-07 12:34:11 +00001064/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001065 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001066 */
1067PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1068 pjsip_rx_data *rdata,
1069 const pjmedia_sdp_session *local_sdp,
1070 unsigned options,
1071 pjsip_inv_session **p_inv)
1072{
1073 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001074 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001075 pjsip_msg *msg;
1076 pjmedia_sdp_session *rem_sdp = NULL;
1077 pj_status_t status;
1078
1079 /* Verify arguments. */
1080 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1081
1082 /* Dialog MUST have been initialised. */
1083 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1084
1085 msg = rdata->msg_info.msg;
1086
1087 /* rdata MUST contain INVITE request */
1088 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1089 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1090 PJ_EINVALIDOP);
1091
Benny Prijono8eae8382006-08-10 21:44:26 +00001092 /* Lock dialog */
1093 pjsip_dlg_inc_lock(dlg);
1094
Benny Prijono268ca612006-02-07 12:34:11 +00001095 /* Normalize options */
1096 if (options & PJSIP_INV_REQUIRE_100REL)
1097 options |= PJSIP_INV_SUPPORT_100REL;
1098
1099 if (options & PJSIP_INV_REQUIRE_TIMER)
1100 options |= PJSIP_INV_SUPPORT_TIMER;
1101
1102 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001103 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001104 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001105
1106 inv->pool = dlg->pool;
1107 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001108 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001109 inv->dlg = dlg;
1110 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001111 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001112 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001113
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001114 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001115 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001116
Benny Prijono268ca612006-02-07 12:34:11 +00001117 /* Parse SDP in message body, if present. */
1118 if (msg->body) {
1119 pjsip_msg_body *body = msg->body;
1120
1121 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001122 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001123 &rem_sdp);
1124 if (status == PJ_SUCCESS)
1125 status = pjmedia_sdp_validate(rem_sdp);
1126
Benny Prijono8eae8382006-08-10 21:44:26 +00001127 if (status != PJ_SUCCESS) {
1128 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001129 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001130 }
Benny Prijono268ca612006-02-07 12:34:11 +00001131 }
1132
1133 /* Create negotiator. */
1134 if (rem_sdp) {
1135 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp,
1136 rem_sdp, &inv->neg);
1137
1138 } else if (local_sdp) {
1139 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1140 &inv->neg);
1141 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001142 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001143 }
1144
Benny Prijono8eae8382006-08-10 21:44:26 +00001145 if (status != PJ_SUCCESS) {
1146 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001147 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001148 }
Benny Prijono268ca612006-02-07 12:34:11 +00001149
1150 /* Register invite as dialog usage. */
1151 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001152 if (status != PJ_SUCCESS) {
1153 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001154 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001155 }
Benny Prijono268ca612006-02-07 12:34:11 +00001156
1157 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001158 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001159
1160 /* Save the invite transaction. */
1161 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001162
1163 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001164 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001165 tsx_inv_data->inv = inv;
1166 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001167
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001168 /* Create 100rel handler */
1169 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1170 pjsip_100rel_attach(inv);
1171 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001172
Benny Prijono268ca612006-02-07 12:34:11 +00001173 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001174 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001175 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001176
1177 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1178 dlg->obj_name));
1179
Benny Prijono268ca612006-02-07 12:34:11 +00001180 return PJ_SUCCESS;
1181}
1182
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001183/*
1184 * Forcefully terminate the session.
1185 */
1186PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1187 int st_code,
1188 pj_bool_t notify)
1189{
1190 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1191
1192 /* Lock dialog. */
1193 pjsip_dlg_inc_lock(inv->dlg);
1194
1195 /* Set callback notify flag. */
1196 inv->notify = notify;
1197
1198 /* If there's pending transaction, terminate the transaction.
1199 * This may subsequently set the INVITE session state to
1200 * disconnected.
1201 */
1202 if (inv->invite_tsx &&
1203 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1204 {
1205 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1206
1207 }
1208
1209 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001210 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001211
1212 /* Forcefully terminate the session if state is not DISCONNECTED */
1213 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1214 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1215 }
1216
1217 /* Done.
1218 * The dec_lock() below will actually destroys the dialog if it
1219 * has no other session.
1220 */
1221 pjsip_dlg_dec_lock(inv->dlg);
1222
1223 return PJ_SUCCESS;
1224}
1225
1226
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001227/*
1228 * Restart UAC session, possibly because app or us wants to re-send the
1229 * INVITE request due to 401/407 challenge or 3xx response.
1230 */
1231PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1232 pj_bool_t new_offer)
1233{
1234 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1235
1236 inv->state = PJSIP_INV_STATE_NULL;
1237 inv->invite_tsx = NULL;
1238 if (inv->last_answer) {
1239 pjsip_tx_data_dec_ref(inv->last_answer);
1240 inv->last_answer = NULL;
1241 }
1242
1243 if (new_offer && inv->neg) {
1244 pjmedia_sdp_neg_state neg_state;
1245
1246 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1247 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1248 pjmedia_sdp_neg_cancel_offer(inv->neg);
1249 }
1250 }
1251
1252 return PJ_SUCCESS;
1253}
1254
1255
Benny Prijono268ca612006-02-07 12:34:11 +00001256static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1257{
1258 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001259 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001260}
1261
1262static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1263{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001264 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001265}
1266
Benny Prijono56315612006-07-18 14:39:40 +00001267
1268PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1269 pjmedia_sdp_session *sdp,
1270 pjsip_msg_body **p_body)
1271{
1272 const pj_str_t STR_APPLICATION = { "application", 11};
1273 const pj_str_t STR_SDP = { "sdp", 3 };
1274 pjsip_msg_body *body;
1275
Benny Prijonoa1e69682007-05-11 15:14:34 +00001276 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001277 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1278
1279 body->content_type.type = STR_APPLICATION;
1280 body->content_type.subtype = STR_SDP;
1281 body->data = sdp;
1282 body->len = 0;
1283 body->clone_data = &clone_sdp;
1284 body->print_body = &print_sdp;
1285
1286 *p_body = body;
1287
1288 return PJ_SUCCESS;
1289}
1290
Benny Prijono268ca612006-02-07 12:34:11 +00001291static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1292 const pjmedia_sdp_session *c_sdp)
1293{
1294 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001295 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001296
Benny Prijono56315612006-07-18 14:39:40 +00001297 status = pjsip_create_sdp_body(pool,
1298 pjmedia_sdp_session_clone(pool, c_sdp),
1299 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001300
Benny Prijono56315612006-07-18 14:39:40 +00001301 if (status != PJ_SUCCESS)
1302 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001303
1304 return body;
1305}
1306
1307/*
1308 * Create initial INVITE request.
1309 */
1310PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1311 pjsip_tx_data **p_tdata )
1312{
1313 pjsip_tx_data *tdata;
1314 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001315 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001316 pj_status_t status;
1317
1318 /* Verify arguments. */
1319 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1320
Benny Prijono26ff9062006-02-21 23:47:00 +00001321 /* State MUST be NULL or CONFIRMED. */
1322 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1323 inv->state == PJSIP_INV_STATE_CONFIRMED,
1324 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001325
Benny Prijono64f851e2006-02-23 13:49:28 +00001326 /* Lock dialog. */
1327 pjsip_dlg_inc_lock(inv->dlg);
1328
Benny Prijono268ca612006-02-07 12:34:11 +00001329 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001330 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001331 &tdata);
1332 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001333 goto on_return;
1334
Benny Prijono268ca612006-02-07 12:34:11 +00001335
Benny Prijono26ff9062006-02-21 23:47:00 +00001336 /* If this is the first INVITE, then copy the headers from inv_hdr.
1337 * These are the headers parsed from the request URI when the
1338 * dialog was created.
1339 */
1340 if (inv->state == PJSIP_INV_STATE_NULL) {
1341 hdr = inv->dlg->inv_hdr.next;
1342
1343 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001344 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001345 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1346 hdr = hdr->next;
1347 }
1348 }
1349
1350 /* See if we have SDP to send. */
1351 if (inv->neg) {
1352 pjmedia_sdp_neg_state neg_state;
1353
1354 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1355
1356 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1357 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1358 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1359
1360
1361 } else {
1362 has_sdp = PJ_FALSE;
1363 }
1364
Benny Prijono268ca612006-02-07 12:34:11 +00001365 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001366 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001367 const pjmedia_sdp_session *offer;
1368
1369 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono176a11f2009-04-14 11:14:51 +00001370 if (status != PJ_SUCCESS) {
1371 pjsip_tx_data_dec_ref(tdata);
Benny Prijono64f851e2006-02-23 13:49:28 +00001372 goto on_return;
Benny Prijono176a11f2009-04-14 11:14:51 +00001373 }
Benny Prijono268ca612006-02-07 12:34:11 +00001374
1375 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1376 }
1377
1378 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001379 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001380 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1381 if (hdr) {
1382 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1383 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1384 }
Benny Prijono268ca612006-02-07 12:34:11 +00001385 }
1386
1387 /* Add Supported header */
1388 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1389 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001390 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001391 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1392 }
1393
1394 /* Add Require header. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001395 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1396 const pj_str_t HREQ = { "Require", 7 };
1397 const pj_str_t tag_100rel = { "100rel", 6 };
1398 pjsip_generic_string_hdr *hreq;
1399
1400 hreq = pjsip_generic_string_hdr_create(tdata->pool, &HREQ,
1401 &tag_100rel);
1402 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
1403 }
Benny Prijono268ca612006-02-07 12:34:11 +00001404
1405 /* Done. */
1406 *p_tdata = tdata;
1407
Benny Prijono64f851e2006-02-23 13:49:28 +00001408
1409on_return:
1410 pjsip_dlg_dec_lock(inv->dlg);
1411 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001412}
1413
1414
1415/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001416 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001417 */
1418static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1419{
1420 pj_status_t status;
1421
1422 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1423 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1424 PJMEDIA_SDPNEG_EINSTATE);
1425
1426 status = pjmedia_sdp_neg_negotiate(inv->pool, inv->neg, 0);
1427
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001428 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1429
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001430 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001431 (*mod_inv.cb.on_media_update)(inv, status);
1432
1433 return status;
1434}
1435
1436/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001437 * Check in incoming message for SDP offer/answer.
1438 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001439static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1440 pjsip_transaction *tsx,
1441 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001442{
1443 struct tsx_inv_data *tsx_inv_data;
1444 static const pj_str_t str_application = { "application", 11 };
1445 static const pj_str_t str_sdp = { "sdp", 3 };
1446 pj_status_t status;
1447 pjsip_msg *msg;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001448 pjmedia_sdp_session *rem_sdp;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001449
1450 /* Check if SDP is present in the message. */
1451
1452 msg = rdata->msg_info.msg;
1453 if (msg->body == NULL) {
1454 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001455 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001456 }
1457
1458 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1459 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1460 {
1461 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001462 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001463 }
1464
Benny Prijono8fcb4332008-10-31 18:01:48 +00001465 /* Get/attach invite session's transaction data */
1466 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1467 if (tsx_inv_data == NULL) {
1468 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1469 tsx_inv_data->inv = inv;
1470 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1471 }
1472
1473 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1474 * EXCEPT if:
1475 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1476 * - the previous negotiation was done on an early media (18x) and
1477 * this response is a final/2xx response, and
1478 * - the 2xx response has different To tag than the 18x response
1479 * (i.e. the request has forked).
1480 *
1481 * The exception above is to add a rudimentary support for early media
1482 * forking (sample case: custom ringback). See this ticket for more
1483 * info: http://trac.pjsip.org/repos/ticket/657
1484 */
1485 if (tsx_inv_data->sdp_done) {
1486 pj_str_t res_tag;
1487
1488 res_tag = rdata->msg_info.to->tag;
1489
1490 /* Allow final response after SDP has been negotiated in early
1491 * media, IF this response is a final response with different
1492 * tag.
1493 */
1494 if (tsx->role == PJSIP_ROLE_UAC &&
1495 rdata->msg_info.msg->line.status.code/100 == 2 &&
1496 tsx_inv_data->done_early &&
1497 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1498 {
1499 const pjmedia_sdp_session *reoffer_sdp = NULL;
1500
1501 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1502 "after SDP negotiation has been done in early "
1503 "media. Renegotiating SDP.."));
1504
1505 /* Retrieve original SDP offer from INVITE request */
1506 reoffer_sdp = (const pjmedia_sdp_session*)
1507 tsx->last_tx->msg->body->data;
1508
1509 /* Feed the original offer to negotiator */
1510 status = pjmedia_sdp_neg_modify_local_offer(inv->pool, inv->neg,
1511 reoffer_sdp);
1512 if (status != PJ_SUCCESS) {
1513 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1514 "forked 2xx response (err=%d)", status));
1515 return status;
1516 }
1517
1518 } else {
1519
1520 if (rdata->msg_info.msg->body) {
1521 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1522 "body is ignored"));
1523 }
1524 return PJ_SUCCESS;
1525 }
1526 }
1527
Benny Prijonoa66c7152006-02-09 01:26:14 +00001528 /* Parse the SDP body. */
1529
Benny Prijonoa1e69682007-05-11 15:14:34 +00001530 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1531 (char*)msg->body->data,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001532 msg->body->len, &rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001533 if (status == PJ_SUCCESS)
Benny Prijono8fcb4332008-10-31 18:01:48 +00001534 status = pjmedia_sdp_validate(rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001535
Benny Prijonoa66c7152006-02-09 01:26:14 +00001536 if (status != PJ_SUCCESS) {
1537 char errmsg[PJ_ERR_MSG_SIZE];
1538 pj_strerror(status, errmsg, sizeof(errmsg));
1539 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1540 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001541 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001542 }
1543
1544 /* The SDP can be an offer or answer, depending on negotiator's state */
1545
1546 if (inv->neg == NULL ||
1547 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1548 {
1549
1550 /* This is an offer. */
1551
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001552 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1553 pjsip_rx_data_get_info(rdata)));
1554
Benny Prijonoa66c7152006-02-09 01:26:14 +00001555 if (inv->neg == NULL) {
1556 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001557 rem_sdp, &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001558 } else {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001559 status=pjmedia_sdp_neg_set_remote_offer(inv->pool, inv->neg,
1560 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001561 }
1562
1563 if (status != PJ_SUCCESS) {
1564 char errmsg[PJ_ERR_MSG_SIZE];
1565 pj_strerror(status, errmsg, sizeof(errmsg));
1566 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1567 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001568 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001569 }
1570
1571 /* Inform application about remote offer. */
1572
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001573 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001574
Benny Prijono8fcb4332008-10-31 18:01:48 +00001575 (*mod_inv.cb.on_rx_offer)(inv, rem_sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001576
1577 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001578
1579 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1580 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1581 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001582 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001583
1584 /* This is an answer.
1585 * Process and negotiate remote answer.
1586 */
1587
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001588 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1589 pjsip_rx_data_get_info(rdata)));
1590
Benny Prijono8fcb4332008-10-31 18:01:48 +00001591 status = pjmedia_sdp_neg_set_remote_answer(inv->pool, inv->neg,
1592 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001593
1594 if (status != PJ_SUCCESS) {
1595 char errmsg[PJ_ERR_MSG_SIZE];
1596 pj_strerror(status, errmsg, sizeof(errmsg));
1597 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1598 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001599 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001600 }
1601
1602 /* Negotiate SDP */
1603
1604 inv_negotiate_sdp(inv);
1605
Benny Prijono8fcb4332008-10-31 18:01:48 +00001606 /* Mark this transaction has having SDP offer/answer done, and
1607 * save the reference to the To tag
1608 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001609
1610 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001611 status_code = rdata->msg_info.msg->line.status.code;
1612 tsx_inv_data->done_early = (status_code/100==1);
1613 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1614 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001615
1616 } else {
1617
1618 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1619 pjsip_rx_data_get_info(rdata),
1620 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1621 }
1622
Benny Prijono26ff9062006-02-21 23:47:00 +00001623 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001624}
1625
1626
Benny Prijono26ff9062006-02-21 23:47:00 +00001627/*
1628 * Process INVITE answer, for both initial and subsequent re-INVITE
1629 */
1630static pj_status_t process_answer( pjsip_inv_session *inv,
1631 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001632 pjsip_tx_data *tdata,
1633 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001634{
1635 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001636 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001637
Benny Prijono64f851e2006-02-23 13:49:28 +00001638 /* If local_sdp is specified, then we MUST NOT have answered the
1639 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001640 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001641 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1642
1643 if (inv->neg == NULL) {
1644 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1645 &inv->neg);
1646 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1647 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1648 {
1649 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
1650 local_sdp);
1651 } else {
1652
1653 /* Can not specify local SDP at this state. */
1654 pj_assert(0);
1655 status = PJMEDIA_SDPNEG_EINSTATE;
1656 }
1657
1658 if (status != PJ_SUCCESS)
1659 return status;
1660
1661 }
1662
1663
1664 /* If SDP negotiator is ready, start negotiation. */
1665 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001666
1667 pjmedia_sdp_neg_state neg_state;
1668
Benny Prijono64f851e2006-02-23 13:49:28 +00001669 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001670 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1671 PJMEDIA_SDP_NEG_STATE_NULL;
1672
1673 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1674
1675 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1676
1677 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1678 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1679 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001680 struct tsx_inv_data *tsx_inv_data;
1681
1682 /* Get invite session's transaction data */
1683 tsx_inv_data = (struct tsx_inv_data*)
1684 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001685
1686 status = inv_negotiate_sdp(inv);
1687 if (status != PJ_SUCCESS)
1688 return status;
1689
Benny Prijono77998ce2007-06-20 10:03:46 +00001690 /* Mark this transaction has having SDP offer/answer done. */
1691 tsx_inv_data->sdp_done = 1;
1692
Benny Prijono26ff9062006-02-21 23:47:00 +00001693 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1694 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001695 }
1696
Benny Prijono64f851e2006-02-23 13:49:28 +00001697 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001698 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001699 *
1700 * Note note:
1701 * - When offer/answer has been completed in reliable 183, we MUST NOT
1702 * send SDP in 2xx response. So if we don't have SDP to send, clear
1703 * the SDP in the message body ONLY if 100rel is active in this
1704 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001705 */
1706 if (sdp) {
1707 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001708 } else {
1709 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1710 tdata->msg->body = NULL;
1711 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001712 }
1713
Benny Prijono26ff9062006-02-21 23:47:00 +00001714
1715 return PJ_SUCCESS;
1716}
1717
Benny Prijonoa66c7152006-02-09 01:26:14 +00001718
1719/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001720 * Create first response to INVITE
1721 */
1722PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1723 pjsip_rx_data *rdata,
1724 int st_code,
1725 const pj_str_t *st_text,
1726 const pjmedia_sdp_session *sdp,
1727 pjsip_tx_data **p_tdata)
1728{
1729 pjsip_tx_data *tdata;
1730 pj_status_t status;
1731
1732 /* Verify arguments. */
1733 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1734
1735 /* Must have INVITE transaction. */
1736 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1737
1738 pjsip_dlg_inc_lock(inv->dlg);
1739
1740 /* Create response */
1741 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1742 &tdata);
1743 if (status != PJ_SUCCESS)
1744 goto on_return;
1745
1746 /* Process SDP in answer */
1747 status = process_answer(inv, st_code, tdata, sdp);
1748 if (status != PJ_SUCCESS) {
1749 pjsip_tx_data_dec_ref(tdata);
1750 goto on_return;
1751 }
1752
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001753 /* Save this answer */
1754 inv->last_answer = tdata;
1755 pjsip_tx_data_add_ref(inv->last_answer);
1756 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1757 pjsip_tx_data_get_info(inv->last_answer)));
1758
Benny Prijono64f851e2006-02-23 13:49:28 +00001759 *p_tdata = tdata;
1760
1761on_return:
1762 pjsip_dlg_dec_lock(inv->dlg);
1763 return status;
1764}
1765
1766
1767/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001768 * Answer initial INVITE
1769 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001770 */
1771PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1772 int st_code,
1773 const pj_str_t *st_text,
1774 const pjmedia_sdp_session *local_sdp,
1775 pjsip_tx_data **p_tdata )
1776{
1777 pjsip_tx_data *last_res;
1778 pj_status_t status;
1779
1780 /* Verify arguments. */
1781 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1782
1783 /* Must have INVITE transaction. */
1784 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1785
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001786 /* Must have created an answer before */
1787 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001788
Benny Prijono64f851e2006-02-23 13:49:28 +00001789 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001790
1791 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001792 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001793 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1794 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001795 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001796
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001797 /* For non-2xx final response, strip message body */
1798 if (st_code >= 300) {
1799 last_res->msg->body = NULL;
1800 }
Benny Prijono268ca612006-02-07 12:34:11 +00001801
Benny Prijono26ff9062006-02-21 23:47:00 +00001802 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001803 status = process_answer(inv, st_code, last_res, local_sdp);
1804 if (status != PJ_SUCCESS) {
1805 pjsip_tx_data_dec_ref(last_res);
1806 goto on_return;
1807 }
Benny Prijono268ca612006-02-07 12:34:11 +00001808
Benny Prijono268ca612006-02-07 12:34:11 +00001809
1810 *p_tdata = last_res;
1811
Benny Prijono64f851e2006-02-23 13:49:28 +00001812on_return:
1813 pjsip_dlg_dec_lock(inv->dlg);
1814 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001815}
1816
1817
1818/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001819 * Set SDP answer.
1820 */
1821PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1822 const pjmedia_sdp_session *sdp )
1823{
1824 pj_status_t status;
1825
1826 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1827
1828 pjsip_dlg_inc_lock(inv->dlg);
1829 status = pjmedia_sdp_neg_set_local_answer( inv->pool, inv->neg, sdp);
1830 pjsip_dlg_dec_lock(inv->dlg);
1831
1832 return status;
1833}
1834
1835
1836/*
Benny Prijono268ca612006-02-07 12:34:11 +00001837 * End session.
1838 */
1839PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
1840 int st_code,
1841 const pj_str_t *st_text,
1842 pjsip_tx_data **p_tdata )
1843{
1844 pjsip_tx_data *tdata;
1845 pj_status_t status;
1846
1847 /* Verify arguments. */
1848 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1849
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001850 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001851 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001852
Benny Prijono268ca612006-02-07 12:34:11 +00001853 /* Create appropriate message. */
1854 switch (inv->state) {
1855 case PJSIP_INV_STATE_CALLING:
1856 case PJSIP_INV_STATE_EARLY:
1857 case PJSIP_INV_STATE_INCOMING:
1858
1859 if (inv->role == PJSIP_ROLE_UAC) {
1860
1861 /* For UAC when session has not been confirmed, create CANCEL. */
1862
1863 /* MUST have the original UAC INVITE transaction. */
1864 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
1865
1866 /* But CANCEL should only be called when we have received a
1867 * provisional response. If we haven't received any responses,
1868 * just destroy the transaction.
1869 */
1870 if (inv->invite_tsx->status_code < 100) {
1871
Benny Prijono1dc8be02007-05-30 04:26:40 +00001872 pjsip_tsx_stop_retransmit(inv->invite_tsx);
1873 inv->cancelling = PJ_TRUE;
1874 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00001875 *p_tdata = NULL;
Benny Prijono1dc8be02007-05-30 04:26:40 +00001876 PJ_LOG(4, (inv->obj_name, "Stopping retransmission, "
1877 "delaying CANCEL"));
Benny Prijonofccab712006-02-22 22:23:22 +00001878 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001879 }
1880
1881 /* The CSeq here assumes that the dialog is started with an
1882 * INVITE session. This may not be correct; dialog can be
1883 * started as SUBSCRIBE session.
1884 * So fix this!
1885 */
1886 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
1887 inv->invite_tsx->last_tx,
1888 &tdata);
1889
1890 } else {
1891
1892 /* For UAS, send a final response. */
1893 tdata = inv->invite_tsx->last_tx;
1894 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
1895
Benny Prijono26ff9062006-02-21 23:47:00 +00001896 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
1897 // st_text);
1898 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001899 }
1900 break;
1901
1902 case PJSIP_INV_STATE_CONNECTING:
1903 case PJSIP_INV_STATE_CONFIRMED:
1904 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001905 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
1906 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001907 break;
1908
1909 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00001910 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001911 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00001912
1913 default:
1914 pj_assert("!Invalid operation!");
1915 return PJ_EINVALIDOP;
1916 }
1917
1918 if (status != PJ_SUCCESS)
1919 return status;
1920
1921
1922 /* Done */
1923
Benny Prijono0606e702007-05-22 12:21:40 +00001924 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00001925 *p_tdata = tdata;
1926
1927 return PJ_SUCCESS;
1928}
1929
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001930/* Following redirection recursion, get next target from the target set and
1931 * notify user.
1932 *
1933 * Returns PJ_FALSE if recursion fails (either because there's no more target
1934 * or user rejects the recursion). If we return PJ_FALSE, caller should
1935 * disconnect the session.
1936 *
1937 * Note:
1938 * the event 'e' argument may be NULL.
1939 */
1940static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
1941 const pj_str_t *reason, pjsip_event *e)
1942{
Benny Prijono08a48b82008-11-27 12:42:07 +00001943 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001944 pjsip_target *target;
1945
1946 /* Won't redirect if the callback is not implemented. */
1947 if (mod_inv.cb.on_redirected == NULL)
1948 return PJ_FALSE;
1949
1950 if (reason == NULL)
1951 reason = pjsip_get_status_text(code);
1952
1953 /* Set status of current target */
1954 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
1955 code, reason);
1956
1957 /* Fetch next target from the target set. We only want to
1958 * process SIP/SIPS URI for now.
1959 */
1960 for (;;) {
1961 target = pjsip_target_set_get_next(&inv->dlg->target_set);
1962 if (target == NULL) {
1963 /* No more target. */
1964 return PJ_FALSE;
1965 }
1966
1967 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
1968 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
1969 {
1970 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
1971 reason = pjsip_get_status_text(code);
1972
1973 /* Mark this target as unusable and fetch next target. */
1974 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
1975 } else {
1976 /* Found a target */
1977 break;
1978 }
1979 }
1980
1981 /* We have target in 'target'. Set this target as current target
1982 * and notify callback.
1983 */
1984 pjsip_target_set_set_current(&inv->dlg->target_set, target);
1985
Benny Prijono08a48b82008-11-27 12:42:07 +00001986 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001987
1988
1989 /* Check what the application wants to do now */
1990 switch (op) {
1991 case PJSIP_REDIRECT_ACCEPT:
1992 case PJSIP_REDIRECT_STOP:
1993 /* Must increment session counter, that's the convention of the
1994 * pjsip_inv_process_redirect().
1995 */
1996 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
1997
1998 /* Act on the recursion */
1999 pjsip_inv_process_redirect(inv, op, e);
2000 return PJ_TRUE;
2001
2002 case PJSIP_REDIRECT_PENDING:
2003 /* Increment session so that the dialog/session is not destroyed
2004 * while we're waiting for user confirmation.
2005 */
2006 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2007
2008 /* Also clear the invite_tsx variable, otherwise when this tsx is
2009 * terminated, it will also terminate the session.
2010 */
2011 inv->invite_tsx = NULL;
2012
2013 /* Done. The processing will continue once the application calls
2014 * pjsip_inv_process_redirect().
2015 */
2016 return PJ_TRUE;
2017
2018 case PJSIP_REDIRECT_REJECT:
2019 /* Recursively call this function again to fetch next target, if any.
2020 */
2021 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2022
2023 }
2024
2025 pj_assert(!"Should not reach here");
2026 return PJ_FALSE;
2027}
2028
2029
2030/* Process redirection/recursion */
2031PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2032 pjsip_redirect_op op,
2033 pjsip_event *e)
2034{
2035 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2036 pjsip_event usr_event;
2037 pj_status_t status = PJ_SUCCESS;
2038
2039 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2040
2041 if (e == NULL) {
2042 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2043 e = &usr_event;
2044 }
2045
2046 pjsip_dlg_inc_lock(inv->dlg);
2047
2048 /* Decrement session. That's the convention here to prevent the dialog
2049 * or session from being destroyed while we're waiting for user
2050 * confirmation.
2051 */
2052 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2053
2054 /* See what the application wants to do now */
2055 switch (op) {
2056 case PJSIP_REDIRECT_ACCEPT:
2057 /* User accept the redirection. Reset the session and resend the
2058 * INVITE request.
2059 */
2060 {
2061 pjsip_tx_data *tdata;
2062 pjsip_via_hdr *via;
2063
2064 /* Get the original INVITE request. */
2065 tdata = inv->invite_req;
2066 pjsip_tx_data_add_ref(tdata);
2067
2068 /* Restore strict route set.
2069 * See http://trac.pjsip.org/repos/ticket/492
2070 */
2071 pjsip_restore_strict_route_set(tdata);
2072
2073 /* Set target */
Benny Prijono20da7992008-12-18 16:48:43 +00002074 tdata->msg->line.req.uri = (pjsip_uri*)
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002075 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2076
2077 /* Remove branch param in Via header. */
2078 via = (pjsip_via_hdr*)
2079 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2080 via->branch_param.slen = 0;
2081
2082 /* Must invalidate the message! */
2083 pjsip_tx_data_invalidate_msg(tdata);
2084
2085 /* Reset the session */
2086 pjsip_inv_uac_restart(inv, PJ_FALSE);
2087
2088 /* (re)Send the INVITE request */
2089 status = pjsip_inv_send_msg(inv, tdata);
2090 }
2091 break;
2092
2093 case PJSIP_REDIRECT_STOP:
2094 /* User doesn't want the redirection. Disconnect the session now. */
2095 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2096 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2097
2098 /* Caller should expect that the invite session is gone now, so
2099 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2100 */
2101 break;
2102
2103 case PJSIP_REDIRECT_REJECT:
2104 /* Current target is rejected. Fetch next target if any. */
2105 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2106 inv_set_cause(inv, cancel_code,
2107 pjsip_get_status_text(cancel_code));
2108 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2109
2110 /* Tell caller that the invite session is gone now */
2111 status = PJSIP_ESESSIONTERMINATED;
2112 }
2113 break;
2114
2115
2116 case PJSIP_REDIRECT_PENDING:
2117 pj_assert(!"Should not happen");
2118 break;
2119 }
2120
2121
2122 pjsip_dlg_dec_lock(inv->dlg);
2123
2124 return status;
2125}
2126
Benny Prijono268ca612006-02-07 12:34:11 +00002127
2128/*
2129 * Create re-INVITE.
2130 */
2131PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2132 const pj_str_t *new_contact,
2133 const pjmedia_sdp_session *new_offer,
2134 pjsip_tx_data **p_tdata )
2135{
Benny Prijono26ff9062006-02-21 23:47:00 +00002136 pj_status_t status;
2137 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002138
Benny Prijono26ff9062006-02-21 23:47:00 +00002139 /* Check arguments. */
2140 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2141
2142 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002143 if (inv->invite_tsx!=NULL)
2144 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002145
2146
2147 pjsip_dlg_inc_lock(inv->dlg);
2148
2149 if (new_contact) {
2150 pj_str_t tmp;
2151 const pj_str_t STR_CONTACT = { "Contact", 7 };
2152
2153 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002154 contact_hdr = (pjsip_contact_hdr*)
2155 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002156 tmp.ptr, tmp.slen, NULL);
2157 if (!contact_hdr) {
2158 status = PJSIP_EINVALIDURI;
2159 goto on_return;
2160 }
2161 }
2162
2163
2164 if (new_offer) {
2165 if (!inv->neg) {
2166 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer,
2167 &inv->neg);
2168 if (status != PJ_SUCCESS)
2169 goto on_return;
2170
2171 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2172
2173 case PJMEDIA_SDP_NEG_STATE_NULL:
2174 pj_assert(!"Unexpected SDP neg state NULL");
2175 status = PJ_EBUG;
2176 goto on_return;
2177
2178 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2179 PJ_LOG(4,(inv->obj_name,
2180 "pjsip_inv_reinvite: already have an offer, new "
2181 "offer is ignored"));
2182 break;
2183
2184 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
2185 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
2186 new_offer);
2187 if (status != PJ_SUCCESS)
2188 goto on_return;
2189 break;
2190
2191 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2192 PJ_LOG(4,(inv->obj_name,
2193 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2194 "offer is ignored"));
2195 break;
2196
2197 case PJMEDIA_SDP_NEG_STATE_DONE:
2198 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2199 new_offer);
2200 if (status != PJ_SUCCESS)
2201 goto on_return;
2202 break;
2203 }
2204 }
2205
2206 if (contact_hdr)
2207 inv->dlg->local.contact = contact_hdr;
2208
2209 status = pjsip_inv_invite(inv, p_tdata);
2210
2211on_return:
2212 pjsip_dlg_dec_lock(inv->dlg);
2213 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002214}
2215
2216/*
2217 * Create UPDATE.
2218 */
2219PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2220 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002221 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002222 pjsip_tx_data **p_tdata )
2223{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002224 pjsip_contact_hdr *contact_hdr = NULL;
2225 pjsip_tx_data *tdata = NULL;
2226 pjmedia_sdp_session *sdp_copy;
2227 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002228
Benny Prijono1f7767b2007-10-03 18:28:49 +00002229 /* Verify arguments. */
2230 PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL);
2231
2232 /* Dialog must have been established */
2233 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2234 PJ_EINVALIDOP);
2235
2236 /* Invite session must not have been disconnected */
2237 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2238 PJ_EINVALIDOP);
2239
2240 /* Lock dialog. */
2241 pjsip_dlg_inc_lock(inv->dlg);
2242
2243 /* Process offer */
2244 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2245 PJ_LOG(4,(inv->dlg->obj_name,
2246 "Invalid SDP offer/answer state for UPDATE"));
2247 status = PJ_EINVALIDOP;
2248 goto on_error;
2249 }
2250
Benny Prijono60e31fc2009-04-23 11:50:25 +00002251 /* Notify negotiator about the new offer. This will fix the offer
2252 * with correct SDP origin.
2253 */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002254 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2255 offer);
2256 if (status != PJ_SUCCESS)
2257 goto on_error;
2258
Benny Prijono60e31fc2009-04-23 11:50:25 +00002259 /* Retrieve the "fixed" offer from negotiator */
2260 pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002261
2262 /* Update Contact if required */
2263 if (new_contact) {
2264 pj_str_t tmp;
2265 const pj_str_t STR_CONTACT = { "Contact", 7 };
2266
2267 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2268 contact_hdr = (pjsip_contact_hdr*)
2269 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2270 tmp.ptr, tmp.slen, NULL);
2271 if (!contact_hdr) {
2272 status = PJSIP_EINVALIDURI;
2273 goto on_error;
2274 }
2275
2276 inv->dlg->local.contact = contact_hdr;
2277 }
2278
2279 /* Create request */
2280 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2281 -1, &tdata);
2282 if (status != PJ_SUCCESS)
2283 goto on_error;
2284
2285 /* Attach SDP body */
2286 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2287 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2288
2289 /* Unlock dialog. */
2290 pjsip_dlg_dec_lock(inv->dlg);
2291
2292 *p_tdata = tdata;
2293
2294 return PJ_SUCCESS;
2295
2296on_error:
2297 if (tdata)
2298 pjsip_tx_data_dec_ref(tdata);
2299
2300 /* Unlock dialog. */
2301 pjsip_dlg_dec_lock(inv->dlg);
2302
2303 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002304}
2305
2306/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002307 * Create an ACK request.
2308 */
2309PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2310 int cseq,
2311 pjsip_tx_data **p_tdata)
2312{
2313 const pjmedia_sdp_session *sdp = NULL;
2314 pj_status_t status;
2315
2316 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2317
2318 /* Lock dialog. */
2319 pjsip_dlg_inc_lock(inv->dlg);
2320
2321 /* Destroy last_ack */
2322 if (inv->last_ack) {
2323 pjsip_tx_data_dec_ref(inv->last_ack);
2324 inv->last_ack = NULL;
2325 }
2326
2327 /* Create new ACK request */
2328 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2329 cseq, &inv->last_ack);
2330 if (status != PJ_SUCCESS) {
2331 pjsip_dlg_dec_lock(inv->dlg);
2332 return status;
2333 }
2334
2335 /* See if we have pending SDP answer to send */
2336 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2337 if (sdp) {
2338 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2339 }
2340
2341 /* Keep this for subsequent response retransmission */
2342 inv->last_ack_cseq = cseq;
2343 pjsip_tx_data_add_ref(inv->last_ack);
2344
2345 /* Done */
2346 *p_tdata = inv->last_ack;
2347
2348 /* Unlock dialog. */
2349 pjsip_dlg_dec_lock(inv->dlg);
2350
2351 return PJ_SUCCESS;
2352}
2353
2354/*
Benny Prijono268ca612006-02-07 12:34:11 +00002355 * Send a request or response message.
2356 */
2357PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002358 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002359{
2360 pj_status_t status;
2361
2362 /* Verify arguments. */
2363 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2364
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002365 PJ_LOG(5,(inv->obj_name, "Sending %s",
2366 pjsip_tx_data_get_info(tdata)));
2367
Benny Prijono268ca612006-02-07 12:34:11 +00002368 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002369 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002370
Benny Prijono64158af2006-04-04 11:06:34 +00002371 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002372
Benny Prijono22e48c92008-03-20 14:40:50 +00002373 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002374 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2375 inv->invite_tsx)
2376 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002377 pjsip_tx_data_dec_ref(tdata);
2378 pjsip_dlg_dec_lock(inv->dlg);
2379 return PJ_EINVALIDOP;
2380 }
2381
2382 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002383 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002384 tsx_inv_data->inv = inv;
2385
Benny Prijono64158af2006-04-04 11:06:34 +00002386 pjsip_dlg_dec_lock(inv->dlg);
2387
2388 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2389 tsx_inv_data);
2390 if (status != PJ_SUCCESS)
2391 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002392
2393 } else {
2394 pjsip_cseq_hdr *cseq;
2395
2396 /* Can only do this to send response to original INVITE
2397 * request.
2398 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002399 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 +00002400 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002401 PJ_EINVALIDOP);
2402
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002403 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002404 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002405 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002406 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002407 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002408 }
2409
Benny Prijono268ca612006-02-07 12:34:11 +00002410 if (status != PJ_SUCCESS)
2411 return status;
2412 }
2413
2414 /* Done (?) */
2415 return PJ_SUCCESS;
2416}
2417
2418
Benny Prijono8ad55352006-02-08 11:16:05 +00002419/*
2420 * Respond to incoming CANCEL request.
2421 */
2422static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2423 pjsip_transaction *cancel_tsx,
2424 pjsip_rx_data *rdata)
2425{
2426 pjsip_tx_data *tdata;
2427 pjsip_transaction *invite_tsx;
2428 pj_str_t key;
2429 pj_status_t status;
2430
2431 /* See if we have matching INVITE server transaction: */
2432
2433 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002434 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002435 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2436
2437 if (invite_tsx == NULL) {
2438
2439 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002440 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002441 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002442 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002443 &tdata);
2444
2445 } else {
2446 /* Always answer CANCEL will 200 (OK) regardless of
2447 * the state of the INVITE transaction.
2448 */
2449 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2450 &tdata);
2451 }
2452
2453 /* See if we have created the response successfully. */
2454 if (status != PJ_SUCCESS) return;
2455
2456 /* Send the CANCEL response */
2457 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2458 if (status != PJ_SUCCESS) return;
2459
2460
2461 /* See if we need to terminate the UAS INVITE transaction
2462 * with 487 (Request Terminated) response.
2463 */
2464 if (invite_tsx && invite_tsx->status_code < 200) {
2465
2466 pj_assert(invite_tsx->last_tx != NULL);
2467
2468 tdata = invite_tsx->last_tx;
2469
2470 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002471 if (status == PJ_SUCCESS) {
2472 /* Remove the message body */
2473 tdata->msg->body = NULL;
Benny Prijono8ad55352006-02-08 11:16:05 +00002474 pjsip_dlg_send_response(inv->dlg, invite_tsx, tdata);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002475 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002476 }
2477
2478 if (invite_tsx)
2479 pj_mutex_unlock(invite_tsx->mutex);
2480}
2481
2482
2483/*
2484 * Respond to incoming BYE request.
2485 */
2486static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2487 pjsip_transaction *bye_tsx,
2488 pjsip_rx_data *rdata,
2489 pjsip_event *e )
2490{
2491 pj_status_t status;
2492 pjsip_tx_data *tdata;
2493
2494 /* Respond BYE with 200: */
2495
2496 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2497 if (status != PJ_SUCCESS) return;
2498
2499 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2500 if (status != PJ_SUCCESS) return;
2501
2502 /* Terminate session: */
2503
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002504 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002505 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002506 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002507 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002508}
2509
2510/*
Benny Prijono38998232006-02-08 22:44:25 +00002511 * Respond to BYE request.
2512 */
2513static void inv_handle_bye_response( pjsip_inv_session *inv,
2514 pjsip_transaction *tsx,
2515 pjsip_rx_data *rdata,
2516 pjsip_event *e )
2517{
2518 pj_status_t status;
2519
2520 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002521 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002522 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2523 return;
2524 }
2525
2526 /* Handle 401/407 challenge. */
2527 if (tsx->status_code == 401 || tsx->status_code == 407) {
2528
2529 pjsip_tx_data *tdata;
2530
2531 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2532 rdata,
2533 tsx->last_tx,
2534 &tdata);
2535
2536 if (status != PJ_SUCCESS) {
2537
2538 /* Does not have proper credentials.
2539 * End the session anyway.
2540 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002541 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002542 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2543
2544 } else {
2545 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002546 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002547 }
2548
2549 } else {
2550
2551 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002552 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002553 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2554 }
2555
2556}
2557
2558/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002559 * Respond to incoming UPDATE request.
2560 */
2561static void inv_respond_incoming_update(pjsip_inv_session *inv,
2562 pjsip_rx_data *rdata)
2563{
2564 pjmedia_sdp_neg_state neg_state;
2565 pj_status_t status;
2566 pjsip_tx_data *tdata = NULL;
2567
2568 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2569
2570 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2571 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2572 status = pjsip_dlg_create_response(inv->dlg, rdata,
2573 PJSIP_SC_REQUEST_PENDING, NULL,
2574 &tdata);
2575 }
2576 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2577 * receive UPDATE while we haven't sent answer.
2578 */
2579 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2580 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2581 status = pjsip_dlg_create_response(inv->dlg, rdata,
2582 PJSIP_SC_INTERNAL_SERVER_ERROR,
2583 NULL, &tdata);
2584
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002585 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2586 * This is a valid scenario according to session-timer draft.
2587 */
2588 } else if (rdata->msg_info.msg->body == NULL) {
2589
2590 status = pjsip_dlg_create_response(inv->dlg, rdata,
2591 200, NULL, &tdata);
2592
Benny Prijono1f7767b2007-10-03 18:28:49 +00002593 } else {
2594 /* We receive new offer from remote */
2595 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2596
2597 /* Application MUST have supplied the answer by now.
2598 * If so, negotiate the SDP.
2599 */
2600 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2601 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2602 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2603 {
2604 /* Negotiation has failed */
2605 status = pjsip_dlg_create_response(inv->dlg, rdata,
2606 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2607 NULL, &tdata);
2608 } else {
2609 /* New media has been negotiated successfully, send 200/OK */
2610 status = pjsip_dlg_create_response(inv->dlg, rdata,
2611 PJSIP_SC_OK, NULL, &tdata);
2612 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002613 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002614 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2615 if (status == PJ_SUCCESS)
2616 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2617 }
2618 }
2619 }
2620
2621 if (status != PJ_SUCCESS) {
2622 if (tdata != NULL) {
2623 pjsip_tx_data_dec_ref(tdata);
2624 tdata = NULL;
2625 }
2626 return;
2627 }
2628
2629 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2630}
2631
2632
2633/*
2634 * Handle incoming response to UAC UPDATE request.
2635 */
2636static void inv_handle_update_response( pjsip_inv_session *inv,
2637 pjsip_event *e)
2638{
2639 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2640 struct tsx_inv_data *tsx_inv_data = NULL;
2641 pj_status_t status = -1;
2642
Benny Prijono48ab2b72007-11-08 09:24:30 +00002643 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002644 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono48ab2b72007-11-08 09:24:30 +00002645 (tsx->status_code == 401 || tsx->status_code == 407)) {
2646
2647 pjsip_tx_data *tdata;
2648
2649 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2650 e->body.tsx_state.src.rdata,
2651 tsx->last_tx,
2652 &tdata);
2653
2654 if (status != PJ_SUCCESS) {
2655
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002656 /* Somehow failed. Probably it's not a good idea to terminate
2657 * the session since this is just a request within dialog. And
2658 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002659 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002660 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002661 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2662 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002663 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002664
2665 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002666 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002667 status = pjsip_inv_send_msg(inv, tdata);
2668 }
2669
2670 /* Process 2xx response */
2671 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002672 tsx->status_code/100 == 2 &&
2673 e->body.tsx_state.src.rdata->msg_info.msg->body)
2674 {
2675 status = inv_check_sdp_in_incoming_msg(inv, tsx,
2676 e->body.tsx_state.src.rdata);
2677
2678 } else {
2679 /* Get/attach invite session's transaction data */
2680 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2681 if (tsx_inv_data == NULL) {
2682 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2683 tsx_inv_data->inv = inv;
2684 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2685 }
2686 }
2687
2688 /* Otherwise if we don't get successful response, cancel
2689 * our negotiator.
2690 */
2691 if (status != PJ_SUCCESS &&
2692 pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
2693 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2694 {
2695 pjmedia_sdp_neg_cancel_offer(inv->neg);
2696
2697 /* Prevent from us cancelling different offer! */
2698 tsx_inv_data->sdp_done = PJ_TRUE;
2699 }
2700}
2701
2702
2703/*
2704 * Handle incoming reliable response.
2705 */
2706static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2707 pjsip_rx_data *rdata)
2708{
2709 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002710 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002711 pj_status_t status;
2712
2713 /* Create PRACK */
2714 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2715 if (status != PJ_SUCCESS)
2716 return;
2717
2718 /* See if we need to attach SDP answer on the PRACK request */
2719 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2720 if (sdp) {
2721 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2722 }
2723
2724 /* Send PRACK (must be using 100rel module!) */
2725 pjsip_100rel_send_prack(inv, tdata);
2726}
2727
2728
2729/*
2730 * Handle incoming PRACK.
2731 */
2732static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2733 pjsip_rx_data *rdata)
2734{
2735 pj_status_t status;
2736
2737 /* Run through 100rel module to see if we can accept this
2738 * PRACK request. The 100rel will send 200/OK to PRACK request.
2739 */
2740 status = pjsip_100rel_on_rx_prack(inv, rdata);
2741 if (status != PJ_SUCCESS)
2742 return;
2743
2744 /* Now check for SDP answer in the PRACK request */
2745 if (rdata->msg_info.msg->body) {
2746 status = inv_check_sdp_in_incoming_msg(inv,
2747 pjsip_rdata_get_tsx(rdata), rdata);
2748 } else {
2749 /* No SDP body */
2750 status = -1;
2751 }
2752
2753 /* If SDP negotiation has been successful, also mark the
2754 * SDP negotiation flag in the invite transaction to be
2755 * done too.
2756 */
2757 if (status == PJ_SUCCESS && inv->invite_tsx) {
2758 struct tsx_inv_data *tsx_inv_data;
2759
2760 /* Get/attach invite session's transaction data */
2761 tsx_inv_data = (struct tsx_inv_data*)
2762 inv->invite_tsx->mod_data[mod_inv.mod.id];
2763 if (tsx_inv_data == NULL) {
2764 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2765 struct tsx_inv_data);
2766 tsx_inv_data->inv = inv;
2767 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2768 }
2769
2770 tsx_inv_data->sdp_done = PJ_TRUE;
2771 }
2772}
2773
2774
2775/*
Benny Prijono8ad55352006-02-08 11:16:05 +00002776 * State NULL is before anything is sent/received.
2777 */
2778static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002779{
2780 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2781 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2782
2783 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2784
2785 if (tsx->method.id == PJSIP_INVITE_METHOD) {
2786
Benny Prijono64f851e2006-02-23 13:49:28 +00002787 /* Keep the initial INVITE transaction. */
2788 if (inv->invite_tsx == NULL)
2789 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00002790
Benny Prijono64f851e2006-02-23 13:49:28 +00002791 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00002792
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002793 /* Save the original INVITE request, if on_redirected() callback
2794 * is implemented. We may need to resend the INVITE if we receive
2795 * redirection response.
2796 */
2797 if (mod_inv.cb.on_redirected) {
2798 if (inv->invite_req) {
2799 pjsip_tx_data_dec_ref(inv->invite_req);
2800 inv->invite_req = NULL;
2801 }
2802 inv->invite_req = tsx->last_tx;
2803 pjsip_tx_data_add_ref(inv->invite_req);
2804 }
2805
Benny Prijono268ca612006-02-07 12:34:11 +00002806 switch (tsx->state) {
2807 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002808 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002809 break;
2810 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002811 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002812 break;
2813 }
2814
2815 } else {
2816 switch (tsx->state) {
2817 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002818 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002819 break;
Benny Prijono38998232006-02-08 22:44:25 +00002820 case PJSIP_TSX_STATE_PROCEEDING:
2821 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
2822 if (tsx->status_code > 100)
2823 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
2824 break;
Benny Prijono2285e7e2008-12-17 14:28:18 +00002825 case PJSIP_TSX_STATE_TERMINATED:
2826 /* there is a failure in sending response. */
2827 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2828 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2829 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002830 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002831 inv_on_state_incoming(inv, e);
2832 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002833 }
2834 }
2835
2836 } else {
2837 pj_assert(!"Unexpected transaction type");
2838 }
2839}
2840
Benny Prijono8ad55352006-02-08 11:16:05 +00002841/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002842 * Generic UAC transaction handler:
2843 * - resend request on 401 or 407 response.
2844 * - terminate dialog on 408 and 481 response.
2845 */
2846static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
2847 pjsip_event *e)
2848{
2849 /* RFC 3261 Section 12.2.1.2:
2850 * If the response for a request within a dialog is a 481
2851 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
2852 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
2853 * no response at all is received for the request (the client
2854 * transaction would inform the TU about the timeout.)
2855 *
2856 * For INVITE initiated dialogs, terminating the dialog consists of
2857 * sending a BYE.
2858 *
2859 * Note:
2860 * according to X, this should terminate dialog usage only, not the
2861 * dialog.
2862 */
2863 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2864
2865 pj_assert(tsx->role == PJSIP_UAC_ROLE);
2866
2867 /* Note that 481 response to CANCEL does not terminate dialog usage,
2868 * but only the transaction.
2869 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00002870 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
2871 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002872 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00002873 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
2874 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
2875 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002876 {
2877 pjsip_tx_data *bye;
2878 pj_status_t status;
2879
2880 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2881 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2882
2883 /* Send BYE */
2884 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2885 -1, &bye);
2886 if (status == PJ_SUCCESS) {
2887 pjsip_inv_send_msg(inv, bye);
2888 }
2889
2890 return PJ_TRUE; /* Handled */
2891
2892 }
2893 /* Handle 401/407 challenge. */
2894 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2895 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
2896 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
2897 {
2898
2899 pjsip_tx_data *tdata;
2900 pj_status_t status;
2901
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002902 if (tsx->method.id == PJSIP_INVITE_METHOD)
2903 inv->invite_tsx = NULL;
2904
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002905 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2906 e->body.tsx_state.src.rdata,
2907 tsx->last_tx, &tdata);
2908
2909 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002910 /* Somehow failed. Probably it's not a good idea to terminate
2911 * the session since this is just a request within dialog. And
2912 * even if we terminate we should send BYE.
2913 */
2914 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002915 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2916 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002917 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002918
2919 } else {
2920 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002921 status = pjsip_inv_send_msg(inv, tdata);
2922 }
2923
2924 return PJ_TRUE; /* Handled */
2925
2926 } else {
2927 return PJ_FALSE; /* Unhandled */
2928 }
2929}
2930
2931
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002932/* Handle call rejection, especially with regard to processing call
2933 * redirection. We need to handle the following scenarios:
2934 * - 3xx response is received -- see if on_redirected() callback is
2935 * implemented. If so, add the Contact URIs in the response to the
2936 * target set and notify user.
2937 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
2938 * if so fetch the next target if any and notify the on_redirected()
2939 * callback.
2940 * - for other cases -- disconnect the session.
2941 */
2942static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
2943{
2944 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2945 pj_status_t status;
2946
2947 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
2948
2949 if (mod_inv.cb.on_redirected == NULL) {
2950
2951 /* Redirection callback is not implemented, disconnect the
2952 * call.
2953 */
2954 goto terminate_session;
2955
2956 } else {
2957 const pjsip_msg *res_msg;
2958
2959 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
2960
2961 /* Gather all Contact URI's in the response and add them
2962 * to target set. The function will take care of removing
2963 * duplicate URI's.
2964 */
2965 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
2966 inv->dlg->pool, res_msg);
2967
2968 /* Recurse to alternate targets if application allows us */
2969 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
2970 {
2971 /* Recursion fails, terminate session now */
2972 goto terminate_session;
2973 }
2974
2975 /* Done */
2976 }
2977
2978 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
2979 !inv->cancelling)
2980 {
2981
2982 /* Handle authentication failure:
2983 * Resend the request with Authorization header.
2984 */
2985 pjsip_tx_data *tdata;
2986
2987 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
2988 e->body.tsx_state.src.rdata,
2989 tsx->last_tx,
2990 &tdata);
2991
2992 if (status != PJ_SUCCESS) {
2993
2994 /* Does not have proper credentials. If we are currently
2995 * recursing, try the next target. Otherwise end the session.
2996 */
2997 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
2998 {
2999 /* Recursion fails, terminate session now */
3000 goto terminate_session;
3001 }
3002
3003 } else {
3004
3005 /* Restart session. */
3006 pjsip_inv_uac_restart(inv, PJ_FALSE);
3007
3008 /* Send the request. */
3009 status = pjsip_inv_send_msg(inv, tdata);
3010 }
3011
3012 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3013 /* Global error */
3014 goto terminate_session;
3015
3016 } else {
3017 /* See if we have alternate target to try */
3018 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3019 /* Recursion fails, terminate session now */
3020 goto terminate_session;
3021 }
3022 }
3023 return;
3024
3025terminate_session:
3026 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3027 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3028}
3029
3030
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003031/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003032 * State CALLING is after sending initial INVITE request but before
3033 * any response (with tag) is received.
3034 */
3035static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003036{
3037 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3038 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003039 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003040
3041 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3042
Benny Prijono8ad55352006-02-08 11:16:05 +00003043 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003044
3045 switch (tsx->state) {
3046
Benny Prijono64f851e2006-02-23 13:49:28 +00003047 case PJSIP_TSX_STATE_CALLING:
3048 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3049 break;
3050
Benny Prijono268ca612006-02-07 12:34:11 +00003051 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003052 if (inv->pending_cancel) {
3053 pjsip_tx_data *cancel;
3054
3055 inv->pending_cancel = PJ_FALSE;
3056
3057 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3058 if (status == PJ_SUCCESS && cancel)
3059 status = pjsip_inv_send_msg(inv, cancel);
3060 }
3061
Benny Prijono268ca612006-02-07 12:34:11 +00003062 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003063
Benny Prijono8ad55352006-02-08 11:16:05 +00003064 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003065
3066 inv_check_sdp_in_incoming_msg(inv, tsx,
3067 e->body.tsx_state.src.rdata);
3068
Benny Prijono1f7767b2007-10-03 18:28:49 +00003069 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3070 inv_handle_incoming_reliable_response(
3071 inv, e->body.tsx_state.src.rdata);
3072 }
3073
Benny Prijono268ca612006-02-07 12:34:11 +00003074 } else {
3075 /* Ignore 100 (Trying) response, as it doesn't change
3076 * session state. It only ceases retransmissions.
3077 */
3078 }
3079 break;
3080
3081 case PJSIP_TSX_STATE_COMPLETED:
3082 if (tsx->status_code/100 == 2) {
3083
3084 /* This should not happen.
3085 * When transaction receives 2xx, it should be terminated
3086 */
3087 pj_assert(0);
Benny Prijono8ad55352006-02-08 11:16:05 +00003088 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003089
3090 inv_check_sdp_in_incoming_msg(inv, tsx,
3091 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003092
3093 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003094 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003095 }
3096 break;
3097
3098 case PJSIP_TSX_STATE_TERMINATED:
3099 /* INVITE transaction can be terminated either because UAC
3100 * transaction received 2xx response or because of transport
3101 * error.
3102 */
3103 if (tsx->status_code/100 == 2) {
3104 /* This must be receipt of 2xx response */
3105
3106 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003107 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003108
Benny Prijonoa66c7152006-02-09 01:26:14 +00003109 inv_check_sdp_in_incoming_msg(inv, tsx,
3110 e->body.tsx_state.src.rdata);
3111
Benny Prijono268ca612006-02-07 12:34:11 +00003112 /* Send ACK */
3113 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3114
Benny Prijonod5f9f422007-11-25 04:40:07 +00003115 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003116
Benny Prijono268ca612006-02-07 12:34:11 +00003117 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003118 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003119 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003120 }
3121 break;
3122
Benny Prijono34a404e2006-02-09 14:38:30 +00003123 default:
3124 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003125 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003126
Benny Prijono1f7767b2007-10-03 18:28:49 +00003127 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003128 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003129 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003130 * Transaction Does Not Exist), 408, or when it's timed out. In these
3131 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003132 * Note that 481 response to CANCEL does not terminate dialog usage,
3133 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003134 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003135 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3136 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003137 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3138 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003139 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003140 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003141 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003142 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3143 }
Benny Prijono268ca612006-02-07 12:34:11 +00003144 }
3145}
3146
Benny Prijono8ad55352006-02-08 11:16:05 +00003147/*
3148 * State INCOMING is after we received the request, but before
3149 * responses with tag are sent.
3150 */
3151static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003152{
3153 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3154 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3155
3156 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3157
Benny Prijono8ad55352006-02-08 11:16:05 +00003158 if (tsx == inv->invite_tsx) {
3159
3160 /*
3161 * Handle the INVITE state transition.
3162 */
3163
Benny Prijono268ca612006-02-07 12:34:11 +00003164 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003165
Benny Prijono64f851e2006-02-23 13:49:28 +00003166 case PJSIP_TSX_STATE_TRYING:
3167 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3168 break;
3169
Benny Prijono268ca612006-02-07 12:34:11 +00003170 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003171 /*
3172 * Transaction sent provisional response.
3173 */
Benny Prijono268ca612006-02-07 12:34:11 +00003174 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003175 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003176 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003177
Benny Prijono268ca612006-02-07 12:34:11 +00003178 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003179 /*
3180 * Transaction sent final response.
3181 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003182 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003183 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003184 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003185 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003186 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003187 }
Benny Prijono268ca612006-02-07 12:34:11 +00003188 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003189
Benny Prijono268ca612006-02-07 12:34:11 +00003190 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003191 /*
3192 * This happens on transport error (e.g. failed to send
3193 * response)
3194 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003195 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003196 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003197 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003198
Benny Prijono268ca612006-02-07 12:34:11 +00003199 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003200 pj_assert(!"Unexpected INVITE state");
3201 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003202 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003203
3204 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3205 tsx->role == PJSIP_ROLE_UAS &&
3206 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3207 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3208 {
3209
3210 /*
3211 * Handle incoming CANCEL request.
3212 */
3213
3214 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3215
Benny Prijono268ca612006-02-07 12:34:11 +00003216 }
3217}
3218
Benny Prijono8ad55352006-02-08 11:16:05 +00003219/*
3220 * State EARLY is for both UAS and UAC, after response with To tag
3221 * is sent/received.
3222 */
3223static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003224{
3225 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3226 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3227
3228 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3229
Benny Prijono8ad55352006-02-08 11:16:05 +00003230 if (tsx == inv->invite_tsx) {
3231
3232 /*
3233 * Handle the INVITE state progress.
3234 */
Benny Prijono268ca612006-02-07 12:34:11 +00003235
3236 switch (tsx->state) {
3237
3238 case PJSIP_TSX_STATE_PROCEEDING:
3239 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003240 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003241
3242 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3243 inv_check_sdp_in_incoming_msg(inv, tsx,
3244 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003245
3246 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3247 inv_handle_incoming_reliable_response(
3248 inv, e->body.tsx_state.src.rdata);
3249 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003250 }
Benny Prijono268ca612006-02-07 12:34:11 +00003251 break;
3252
3253 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003254 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003255 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003256 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3257 inv_check_sdp_in_incoming_msg(inv, tsx,
3258 e->body.tsx_state.src.rdata);
3259 }
3260
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003261 } else if (tsx->role == PJSIP_ROLE_UAC) {
3262
3263 handle_uac_call_rejection(inv, e);
3264
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003265 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003266 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003267 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003268 }
Benny Prijono268ca612006-02-07 12:34:11 +00003269 break;
3270
Benny Prijonof3195072006-02-14 21:15:30 +00003271 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003272 /* For some reason can go here (maybe when ACK for 2xx has
3273 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003274
Benny Prijono268ca612006-02-07 12:34:11 +00003275 case PJSIP_TSX_STATE_TERMINATED:
3276 /* INVITE transaction can be terminated either because UAC
3277 * transaction received 2xx response or because of transport
3278 * error.
3279 */
3280 if (tsx->status_code/100 == 2) {
3281
3282 /* This must be receipt of 2xx response */
3283
3284 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003285 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003286
Benny Prijonoa66c7152006-02-09 01:26:14 +00003287 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3288 inv_check_sdp_in_incoming_msg(inv, tsx,
3289 e->body.tsx_state.src.rdata);
3290 }
3291
Benny Prijono268ca612006-02-07 12:34:11 +00003292 /* if UAC, send ACK and move state to confirmed. */
3293 if (tsx->role == PJSIP_ROLE_UAC) {
3294 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3295
Benny Prijonod5f9f422007-11-25 04:40:07 +00003296 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003297 }
3298
3299 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003300 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003301 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003302 }
3303 break;
3304
3305 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003306 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003307 }
3308
Benny Prijono8ad55352006-02-08 11:16:05 +00003309 } else if (inv->role == PJSIP_ROLE_UAS &&
3310 tsx->role == PJSIP_ROLE_UAS &&
3311 tsx->method.id == PJSIP_CANCEL_METHOD &&
3312 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3313 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3314 {
Benny Prijono268ca612006-02-07 12:34:11 +00003315
Benny Prijono8ad55352006-02-08 11:16:05 +00003316 /*
3317 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003318 */
3319
Benny Prijono8ad55352006-02-08 11:16:05 +00003320 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3321
Benny Prijono1f7767b2007-10-03 18:28:49 +00003322 } else if (tsx->role == PJSIP_ROLE_UAS &&
3323 tsx->state == PJSIP_TSX_STATE_TRYING &&
3324 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003325 {
3326 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003327 * Handle incoming UPDATE
3328 */
3329 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3330
3331
3332 } else if (tsx->role == PJSIP_ROLE_UAC &&
3333 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3334 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3335 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3336 {
3337 /*
3338 * Handle response to outgoing UPDATE request.
3339 */
3340 inv_handle_update_response(inv, e);
3341
3342 } else if (tsx->role == PJSIP_ROLE_UAS &&
3343 tsx->state == PJSIP_TSX_STATE_TRYING &&
3344 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3345 {
3346 /*
3347 * Handle incoming PRACK
3348 */
3349 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3350
3351 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003352
3353 /* Generic handling for UAC tsx completion */
3354 handle_uac_tsx_response(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003355 }
3356}
3357
Benny Prijono8ad55352006-02-08 11:16:05 +00003358/*
3359 * State CONNECTING is after 2xx response to INVITE is sent/received.
3360 */
3361static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003362{
3363 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3364 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3365
3366 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3367
Benny Prijono8ad55352006-02-08 11:16:05 +00003368 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003369
Benny Prijono8ad55352006-02-08 11:16:05 +00003370 /*
3371 * Handle INVITE state progression.
3372 */
Benny Prijono268ca612006-02-07 12:34:11 +00003373 switch (tsx->state) {
3374
3375 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003376 /* It can only go here if incoming ACK request has the same Via
3377 * branch parameter as the INVITE transaction.
3378 */
3379 if (tsx->status_code/100 == 2) {
3380 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3381 inv_check_sdp_in_incoming_msg(inv, tsx,
3382 e->body.tsx_state.src.rdata);
3383 }
3384
Benny Prijono38998232006-02-08 22:44:25 +00003385 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003386 }
Benny Prijono268ca612006-02-07 12:34:11 +00003387 break;
3388
3389 case PJSIP_TSX_STATE_TERMINATED:
3390 /* INVITE transaction can be terminated either because UAC
3391 * transaction received 2xx response or because of transport
3392 * error.
3393 */
3394 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003395 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003396 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003397 }
3398 break;
3399
3400 case PJSIP_TSX_STATE_DESTROYED:
3401 /* Do nothing. */
3402 break;
3403
3404 default:
3405 pj_assert(!"Unexpected state");
3406 }
3407
Benny Prijono8ad55352006-02-08 11:16:05 +00003408 } else if (tsx->role == PJSIP_ROLE_UAS &&
3409 tsx->method.id == PJSIP_BYE_METHOD &&
3410 tsx->status_code < 200 &&
3411 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3412 {
3413
3414 /*
3415 * Handle incoming BYE.
3416 */
3417
3418 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3419
Benny Prijono38998232006-02-08 22:44:25 +00003420 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3421 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003422 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3423 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003424 {
3425
3426 /*
3427 * Outgoing BYE
3428 */
3429 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3430
Benny Prijono268ca612006-02-07 12:34:11 +00003431 }
Benny Prijono70127222006-07-02 14:53:05 +00003432 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3433 tsx->role == PJSIP_ROLE_UAS &&
3434 tsx->status_code < 200 &&
3435 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3436 {
Benny Prijono38998232006-02-08 22:44:25 +00003437
Benny Prijono70127222006-07-02 14:53:05 +00003438 /*
3439 * Handle strandled incoming CANCEL.
3440 */
3441 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3442 pjsip_tx_data *tdata;
3443 pj_status_t status;
3444
3445 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3446 if (status != PJ_SUCCESS) return;
3447
3448 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3449 if (status != PJ_SUCCESS) return;
3450
Benny Prijono1f7767b2007-10-03 18:28:49 +00003451 } else if (tsx->role == PJSIP_ROLE_UAS &&
3452 tsx->state == PJSIP_TSX_STATE_TRYING &&
3453 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3454 {
3455 /*
3456 * Handle incoming UPDATE
3457 */
3458 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3459
3460
3461 } else if (tsx->role == PJSIP_ROLE_UAC &&
3462 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3463 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3464 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3465 {
3466 /*
3467 * Handle response to outgoing UPDATE request.
3468 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003469 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003470 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003471
3472 } else if (tsx->role == PJSIP_ROLE_UAS &&
3473 tsx->state == PJSIP_TSX_STATE_TRYING &&
3474 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3475 {
3476 /*
3477 * Handle incoming PRACK
3478 */
3479 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3480
3481 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono87402382008-02-21 19:28:21 +00003482
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003483 /* Generic handling for UAC tsx completion */
3484 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003485 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003486
Benny Prijono268ca612006-02-07 12:34:11 +00003487}
3488
Benny Prijono8ad55352006-02-08 11:16:05 +00003489/*
3490 * State CONFIRMED is after ACK is sent/received.
3491 */
3492static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003493{
3494 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3495 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3496
3497 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3498
Benny Prijono268ca612006-02-07 12:34:11 +00003499
Benny Prijono8ad55352006-02-08 11:16:05 +00003500 if (tsx->method.id == PJSIP_BYE_METHOD &&
3501 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003502 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3503 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003504 {
Benny Prijono38998232006-02-08 22:44:25 +00003505
Benny Prijono8ad55352006-02-08 11:16:05 +00003506 /*
Benny Prijono38998232006-02-08 22:44:25 +00003507 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003508 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003509
Benny Prijonoa66c7152006-02-09 01:26:14 +00003510 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003511
Benny Prijono8ad55352006-02-08 11:16:05 +00003512 }
3513 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3514 tsx->role == PJSIP_ROLE_UAS &&
3515 tsx->status_code < 200 &&
3516 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3517 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003518
Benny Prijono8ad55352006-02-08 11:16:05 +00003519 /*
3520 * Handle incoming BYE.
3521 */
Benny Prijono268ca612006-02-07 12:34:11 +00003522
Benny Prijono8ad55352006-02-08 11:16:05 +00003523 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3524
Benny Prijono268ca612006-02-07 12:34:11 +00003525 }
Benny Prijono70127222006-07-02 14:53:05 +00003526 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3527 tsx->role == PJSIP_ROLE_UAS &&
3528 tsx->status_code < 200 &&
3529 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3530 {
3531
3532 /*
3533 * Handle strandled incoming CANCEL.
3534 */
3535 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3536 pjsip_tx_data *tdata;
3537 pj_status_t status;
3538
3539 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3540 if (status != PJ_SUCCESS) return;
3541
3542 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3543 if (status != PJ_SUCCESS) return;
3544
3545 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003546 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3547 tsx->role == PJSIP_ROLE_UAS)
3548 {
3549
3550 /*
3551 * Handle incoming re-INVITE
3552 */
3553 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3554
3555 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3556 pjsip_tx_data *tdata;
3557 pj_status_t status;
3558
3559 /* Check if we have INVITE pending. */
3560 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003561 pj_str_t reason;
3562
3563 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003564
3565 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003566 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3567 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003568 if (status != PJ_SUCCESS)
3569 return;
3570
3571 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3572
3573
3574 return;
3575 }
3576
3577 /* Save the invite transaction. */
3578 inv->invite_tsx = tsx;
3579
3580 /* Process SDP in incoming message. */
3581 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3582
3583 if (status != PJ_SUCCESS) {
3584
3585 /* Not Acceptable */
3586 const pjsip_hdr *accept;
3587
3588 status = pjsip_dlg_create_response(inv->dlg, rdata,
3589 488, NULL, &tdata);
3590 if (status != PJ_SUCCESS)
3591 return;
3592
3593
3594 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3595 NULL);
3596 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003597 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003598 pjsip_hdr_clone(tdata->pool, accept));
3599 }
3600
3601 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3602
3603 return;
3604 }
3605
3606 /* Create 2xx ANSWER */
3607 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3608 if (status != PJ_SUCCESS)
3609 return;
3610
Benny Prijono7d910092007-06-20 04:19:46 +00003611 /* If the INVITE request has SDP body, send answer.
3612 * Otherwise generate offer from local active SDP.
3613 */
3614 if (rdata->msg_info.msg->body != NULL) {
3615 status = process_answer(inv, 200, tdata, NULL);
3616 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003617 /* INVITE does not have SDP.
3618 * If on_create_offer() callback is implemented, ask app.
3619 * to generate an offer, otherwise just send active local
3620 * SDP to signal that nothing gets modified.
3621 */
3622 pjmedia_sdp_session *sdp = NULL;
3623
3624 if (mod_inv.cb.on_create_offer) {
3625 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3626 if (sdp) {
Benny Prijono60e31fc2009-04-23 11:50:25 +00003627 /* Notify negotiator about the new offer. This will
3628 * fix the offer with correct SDP origin.
3629 */
Benny Prijono77998ce2007-06-20 10:03:46 +00003630 status = pjmedia_sdp_neg_modify_local_offer(dlg->pool,
3631 inv->neg,
3632 sdp);
Benny Prijono60e31fc2009-04-23 11:50:25 +00003633
3634 /* Retrieve the "fixed" offer from negotiator */
3635 if (status==PJ_SUCCESS)
3636 pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
Benny Prijono77998ce2007-06-20 10:03:46 +00003637 }
3638 }
3639
3640 if (sdp == NULL) {
3641 const pjmedia_sdp_session *active_sdp = NULL;
3642 status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
3643 inv->neg,
3644 &active_sdp);
3645 if (status == PJ_SUCCESS)
3646 sdp = (pjmedia_sdp_session*) active_sdp;
3647 }
3648
3649 if (sdp) {
3650 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003651 }
3652 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003653
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003654 if (status != PJ_SUCCESS) {
3655 /*
3656 * SDP negotiation has failed.
3657 */
3658 pj_status_t rc;
3659 pj_str_t reason;
3660
3661 /* Delete the 2xx answer */
3662 pjsip_tx_data_dec_ref(tdata);
3663
3664 /* Create 500 response */
3665 reason = pj_str("SDP negotiation failed");
3666 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3667 &tdata);
3668 if (rc == PJ_SUCCESS) {
3669 pjsip_warning_hdr *w;
3670 const pj_str_t *endpt_name;
3671
3672 endpt_name = pjsip_endpt_name(dlg->endpt);
3673 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3674 endpt_name,
3675 status);
3676 if (w)
3677 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3678
3679 pjsip_inv_send_msg(inv, tdata);
3680 }
3681 return;
3682 }
3683
3684 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003685 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003686
Benny Prijono7d910092007-06-20 04:19:46 +00003687 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
3688 /* This is the case where ACK has the same branch as
3689 * the INVITE request.
3690 */
3691 if (tsx->status_code/100 == 2 &&
3692 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3693 {
3694 inv_check_sdp_in_incoming_msg(inv, tsx,
3695 e->body.tsx_state.src.rdata);
3696 }
3697
Benny Prijono26ff9062006-02-21 23:47:00 +00003698 }
3699
3700 }
3701 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3702 tsx->role == PJSIP_ROLE_UAC)
3703 {
Benny Prijono22e48c92008-03-20 14:40:50 +00003704
Benny Prijono26ff9062006-02-21 23:47:00 +00003705 /*
3706 * Handle outgoing re-INVITE
3707 */
Benny Prijono22e48c92008-03-20 14:40:50 +00003708 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
3709
Benny Prijono61fc5e62008-06-25 18:35:31 +00003710 /* Must not have other pending INVITE transaction */
3711 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
3712
Benny Prijono22e48c92008-03-20 14:40:50 +00003713 /* Save pending invite transaction */
3714 inv->invite_tsx = tsx;
3715
3716 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
3717 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00003718 {
3719
3720 /* Re-INVITE was accepted. */
3721
3722 /* Process SDP */
3723 inv_check_sdp_in_incoming_msg(inv, tsx,
3724 e->body.tsx_state.src.rdata);
3725
3726 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00003727 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003728
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003729 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00003730
3731 /* Handle response that terminates dialog */
3732 /* Nothing to do (already handled) */
3733
Benny Prijono77998ce2007-06-20 10:03:46 +00003734 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
3735
3736 pjmedia_sdp_neg_state neg_state;
3737
3738 /* Outgoing INVITE transaction has failed, cancel SDP nego */
3739 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
3740 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
3741 pjmedia_sdp_neg_cancel_offer(inv->neg);
3742 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003743 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003744
3745 } else if (tsx->role == PJSIP_ROLE_UAS &&
3746 tsx->state == PJSIP_TSX_STATE_TRYING &&
3747 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3748 {
3749 /*
3750 * Handle incoming UPDATE
3751 */
3752 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3753
3754 } else if (tsx->role == PJSIP_ROLE_UAC &&
3755 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3756 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3757 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3758 {
3759 /*
3760 * Handle response to outgoing UPDATE request.
3761 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003762 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003763 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003764
3765 } else if (tsx->role == PJSIP_ROLE_UAS &&
3766 tsx->state == PJSIP_TSX_STATE_TRYING &&
3767 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3768 {
3769 /*
3770 * Handle strandled incoming PRACK
3771 */
3772 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3773
3774 } else if (tsx->role == PJSIP_ROLE_UAC) {
3775 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003776 * Handle 401/407/408/481 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00003777 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003778 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003779 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003780
Benny Prijono268ca612006-02-07 12:34:11 +00003781}
3782
Benny Prijono8ad55352006-02-08 11:16:05 +00003783/*
3784 * After session has been terminated, but before dialog is destroyed
3785 * (because dialog has other usages, or because dialog is waiting for
3786 * the last transaction to terminate).
3787 */
3788static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003789{
Benny Prijono8ad55352006-02-08 11:16:05 +00003790 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3791 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00003792
Benny Prijono8ad55352006-02-08 11:16:05 +00003793 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3794
Benny Prijono70127222006-07-02 14:53:05 +00003795 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00003796 tsx->status_code < 200 &&
3797 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3798 {
Benny Prijono70127222006-07-02 14:53:05 +00003799 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00003800
3801 /*
Benny Prijono70127222006-07-02 14:53:05 +00003802 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00003803 */
Benny Prijono70127222006-07-02 14:53:05 +00003804 if (tsx->method.id == PJSIP_BYE_METHOD) {
3805 inv_respond_incoming_bye( inv, tsx, rdata, e );
3806 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
3807 /*
3808 * Respond CANCEL with 200/OK too.
3809 */
3810 pjsip_tx_data *tdata;
3811 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00003812
Benny Prijono70127222006-07-02 14:53:05 +00003813 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3814 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00003815
Benny Prijono70127222006-07-02 14:53:05 +00003816 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3817 if (status != PJ_SUCCESS) return;
3818
3819 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00003820
3821 } else if (tsx->role == PJSIP_ROLE_UAC) {
3822 /*
3823 * Handle 401/407/408/481 response
3824 */
3825 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00003826 }
Benny Prijono268ca612006-02-07 12:34:11 +00003827}
3828