blob: ae1011efb9b4783ade32f68049c1ecd0a4613abd [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
Nanang Izzuddin5d5a20e2009-08-06 16:04:20 +0000911 } else if (!pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
912 NULL, &req_hdr->values[i]))
913 {
Benny Prijono268ca612006-02-07 12:34:11 +0000914 /* Unknown/unsupported extension tag! */
915 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
916 }
917 }
918
919 /* Check if there are required tags that we don't support */
920 if (unsupp_cnt) {
921
922 code = PJSIP_SC_BAD_EXTENSION;
923 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
924
925 if (p_tdata) {
926 pjsip_unsupported_hdr *unsupp_hdr;
927 const pjsip_hdr *h;
928
929 /* Add Unsupported header. */
930 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
931 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
932
933 unsupp_hdr->count = unsupp_cnt;
934 for (i=0; i<unsupp_cnt; ++i)
935 unsupp_hdr->values[i] = unsupp_tags[i];
936
937 pj_list_push_back(&res_hdr_list, unsupp_hdr);
938
939 /* Add Supported header. */
940 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
941 NULL);
942 pj_assert(h);
943 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000944 sup_hdr = (pjsip_supported_hdr*)
945 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000946 pj_list_push_back(&res_hdr_list, sup_hdr);
947 }
948 }
949
950 goto on_return;
951 }
952 }
953
954 /* Check if there are local requirements that are not supported
955 * by peer.
956 */
957 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
958 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
959 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
960 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
961 {
962 code = PJSIP_SC_EXTENSION_REQUIRED;
963 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
964
965 if (p_tdata) {
966 const pjsip_hdr *h;
967
968 /* Add Require header. */
969 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
970 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
971
972 if (*options & PJSIP_INV_REQUIRE_100REL)
973 req_hdr->values[req_hdr->count++] = pj_str("100rel");
974
975 if (*options & PJSIP_INV_REQUIRE_TIMER)
976 req_hdr->values[req_hdr->count++] = pj_str("timer");
977
978 pj_list_push_back(&res_hdr_list, req_hdr);
979
980 /* Add Supported header. */
981 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
982 NULL);
983 pj_assert(h);
984 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000985 sup_hdr = (pjsip_supported_hdr*)
986 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000987 pj_list_push_back(&res_hdr_list, sup_hdr);
988 }
989
990 }
991
992 goto on_return;
993 }
994
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000995 /* If remote Require something that we support, make us Require
996 * that feature too.
997 */
998 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
999 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
1000 *options |= PJSIP_INV_REQUIRE_100REL;
1001 }
1002 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1003 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1004 *options |= PJSIP_INV_REQUIRE_TIMER;
1005 }
1006
Benny Prijono268ca612006-02-07 12:34:11 +00001007on_return:
1008
1009 /* Create response if necessary */
1010 if (code != 200 && p_tdata) {
1011 pjsip_tx_data *tdata;
1012 const pjsip_hdr *h;
1013
1014 if (dlg) {
1015 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1016 &tdata);
1017 } else {
1018 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1019 &tdata);
1020 }
1021
1022 if (status != PJ_SUCCESS)
1023 return status;
1024
1025 /* Add response headers. */
1026 h = res_hdr_list.next;
1027 while (h != &res_hdr_list) {
1028 pjsip_hdr *cloned;
1029
Benny Prijonoa1e69682007-05-11 15:14:34 +00001030 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001031 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1032
1033 pjsip_msg_add_hdr(tdata->msg, cloned);
1034
1035 h = h->next;
1036 }
1037
1038 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001039
1040 /* Can not return PJ_SUCCESS when response message is produced.
1041 * Ref: PROTOS test ~#2490
1042 */
1043 if (status == PJ_SUCCESS)
1044 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1045
Benny Prijono268ca612006-02-07 12:34:11 +00001046 }
1047
1048 return status;
1049}
1050
Benny Prijono87a90212008-01-23 20:29:30 +00001051
1052/*
1053 * Verify incoming INVITE request.
1054 */
1055PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1056 unsigned *options,
1057 const pjmedia_sdp_session *l_sdp,
1058 pjsip_dialog *dlg,
1059 pjsip_endpoint *endpt,
1060 pjsip_tx_data **p_tdata)
1061{
1062 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1063 endpt, p_tdata);
1064}
1065
Benny Prijono268ca612006-02-07 12:34:11 +00001066/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001067 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001068 */
1069PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1070 pjsip_rx_data *rdata,
1071 const pjmedia_sdp_session *local_sdp,
1072 unsigned options,
1073 pjsip_inv_session **p_inv)
1074{
1075 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001076 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001077 pjsip_msg *msg;
1078 pjmedia_sdp_session *rem_sdp = NULL;
1079 pj_status_t status;
1080
1081 /* Verify arguments. */
1082 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1083
1084 /* Dialog MUST have been initialised. */
1085 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1086
1087 msg = rdata->msg_info.msg;
1088
1089 /* rdata MUST contain INVITE request */
1090 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1091 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1092 PJ_EINVALIDOP);
1093
Benny Prijono8eae8382006-08-10 21:44:26 +00001094 /* Lock dialog */
1095 pjsip_dlg_inc_lock(dlg);
1096
Benny Prijono268ca612006-02-07 12:34:11 +00001097 /* Normalize options */
1098 if (options & PJSIP_INV_REQUIRE_100REL)
1099 options |= PJSIP_INV_SUPPORT_100REL;
1100
1101 if (options & PJSIP_INV_REQUIRE_TIMER)
1102 options |= PJSIP_INV_SUPPORT_TIMER;
1103
1104 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001105 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001106 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001107
1108 inv->pool = dlg->pool;
1109 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001110 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001111 inv->dlg = dlg;
1112 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001113 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001114 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001115
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001116 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001117 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001118
Benny Prijono268ca612006-02-07 12:34:11 +00001119 /* Parse SDP in message body, if present. */
1120 if (msg->body) {
1121 pjsip_msg_body *body = msg->body;
1122
1123 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001124 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001125 &rem_sdp);
1126 if (status == PJ_SUCCESS)
1127 status = pjmedia_sdp_validate(rem_sdp);
1128
Benny Prijono8eae8382006-08-10 21:44:26 +00001129 if (status != PJ_SUCCESS) {
1130 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001131 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001132 }
Benny Prijono268ca612006-02-07 12:34:11 +00001133 }
1134
1135 /* Create negotiator. */
1136 if (rem_sdp) {
1137 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp,
1138 rem_sdp, &inv->neg);
1139
1140 } else if (local_sdp) {
1141 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1142 &inv->neg);
1143 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001144 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001145 }
1146
Benny Prijono8eae8382006-08-10 21:44:26 +00001147 if (status != PJ_SUCCESS) {
1148 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001149 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001150 }
Benny Prijono268ca612006-02-07 12:34:11 +00001151
1152 /* Register invite as dialog usage. */
1153 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001154 if (status != PJ_SUCCESS) {
1155 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001156 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001157 }
Benny Prijono268ca612006-02-07 12:34:11 +00001158
1159 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001160 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001161
1162 /* Save the invite transaction. */
1163 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001164
1165 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001166 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001167 tsx_inv_data->inv = inv;
1168 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001169
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001170 /* Create 100rel handler */
1171 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1172 pjsip_100rel_attach(inv);
1173 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001174
Benny Prijono268ca612006-02-07 12:34:11 +00001175 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001176 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001177 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001178
1179 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1180 dlg->obj_name));
1181
Benny Prijono268ca612006-02-07 12:34:11 +00001182 return PJ_SUCCESS;
1183}
1184
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001185/*
1186 * Forcefully terminate the session.
1187 */
1188PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1189 int st_code,
1190 pj_bool_t notify)
1191{
1192 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1193
1194 /* Lock dialog. */
1195 pjsip_dlg_inc_lock(inv->dlg);
1196
1197 /* Set callback notify flag. */
1198 inv->notify = notify;
1199
1200 /* If there's pending transaction, terminate the transaction.
1201 * This may subsequently set the INVITE session state to
1202 * disconnected.
1203 */
1204 if (inv->invite_tsx &&
1205 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1206 {
1207 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1208
1209 }
1210
1211 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001212 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001213
1214 /* Forcefully terminate the session if state is not DISCONNECTED */
1215 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1216 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1217 }
1218
1219 /* Done.
1220 * The dec_lock() below will actually destroys the dialog if it
1221 * has no other session.
1222 */
1223 pjsip_dlg_dec_lock(inv->dlg);
1224
1225 return PJ_SUCCESS;
1226}
1227
1228
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001229/*
1230 * Restart UAC session, possibly because app or us wants to re-send the
1231 * INVITE request due to 401/407 challenge or 3xx response.
1232 */
1233PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1234 pj_bool_t new_offer)
1235{
1236 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1237
1238 inv->state = PJSIP_INV_STATE_NULL;
1239 inv->invite_tsx = NULL;
1240 if (inv->last_answer) {
1241 pjsip_tx_data_dec_ref(inv->last_answer);
1242 inv->last_answer = NULL;
1243 }
1244
1245 if (new_offer && inv->neg) {
1246 pjmedia_sdp_neg_state neg_state;
1247
1248 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1249 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1250 pjmedia_sdp_neg_cancel_offer(inv->neg);
1251 }
1252 }
1253
1254 return PJ_SUCCESS;
1255}
1256
1257
Benny Prijono268ca612006-02-07 12:34:11 +00001258static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1259{
1260 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001261 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001262}
1263
1264static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1265{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001266 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001267}
1268
Benny Prijono56315612006-07-18 14:39:40 +00001269
1270PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1271 pjmedia_sdp_session *sdp,
1272 pjsip_msg_body **p_body)
1273{
1274 const pj_str_t STR_APPLICATION = { "application", 11};
1275 const pj_str_t STR_SDP = { "sdp", 3 };
1276 pjsip_msg_body *body;
1277
Benny Prijonoa1e69682007-05-11 15:14:34 +00001278 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001279 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1280
1281 body->content_type.type = STR_APPLICATION;
1282 body->content_type.subtype = STR_SDP;
1283 body->data = sdp;
1284 body->len = 0;
1285 body->clone_data = &clone_sdp;
1286 body->print_body = &print_sdp;
1287
1288 *p_body = body;
1289
1290 return PJ_SUCCESS;
1291}
1292
Benny Prijono268ca612006-02-07 12:34:11 +00001293static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1294 const pjmedia_sdp_session *c_sdp)
1295{
1296 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001297 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001298
Benny Prijono56315612006-07-18 14:39:40 +00001299 status = pjsip_create_sdp_body(pool,
1300 pjmedia_sdp_session_clone(pool, c_sdp),
1301 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001302
Benny Prijono56315612006-07-18 14:39:40 +00001303 if (status != PJ_SUCCESS)
1304 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001305
1306 return body;
1307}
1308
1309/*
1310 * Create initial INVITE request.
1311 */
1312PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1313 pjsip_tx_data **p_tdata )
1314{
1315 pjsip_tx_data *tdata;
1316 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001317 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001318 pj_status_t status;
1319
1320 /* Verify arguments. */
1321 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1322
Benny Prijono26ff9062006-02-21 23:47:00 +00001323 /* State MUST be NULL or CONFIRMED. */
1324 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1325 inv->state == PJSIP_INV_STATE_CONFIRMED,
1326 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001327
Benny Prijono64f851e2006-02-23 13:49:28 +00001328 /* Lock dialog. */
1329 pjsip_dlg_inc_lock(inv->dlg);
1330
Benny Prijono268ca612006-02-07 12:34:11 +00001331 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001332 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001333 &tdata);
1334 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001335 goto on_return;
1336
Benny Prijono268ca612006-02-07 12:34:11 +00001337
Benny Prijono26ff9062006-02-21 23:47:00 +00001338 /* If this is the first INVITE, then copy the headers from inv_hdr.
1339 * These are the headers parsed from the request URI when the
1340 * dialog was created.
1341 */
1342 if (inv->state == PJSIP_INV_STATE_NULL) {
1343 hdr = inv->dlg->inv_hdr.next;
1344
1345 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001346 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001347 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1348 hdr = hdr->next;
1349 }
1350 }
1351
1352 /* See if we have SDP to send. */
1353 if (inv->neg) {
1354 pjmedia_sdp_neg_state neg_state;
1355
1356 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1357
1358 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1359 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1360 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1361
1362
1363 } else {
1364 has_sdp = PJ_FALSE;
1365 }
1366
Benny Prijono268ca612006-02-07 12:34:11 +00001367 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001368 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001369 const pjmedia_sdp_session *offer;
1370
1371 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono176a11f2009-04-14 11:14:51 +00001372 if (status != PJ_SUCCESS) {
1373 pjsip_tx_data_dec_ref(tdata);
Benny Prijono64f851e2006-02-23 13:49:28 +00001374 goto on_return;
Benny Prijono176a11f2009-04-14 11:14:51 +00001375 }
Benny Prijono268ca612006-02-07 12:34:11 +00001376
1377 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1378 }
1379
1380 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001381 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001382 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1383 if (hdr) {
1384 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1385 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1386 }
Benny Prijono268ca612006-02-07 12:34:11 +00001387 }
1388
1389 /* Add Supported header */
1390 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1391 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001392 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001393 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1394 }
1395
1396 /* Add Require header. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001397 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1398 const pj_str_t HREQ = { "Require", 7 };
1399 const pj_str_t tag_100rel = { "100rel", 6 };
1400 pjsip_generic_string_hdr *hreq;
1401
1402 hreq = pjsip_generic_string_hdr_create(tdata->pool, &HREQ,
1403 &tag_100rel);
1404 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
1405 }
Benny Prijono268ca612006-02-07 12:34:11 +00001406
1407 /* Done. */
1408 *p_tdata = tdata;
1409
Benny Prijono64f851e2006-02-23 13:49:28 +00001410
1411on_return:
1412 pjsip_dlg_dec_lock(inv->dlg);
1413 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001414}
1415
1416
1417/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001418 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001419 */
1420static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1421{
1422 pj_status_t status;
1423
1424 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1425 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1426 PJMEDIA_SDPNEG_EINSTATE);
1427
1428 status = pjmedia_sdp_neg_negotiate(inv->pool, inv->neg, 0);
1429
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001430 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1431
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001432 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001433 (*mod_inv.cb.on_media_update)(inv, status);
1434
1435 return status;
1436}
1437
1438/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001439 * Check in incoming message for SDP offer/answer.
1440 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001441static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1442 pjsip_transaction *tsx,
1443 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001444{
1445 struct tsx_inv_data *tsx_inv_data;
1446 static const pj_str_t str_application = { "application", 11 };
1447 static const pj_str_t str_sdp = { "sdp", 3 };
1448 pj_status_t status;
1449 pjsip_msg *msg;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001450 pjmedia_sdp_session *rem_sdp;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001451
1452 /* Check if SDP is present in the message. */
1453
1454 msg = rdata->msg_info.msg;
1455 if (msg->body == NULL) {
1456 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001457 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001458 }
1459
1460 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1461 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1462 {
1463 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001464 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001465 }
1466
Benny Prijono8fcb4332008-10-31 18:01:48 +00001467 /* Get/attach invite session's transaction data */
1468 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1469 if (tsx_inv_data == NULL) {
1470 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1471 tsx_inv_data->inv = inv;
1472 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1473 }
1474
1475 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1476 * EXCEPT if:
1477 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1478 * - the previous negotiation was done on an early media (18x) and
1479 * this response is a final/2xx response, and
1480 * - the 2xx response has different To tag than the 18x response
1481 * (i.e. the request has forked).
1482 *
1483 * The exception above is to add a rudimentary support for early media
1484 * forking (sample case: custom ringback). See this ticket for more
1485 * info: http://trac.pjsip.org/repos/ticket/657
1486 */
1487 if (tsx_inv_data->sdp_done) {
1488 pj_str_t res_tag;
1489
1490 res_tag = rdata->msg_info.to->tag;
1491
1492 /* Allow final response after SDP has been negotiated in early
1493 * media, IF this response is a final response with different
1494 * tag.
1495 */
1496 if (tsx->role == PJSIP_ROLE_UAC &&
1497 rdata->msg_info.msg->line.status.code/100 == 2 &&
1498 tsx_inv_data->done_early &&
1499 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1500 {
1501 const pjmedia_sdp_session *reoffer_sdp = NULL;
1502
1503 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1504 "after SDP negotiation has been done in early "
1505 "media. Renegotiating SDP.."));
1506
1507 /* Retrieve original SDP offer from INVITE request */
1508 reoffer_sdp = (const pjmedia_sdp_session*)
1509 tsx->last_tx->msg->body->data;
1510
1511 /* Feed the original offer to negotiator */
1512 status = pjmedia_sdp_neg_modify_local_offer(inv->pool, inv->neg,
1513 reoffer_sdp);
1514 if (status != PJ_SUCCESS) {
1515 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1516 "forked 2xx response (err=%d)", status));
1517 return status;
1518 }
1519
1520 } else {
1521
1522 if (rdata->msg_info.msg->body) {
1523 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1524 "body is ignored"));
1525 }
1526 return PJ_SUCCESS;
1527 }
1528 }
1529
Benny Prijonoa66c7152006-02-09 01:26:14 +00001530 /* Parse the SDP body. */
1531
Benny Prijonoa1e69682007-05-11 15:14:34 +00001532 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1533 (char*)msg->body->data,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001534 msg->body->len, &rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001535 if (status == PJ_SUCCESS)
Benny Prijono8fcb4332008-10-31 18:01:48 +00001536 status = pjmedia_sdp_validate(rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001537
Benny Prijonoa66c7152006-02-09 01:26:14 +00001538 if (status != PJ_SUCCESS) {
1539 char errmsg[PJ_ERR_MSG_SIZE];
1540 pj_strerror(status, errmsg, sizeof(errmsg));
1541 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1542 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001543 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001544 }
1545
1546 /* The SDP can be an offer or answer, depending on negotiator's state */
1547
1548 if (inv->neg == NULL ||
1549 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1550 {
1551
1552 /* This is an offer. */
1553
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001554 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1555 pjsip_rx_data_get_info(rdata)));
1556
Benny Prijonoa66c7152006-02-09 01:26:14 +00001557 if (inv->neg == NULL) {
1558 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001559 rem_sdp, &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001560 } else {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001561 status=pjmedia_sdp_neg_set_remote_offer(inv->pool, inv->neg,
1562 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001563 }
1564
1565 if (status != PJ_SUCCESS) {
1566 char errmsg[PJ_ERR_MSG_SIZE];
1567 pj_strerror(status, errmsg, sizeof(errmsg));
1568 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1569 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001570 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001571 }
1572
1573 /* Inform application about remote offer. */
1574
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001575 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001576
Benny Prijono8fcb4332008-10-31 18:01:48 +00001577 (*mod_inv.cb.on_rx_offer)(inv, rem_sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001578
1579 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001580
1581 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1582 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1583 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001584 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001585
1586 /* This is an answer.
1587 * Process and negotiate remote answer.
1588 */
1589
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001590 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1591 pjsip_rx_data_get_info(rdata)));
1592
Benny Prijono8fcb4332008-10-31 18:01:48 +00001593 status = pjmedia_sdp_neg_set_remote_answer(inv->pool, inv->neg,
1594 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001595
1596 if (status != PJ_SUCCESS) {
1597 char errmsg[PJ_ERR_MSG_SIZE];
1598 pj_strerror(status, errmsg, sizeof(errmsg));
1599 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1600 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001601 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001602 }
1603
1604 /* Negotiate SDP */
1605
1606 inv_negotiate_sdp(inv);
1607
Benny Prijono8fcb4332008-10-31 18:01:48 +00001608 /* Mark this transaction has having SDP offer/answer done, and
1609 * save the reference to the To tag
1610 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001611
1612 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001613 status_code = rdata->msg_info.msg->line.status.code;
1614 tsx_inv_data->done_early = (status_code/100==1);
1615 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1616 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001617
1618 } else {
1619
1620 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1621 pjsip_rx_data_get_info(rdata),
1622 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1623 }
1624
Benny Prijono26ff9062006-02-21 23:47:00 +00001625 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001626}
1627
1628
Benny Prijono26ff9062006-02-21 23:47:00 +00001629/*
1630 * Process INVITE answer, for both initial and subsequent re-INVITE
1631 */
1632static pj_status_t process_answer( pjsip_inv_session *inv,
1633 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001634 pjsip_tx_data *tdata,
1635 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001636{
1637 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001638 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001639
Benny Prijono64f851e2006-02-23 13:49:28 +00001640 /* If local_sdp is specified, then we MUST NOT have answered the
1641 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001642 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001643 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1644
1645 if (inv->neg == NULL) {
1646 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1647 &inv->neg);
1648 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1649 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1650 {
1651 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
1652 local_sdp);
1653 } else {
1654
1655 /* Can not specify local SDP at this state. */
1656 pj_assert(0);
1657 status = PJMEDIA_SDPNEG_EINSTATE;
1658 }
1659
1660 if (status != PJ_SUCCESS)
1661 return status;
1662
1663 }
1664
1665
1666 /* If SDP negotiator is ready, start negotiation. */
1667 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001668
1669 pjmedia_sdp_neg_state neg_state;
1670
Benny Prijono64f851e2006-02-23 13:49:28 +00001671 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001672 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1673 PJMEDIA_SDP_NEG_STATE_NULL;
1674
1675 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1676
1677 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1678
1679 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1680 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1681 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001682 struct tsx_inv_data *tsx_inv_data;
1683
1684 /* Get invite session's transaction data */
1685 tsx_inv_data = (struct tsx_inv_data*)
1686 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001687
1688 status = inv_negotiate_sdp(inv);
1689 if (status != PJ_SUCCESS)
1690 return status;
1691
Benny Prijono77998ce2007-06-20 10:03:46 +00001692 /* Mark this transaction has having SDP offer/answer done. */
1693 tsx_inv_data->sdp_done = 1;
1694
Benny Prijono26ff9062006-02-21 23:47:00 +00001695 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1696 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001697 }
1698
Benny Prijono64f851e2006-02-23 13:49:28 +00001699 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001700 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001701 *
1702 * Note note:
1703 * - When offer/answer has been completed in reliable 183, we MUST NOT
1704 * send SDP in 2xx response. So if we don't have SDP to send, clear
1705 * the SDP in the message body ONLY if 100rel is active in this
1706 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001707 */
1708 if (sdp) {
1709 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001710 } else {
1711 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1712 tdata->msg->body = NULL;
1713 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001714 }
1715
Benny Prijono26ff9062006-02-21 23:47:00 +00001716
1717 return PJ_SUCCESS;
1718}
1719
Benny Prijonoa66c7152006-02-09 01:26:14 +00001720
1721/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001722 * Create first response to INVITE
1723 */
1724PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1725 pjsip_rx_data *rdata,
1726 int st_code,
1727 const pj_str_t *st_text,
1728 const pjmedia_sdp_session *sdp,
1729 pjsip_tx_data **p_tdata)
1730{
1731 pjsip_tx_data *tdata;
1732 pj_status_t status;
1733
1734 /* Verify arguments. */
1735 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1736
1737 /* Must have INVITE transaction. */
1738 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1739
1740 pjsip_dlg_inc_lock(inv->dlg);
1741
1742 /* Create response */
1743 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1744 &tdata);
1745 if (status != PJ_SUCCESS)
1746 goto on_return;
1747
1748 /* Process SDP in answer */
1749 status = process_answer(inv, st_code, tdata, sdp);
1750 if (status != PJ_SUCCESS) {
1751 pjsip_tx_data_dec_ref(tdata);
1752 goto on_return;
1753 }
1754
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001755 /* Save this answer */
1756 inv->last_answer = tdata;
1757 pjsip_tx_data_add_ref(inv->last_answer);
1758 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1759 pjsip_tx_data_get_info(inv->last_answer)));
1760
Benny Prijono64f851e2006-02-23 13:49:28 +00001761 *p_tdata = tdata;
1762
1763on_return:
1764 pjsip_dlg_dec_lock(inv->dlg);
1765 return status;
1766}
1767
1768
1769/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001770 * Answer initial INVITE
1771 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001772 */
1773PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1774 int st_code,
1775 const pj_str_t *st_text,
1776 const pjmedia_sdp_session *local_sdp,
1777 pjsip_tx_data **p_tdata )
1778{
1779 pjsip_tx_data *last_res;
1780 pj_status_t status;
1781
1782 /* Verify arguments. */
1783 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1784
1785 /* Must have INVITE transaction. */
1786 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1787
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001788 /* Must have created an answer before */
1789 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001790
Benny Prijono64f851e2006-02-23 13:49:28 +00001791 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001792
1793 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001794 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001795 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1796 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001797 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001798
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001799 /* For non-2xx final response, strip message body */
1800 if (st_code >= 300) {
1801 last_res->msg->body = NULL;
1802 }
Benny Prijono268ca612006-02-07 12:34:11 +00001803
Benny Prijono26ff9062006-02-21 23:47:00 +00001804 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001805 status = process_answer(inv, st_code, last_res, local_sdp);
1806 if (status != PJ_SUCCESS) {
1807 pjsip_tx_data_dec_ref(last_res);
1808 goto on_return;
1809 }
Benny Prijono268ca612006-02-07 12:34:11 +00001810
Benny Prijono268ca612006-02-07 12:34:11 +00001811
1812 *p_tdata = last_res;
1813
Benny Prijono64f851e2006-02-23 13:49:28 +00001814on_return:
1815 pjsip_dlg_dec_lock(inv->dlg);
1816 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001817}
1818
1819
1820/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001821 * Set SDP answer.
1822 */
1823PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1824 const pjmedia_sdp_session *sdp )
1825{
1826 pj_status_t status;
1827
1828 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1829
1830 pjsip_dlg_inc_lock(inv->dlg);
1831 status = pjmedia_sdp_neg_set_local_answer( inv->pool, inv->neg, sdp);
1832 pjsip_dlg_dec_lock(inv->dlg);
1833
1834 return status;
1835}
1836
1837
1838/*
Benny Prijono268ca612006-02-07 12:34:11 +00001839 * End session.
1840 */
1841PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
1842 int st_code,
1843 const pj_str_t *st_text,
1844 pjsip_tx_data **p_tdata )
1845{
1846 pjsip_tx_data *tdata;
1847 pj_status_t status;
1848
1849 /* Verify arguments. */
1850 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1851
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001852 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001853 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001854
Benny Prijono268ca612006-02-07 12:34:11 +00001855 /* Create appropriate message. */
1856 switch (inv->state) {
1857 case PJSIP_INV_STATE_CALLING:
1858 case PJSIP_INV_STATE_EARLY:
1859 case PJSIP_INV_STATE_INCOMING:
1860
1861 if (inv->role == PJSIP_ROLE_UAC) {
1862
1863 /* For UAC when session has not been confirmed, create CANCEL. */
1864
1865 /* MUST have the original UAC INVITE transaction. */
1866 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
1867
1868 /* But CANCEL should only be called when we have received a
1869 * provisional response. If we haven't received any responses,
1870 * just destroy the transaction.
1871 */
1872 if (inv->invite_tsx->status_code < 100) {
1873
Benny Prijono006a4e82009-04-26 11:30:22 +00001874 /* Do not stop INVITE retransmission, see ticket #506 */
1875 //pjsip_tsx_stop_retransmit(inv->invite_tsx);
Benny Prijono1dc8be02007-05-30 04:26:40 +00001876 inv->cancelling = PJ_TRUE;
1877 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00001878 *p_tdata = NULL;
Benny Prijono006a4e82009-04-26 11:30:22 +00001879 PJ_LOG(4, (inv->obj_name, "Delaying CANCEL since no "
1880 "provisional response is received yet"));
Benny Prijonofccab712006-02-22 22:23:22 +00001881 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001882 }
1883
1884 /* The CSeq here assumes that the dialog is started with an
1885 * INVITE session. This may not be correct; dialog can be
1886 * started as SUBSCRIBE session.
1887 * So fix this!
1888 */
1889 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
1890 inv->invite_tsx->last_tx,
1891 &tdata);
Benny Prijono99b04372009-04-26 11:02:04 +00001892 if (status != PJ_SUCCESS)
1893 return status;
1894
1895 /* Set timeout for the INVITE transaction, in case UAS is not
1896 * able to respond the INVITE with 487 final response. The
1897 * timeout value is 64*T1.
1898 */
1899 pjsip_tsx_set_timeout(inv->invite_tsx, 64 * pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00001900
1901 } else {
1902
1903 /* For UAS, send a final response. */
1904 tdata = inv->invite_tsx->last_tx;
1905 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
1906
Benny Prijono26ff9062006-02-21 23:47:00 +00001907 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
1908 // st_text);
1909 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001910 }
1911 break;
1912
1913 case PJSIP_INV_STATE_CONNECTING:
1914 case PJSIP_INV_STATE_CONFIRMED:
1915 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001916 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
1917 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001918 break;
1919
1920 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00001921 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001922 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00001923
1924 default:
1925 pj_assert("!Invalid operation!");
1926 return PJ_EINVALIDOP;
1927 }
1928
1929 if (status != PJ_SUCCESS)
1930 return status;
1931
1932
1933 /* Done */
1934
Benny Prijono0606e702007-05-22 12:21:40 +00001935 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00001936 *p_tdata = tdata;
1937
1938 return PJ_SUCCESS;
1939}
1940
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001941/* Following redirection recursion, get next target from the target set and
1942 * notify user.
1943 *
1944 * Returns PJ_FALSE if recursion fails (either because there's no more target
1945 * or user rejects the recursion). If we return PJ_FALSE, caller should
1946 * disconnect the session.
1947 *
1948 * Note:
1949 * the event 'e' argument may be NULL.
1950 */
1951static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
1952 const pj_str_t *reason, pjsip_event *e)
1953{
Benny Prijono08a48b82008-11-27 12:42:07 +00001954 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001955 pjsip_target *target;
1956
1957 /* Won't redirect if the callback is not implemented. */
1958 if (mod_inv.cb.on_redirected == NULL)
1959 return PJ_FALSE;
1960
1961 if (reason == NULL)
1962 reason = pjsip_get_status_text(code);
1963
1964 /* Set status of current target */
1965 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
1966 code, reason);
1967
1968 /* Fetch next target from the target set. We only want to
1969 * process SIP/SIPS URI for now.
1970 */
1971 for (;;) {
1972 target = pjsip_target_set_get_next(&inv->dlg->target_set);
1973 if (target == NULL) {
1974 /* No more target. */
1975 return PJ_FALSE;
1976 }
1977
1978 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
1979 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
1980 {
1981 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
1982 reason = pjsip_get_status_text(code);
1983
1984 /* Mark this target as unusable and fetch next target. */
1985 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
1986 } else {
1987 /* Found a target */
1988 break;
1989 }
1990 }
1991
1992 /* We have target in 'target'. Set this target as current target
1993 * and notify callback.
1994 */
1995 pjsip_target_set_set_current(&inv->dlg->target_set, target);
1996
Benny Prijono08a48b82008-11-27 12:42:07 +00001997 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001998
1999
2000 /* Check what the application wants to do now */
2001 switch (op) {
2002 case PJSIP_REDIRECT_ACCEPT:
2003 case PJSIP_REDIRECT_STOP:
2004 /* Must increment session counter, that's the convention of the
2005 * pjsip_inv_process_redirect().
2006 */
2007 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2008
2009 /* Act on the recursion */
2010 pjsip_inv_process_redirect(inv, op, e);
2011 return PJ_TRUE;
2012
2013 case PJSIP_REDIRECT_PENDING:
2014 /* Increment session so that the dialog/session is not destroyed
2015 * while we're waiting for user confirmation.
2016 */
2017 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2018
2019 /* Also clear the invite_tsx variable, otherwise when this tsx is
2020 * terminated, it will also terminate the session.
2021 */
2022 inv->invite_tsx = NULL;
2023
2024 /* Done. The processing will continue once the application calls
2025 * pjsip_inv_process_redirect().
2026 */
2027 return PJ_TRUE;
2028
2029 case PJSIP_REDIRECT_REJECT:
2030 /* Recursively call this function again to fetch next target, if any.
2031 */
2032 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2033
2034 }
2035
2036 pj_assert(!"Should not reach here");
2037 return PJ_FALSE;
2038}
2039
2040
2041/* Process redirection/recursion */
2042PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2043 pjsip_redirect_op op,
2044 pjsip_event *e)
2045{
2046 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2047 pjsip_event usr_event;
2048 pj_status_t status = PJ_SUCCESS;
2049
2050 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2051
2052 if (e == NULL) {
2053 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2054 e = &usr_event;
2055 }
2056
2057 pjsip_dlg_inc_lock(inv->dlg);
2058
2059 /* Decrement session. That's the convention here to prevent the dialog
2060 * or session from being destroyed while we're waiting for user
2061 * confirmation.
2062 */
2063 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2064
2065 /* See what the application wants to do now */
2066 switch (op) {
2067 case PJSIP_REDIRECT_ACCEPT:
2068 /* User accept the redirection. Reset the session and resend the
2069 * INVITE request.
2070 */
2071 {
2072 pjsip_tx_data *tdata;
2073 pjsip_via_hdr *via;
2074
2075 /* Get the original INVITE request. */
2076 tdata = inv->invite_req;
2077 pjsip_tx_data_add_ref(tdata);
2078
2079 /* Restore strict route set.
2080 * See http://trac.pjsip.org/repos/ticket/492
2081 */
2082 pjsip_restore_strict_route_set(tdata);
2083
2084 /* Set target */
Benny Prijono20da7992008-12-18 16:48:43 +00002085 tdata->msg->line.req.uri = (pjsip_uri*)
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002086 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2087
2088 /* Remove branch param in Via header. */
2089 via = (pjsip_via_hdr*)
2090 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2091 via->branch_param.slen = 0;
2092
2093 /* Must invalidate the message! */
2094 pjsip_tx_data_invalidate_msg(tdata);
2095
2096 /* Reset the session */
2097 pjsip_inv_uac_restart(inv, PJ_FALSE);
2098
2099 /* (re)Send the INVITE request */
2100 status = pjsip_inv_send_msg(inv, tdata);
2101 }
2102 break;
2103
2104 case PJSIP_REDIRECT_STOP:
2105 /* User doesn't want the redirection. Disconnect the session now. */
2106 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2107 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2108
2109 /* Caller should expect that the invite session is gone now, so
2110 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2111 */
2112 break;
2113
2114 case PJSIP_REDIRECT_REJECT:
2115 /* Current target is rejected. Fetch next target if any. */
2116 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2117 inv_set_cause(inv, cancel_code,
2118 pjsip_get_status_text(cancel_code));
2119 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2120
2121 /* Tell caller that the invite session is gone now */
2122 status = PJSIP_ESESSIONTERMINATED;
2123 }
2124 break;
2125
2126
2127 case PJSIP_REDIRECT_PENDING:
2128 pj_assert(!"Should not happen");
2129 break;
2130 }
2131
2132
2133 pjsip_dlg_dec_lock(inv->dlg);
2134
2135 return status;
2136}
2137
Benny Prijono268ca612006-02-07 12:34:11 +00002138
2139/*
2140 * Create re-INVITE.
2141 */
2142PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2143 const pj_str_t *new_contact,
2144 const pjmedia_sdp_session *new_offer,
2145 pjsip_tx_data **p_tdata )
2146{
Benny Prijono26ff9062006-02-21 23:47:00 +00002147 pj_status_t status;
2148 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002149
Benny Prijono26ff9062006-02-21 23:47:00 +00002150 /* Check arguments. */
2151 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2152
2153 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002154 if (inv->invite_tsx!=NULL)
2155 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002156
2157
2158 pjsip_dlg_inc_lock(inv->dlg);
2159
2160 if (new_contact) {
2161 pj_str_t tmp;
2162 const pj_str_t STR_CONTACT = { "Contact", 7 };
2163
2164 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002165 contact_hdr = (pjsip_contact_hdr*)
2166 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002167 tmp.ptr, tmp.slen, NULL);
2168 if (!contact_hdr) {
2169 status = PJSIP_EINVALIDURI;
2170 goto on_return;
2171 }
2172 }
2173
2174
2175 if (new_offer) {
2176 if (!inv->neg) {
2177 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer,
2178 &inv->neg);
2179 if (status != PJ_SUCCESS)
2180 goto on_return;
2181
2182 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2183
2184 case PJMEDIA_SDP_NEG_STATE_NULL:
2185 pj_assert(!"Unexpected SDP neg state NULL");
2186 status = PJ_EBUG;
2187 goto on_return;
2188
2189 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2190 PJ_LOG(4,(inv->obj_name,
2191 "pjsip_inv_reinvite: already have an offer, new "
2192 "offer is ignored"));
2193 break;
2194
2195 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
2196 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
2197 new_offer);
2198 if (status != PJ_SUCCESS)
2199 goto on_return;
2200 break;
2201
2202 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2203 PJ_LOG(4,(inv->obj_name,
2204 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2205 "offer is ignored"));
2206 break;
2207
2208 case PJMEDIA_SDP_NEG_STATE_DONE:
2209 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2210 new_offer);
2211 if (status != PJ_SUCCESS)
2212 goto on_return;
2213 break;
2214 }
2215 }
2216
2217 if (contact_hdr)
2218 inv->dlg->local.contact = contact_hdr;
2219
2220 status = pjsip_inv_invite(inv, p_tdata);
2221
2222on_return:
2223 pjsip_dlg_dec_lock(inv->dlg);
2224 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002225}
2226
2227/*
2228 * Create UPDATE.
2229 */
2230PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2231 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002232 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002233 pjsip_tx_data **p_tdata )
2234{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002235 pjsip_contact_hdr *contact_hdr = NULL;
2236 pjsip_tx_data *tdata = NULL;
2237 pjmedia_sdp_session *sdp_copy;
2238 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002239
Benny Prijono1f7767b2007-10-03 18:28:49 +00002240 /* Verify arguments. */
2241 PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL);
2242
2243 /* Dialog must have been established */
2244 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2245 PJ_EINVALIDOP);
2246
2247 /* Invite session must not have been disconnected */
2248 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2249 PJ_EINVALIDOP);
2250
2251 /* Lock dialog. */
2252 pjsip_dlg_inc_lock(inv->dlg);
2253
2254 /* Process offer */
2255 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2256 PJ_LOG(4,(inv->dlg->obj_name,
2257 "Invalid SDP offer/answer state for UPDATE"));
2258 status = PJ_EINVALIDOP;
2259 goto on_error;
2260 }
2261
Benny Prijono60e31fc2009-04-23 11:50:25 +00002262 /* Notify negotiator about the new offer. This will fix the offer
2263 * with correct SDP origin.
2264 */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002265 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2266 offer);
2267 if (status != PJ_SUCCESS)
2268 goto on_error;
2269
Benny Prijono60e31fc2009-04-23 11:50:25 +00002270 /* Retrieve the "fixed" offer from negotiator */
2271 pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002272
2273 /* Update Contact if required */
2274 if (new_contact) {
2275 pj_str_t tmp;
2276 const pj_str_t STR_CONTACT = { "Contact", 7 };
2277
2278 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2279 contact_hdr = (pjsip_contact_hdr*)
2280 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2281 tmp.ptr, tmp.slen, NULL);
2282 if (!contact_hdr) {
2283 status = PJSIP_EINVALIDURI;
2284 goto on_error;
2285 }
2286
2287 inv->dlg->local.contact = contact_hdr;
2288 }
2289
2290 /* Create request */
2291 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2292 -1, &tdata);
2293 if (status != PJ_SUCCESS)
2294 goto on_error;
2295
2296 /* Attach SDP body */
2297 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2298 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2299
2300 /* Unlock dialog. */
2301 pjsip_dlg_dec_lock(inv->dlg);
2302
2303 *p_tdata = tdata;
2304
2305 return PJ_SUCCESS;
2306
2307on_error:
2308 if (tdata)
2309 pjsip_tx_data_dec_ref(tdata);
2310
2311 /* Unlock dialog. */
2312 pjsip_dlg_dec_lock(inv->dlg);
2313
2314 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002315}
2316
2317/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002318 * Create an ACK request.
2319 */
2320PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2321 int cseq,
2322 pjsip_tx_data **p_tdata)
2323{
2324 const pjmedia_sdp_session *sdp = NULL;
2325 pj_status_t status;
2326
2327 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2328
2329 /* Lock dialog. */
2330 pjsip_dlg_inc_lock(inv->dlg);
2331
2332 /* Destroy last_ack */
2333 if (inv->last_ack) {
2334 pjsip_tx_data_dec_ref(inv->last_ack);
2335 inv->last_ack = NULL;
2336 }
2337
2338 /* Create new ACK request */
2339 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2340 cseq, &inv->last_ack);
2341 if (status != PJ_SUCCESS) {
2342 pjsip_dlg_dec_lock(inv->dlg);
2343 return status;
2344 }
2345
2346 /* See if we have pending SDP answer to send */
2347 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2348 if (sdp) {
2349 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2350 }
2351
2352 /* Keep this for subsequent response retransmission */
2353 inv->last_ack_cseq = cseq;
2354 pjsip_tx_data_add_ref(inv->last_ack);
2355
2356 /* Done */
2357 *p_tdata = inv->last_ack;
2358
2359 /* Unlock dialog. */
2360 pjsip_dlg_dec_lock(inv->dlg);
2361
2362 return PJ_SUCCESS;
2363}
2364
2365/*
Benny Prijono268ca612006-02-07 12:34:11 +00002366 * Send a request or response message.
2367 */
2368PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002369 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002370{
2371 pj_status_t status;
2372
2373 /* Verify arguments. */
2374 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2375
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002376 PJ_LOG(5,(inv->obj_name, "Sending %s",
2377 pjsip_tx_data_get_info(tdata)));
2378
Benny Prijono268ca612006-02-07 12:34:11 +00002379 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002380 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002381
Benny Prijono64158af2006-04-04 11:06:34 +00002382 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002383
Benny Prijono22e48c92008-03-20 14:40:50 +00002384 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002385 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2386 inv->invite_tsx)
2387 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002388 pjsip_tx_data_dec_ref(tdata);
2389 pjsip_dlg_dec_lock(inv->dlg);
2390 return PJ_EINVALIDOP;
2391 }
2392
2393 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002394 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002395 tsx_inv_data->inv = inv;
2396
Benny Prijono64158af2006-04-04 11:06:34 +00002397 pjsip_dlg_dec_lock(inv->dlg);
2398
2399 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2400 tsx_inv_data);
2401 if (status != PJ_SUCCESS)
2402 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002403
2404 } else {
2405 pjsip_cseq_hdr *cseq;
2406
2407 /* Can only do this to send response to original INVITE
2408 * request.
2409 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002410 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 +00002411 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002412 PJ_EINVALIDOP);
2413
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002414 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002415 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002416 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002417 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002418 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002419 }
2420
Benny Prijono268ca612006-02-07 12:34:11 +00002421 if (status != PJ_SUCCESS)
2422 return status;
2423 }
2424
2425 /* Done (?) */
2426 return PJ_SUCCESS;
2427}
2428
2429
Benny Prijono8ad55352006-02-08 11:16:05 +00002430/*
2431 * Respond to incoming CANCEL request.
2432 */
2433static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2434 pjsip_transaction *cancel_tsx,
2435 pjsip_rx_data *rdata)
2436{
2437 pjsip_tx_data *tdata;
2438 pjsip_transaction *invite_tsx;
2439 pj_str_t key;
2440 pj_status_t status;
2441
2442 /* See if we have matching INVITE server transaction: */
2443
2444 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002445 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002446 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2447
2448 if (invite_tsx == NULL) {
2449
2450 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002451 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002452 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002453 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002454 &tdata);
2455
2456 } else {
2457 /* Always answer CANCEL will 200 (OK) regardless of
2458 * the state of the INVITE transaction.
2459 */
2460 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2461 &tdata);
2462 }
2463
2464 /* See if we have created the response successfully. */
2465 if (status != PJ_SUCCESS) return;
2466
2467 /* Send the CANCEL response */
2468 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2469 if (status != PJ_SUCCESS) return;
2470
2471
2472 /* See if we need to terminate the UAS INVITE transaction
2473 * with 487 (Request Terminated) response.
2474 */
2475 if (invite_tsx && invite_tsx->status_code < 200) {
2476
2477 pj_assert(invite_tsx->last_tx != NULL);
2478
2479 tdata = invite_tsx->last_tx;
2480
2481 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002482 if (status == PJ_SUCCESS) {
2483 /* Remove the message body */
2484 tdata->msg->body = NULL;
Benny Prijono1e08e4f2009-05-13 08:57:38 +00002485 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
2486 status = pjsip_100rel_tx_response(inv, tdata);
2487 } else {
2488 status = pjsip_dlg_send_response(inv->dlg, invite_tsx,
2489 tdata);
2490 }
Benny Prijonofc8bb142007-11-08 09:56:50 +00002491 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002492 }
2493
2494 if (invite_tsx)
2495 pj_mutex_unlock(invite_tsx->mutex);
2496}
2497
2498
2499/*
2500 * Respond to incoming BYE request.
2501 */
2502static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2503 pjsip_transaction *bye_tsx,
2504 pjsip_rx_data *rdata,
2505 pjsip_event *e )
2506{
2507 pj_status_t status;
2508 pjsip_tx_data *tdata;
2509
2510 /* Respond BYE with 200: */
2511
2512 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2513 if (status != PJ_SUCCESS) return;
2514
2515 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2516 if (status != PJ_SUCCESS) return;
2517
2518 /* Terminate session: */
2519
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002520 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002521 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002522 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002523 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002524}
2525
2526/*
Benny Prijono38998232006-02-08 22:44:25 +00002527 * Respond to BYE request.
2528 */
2529static void inv_handle_bye_response( pjsip_inv_session *inv,
2530 pjsip_transaction *tsx,
2531 pjsip_rx_data *rdata,
2532 pjsip_event *e )
2533{
2534 pj_status_t status;
2535
2536 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002537 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002538 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2539 return;
2540 }
2541
2542 /* Handle 401/407 challenge. */
2543 if (tsx->status_code == 401 || tsx->status_code == 407) {
2544
2545 pjsip_tx_data *tdata;
2546
2547 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2548 rdata,
2549 tsx->last_tx,
2550 &tdata);
2551
2552 if (status != PJ_SUCCESS) {
2553
2554 /* Does not have proper credentials.
2555 * End the session anyway.
2556 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002557 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002558 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2559
2560 } else {
2561 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002562 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002563 }
2564
2565 } else {
2566
2567 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002568 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002569 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2570 }
2571
2572}
2573
2574/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002575 * Respond to incoming UPDATE request.
2576 */
2577static void inv_respond_incoming_update(pjsip_inv_session *inv,
2578 pjsip_rx_data *rdata)
2579{
2580 pjmedia_sdp_neg_state neg_state;
2581 pj_status_t status;
2582 pjsip_tx_data *tdata = NULL;
2583
2584 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2585
2586 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2587 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2588 status = pjsip_dlg_create_response(inv->dlg, rdata,
2589 PJSIP_SC_REQUEST_PENDING, NULL,
2590 &tdata);
2591 }
2592 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2593 * receive UPDATE while we haven't sent answer.
2594 */
2595 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2596 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2597 status = pjsip_dlg_create_response(inv->dlg, rdata,
2598 PJSIP_SC_INTERNAL_SERVER_ERROR,
2599 NULL, &tdata);
2600
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002601 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2602 * This is a valid scenario according to session-timer draft.
2603 */
2604 } else if (rdata->msg_info.msg->body == NULL) {
2605
2606 status = pjsip_dlg_create_response(inv->dlg, rdata,
2607 200, NULL, &tdata);
2608
Benny Prijono1f7767b2007-10-03 18:28:49 +00002609 } else {
2610 /* We receive new offer from remote */
2611 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2612
2613 /* Application MUST have supplied the answer by now.
2614 * If so, negotiate the SDP.
2615 */
2616 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2617 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2618 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2619 {
2620 /* Negotiation has failed */
2621 status = pjsip_dlg_create_response(inv->dlg, rdata,
2622 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2623 NULL, &tdata);
2624 } else {
2625 /* New media has been negotiated successfully, send 200/OK */
2626 status = pjsip_dlg_create_response(inv->dlg, rdata,
2627 PJSIP_SC_OK, NULL, &tdata);
2628 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002629 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002630 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2631 if (status == PJ_SUCCESS)
2632 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2633 }
2634 }
2635 }
2636
2637 if (status != PJ_SUCCESS) {
2638 if (tdata != NULL) {
2639 pjsip_tx_data_dec_ref(tdata);
2640 tdata = NULL;
2641 }
2642 return;
2643 }
2644
2645 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2646}
2647
2648
2649/*
2650 * Handle incoming response to UAC UPDATE request.
2651 */
2652static void inv_handle_update_response( pjsip_inv_session *inv,
2653 pjsip_event *e)
2654{
2655 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2656 struct tsx_inv_data *tsx_inv_data = NULL;
2657 pj_status_t status = -1;
2658
Benny Prijono48ab2b72007-11-08 09:24:30 +00002659 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002660 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono48ab2b72007-11-08 09:24:30 +00002661 (tsx->status_code == 401 || tsx->status_code == 407)) {
2662
2663 pjsip_tx_data *tdata;
2664
2665 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2666 e->body.tsx_state.src.rdata,
2667 tsx->last_tx,
2668 &tdata);
2669
2670 if (status != PJ_SUCCESS) {
2671
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002672 /* Somehow failed. Probably it's not a good idea to terminate
2673 * the session since this is just a request within dialog. And
2674 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002675 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002676 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002677 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2678 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002679 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002680
2681 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002682 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002683 status = pjsip_inv_send_msg(inv, tdata);
2684 }
2685
2686 /* Process 2xx response */
2687 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002688 tsx->status_code/100 == 2 &&
2689 e->body.tsx_state.src.rdata->msg_info.msg->body)
2690 {
2691 status = inv_check_sdp_in_incoming_msg(inv, tsx,
2692 e->body.tsx_state.src.rdata);
2693
2694 } else {
2695 /* Get/attach invite session's transaction data */
2696 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2697 if (tsx_inv_data == NULL) {
2698 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2699 tsx_inv_data->inv = inv;
2700 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2701 }
2702 }
2703
2704 /* Otherwise if we don't get successful response, cancel
2705 * our negotiator.
2706 */
2707 if (status != PJ_SUCCESS &&
2708 pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
2709 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2710 {
2711 pjmedia_sdp_neg_cancel_offer(inv->neg);
2712
2713 /* Prevent from us cancelling different offer! */
2714 tsx_inv_data->sdp_done = PJ_TRUE;
2715 }
2716}
2717
2718
2719/*
2720 * Handle incoming reliable response.
2721 */
2722static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2723 pjsip_rx_data *rdata)
2724{
2725 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002726 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002727 pj_status_t status;
2728
2729 /* Create PRACK */
2730 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2731 if (status != PJ_SUCCESS)
2732 return;
2733
2734 /* See if we need to attach SDP answer on the PRACK request */
2735 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2736 if (sdp) {
2737 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2738 }
2739
2740 /* Send PRACK (must be using 100rel module!) */
2741 pjsip_100rel_send_prack(inv, tdata);
2742}
2743
2744
2745/*
2746 * Handle incoming PRACK.
2747 */
2748static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2749 pjsip_rx_data *rdata)
2750{
2751 pj_status_t status;
2752
2753 /* Run through 100rel module to see if we can accept this
2754 * PRACK request. The 100rel will send 200/OK to PRACK request.
2755 */
2756 status = pjsip_100rel_on_rx_prack(inv, rdata);
2757 if (status != PJ_SUCCESS)
2758 return;
2759
2760 /* Now check for SDP answer in the PRACK request */
2761 if (rdata->msg_info.msg->body) {
2762 status = inv_check_sdp_in_incoming_msg(inv,
2763 pjsip_rdata_get_tsx(rdata), rdata);
2764 } else {
2765 /* No SDP body */
2766 status = -1;
2767 }
2768
2769 /* If SDP negotiation has been successful, also mark the
2770 * SDP negotiation flag in the invite transaction to be
2771 * done too.
2772 */
2773 if (status == PJ_SUCCESS && inv->invite_tsx) {
2774 struct tsx_inv_data *tsx_inv_data;
2775
2776 /* Get/attach invite session's transaction data */
2777 tsx_inv_data = (struct tsx_inv_data*)
2778 inv->invite_tsx->mod_data[mod_inv.mod.id];
2779 if (tsx_inv_data == NULL) {
2780 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2781 struct tsx_inv_data);
2782 tsx_inv_data->inv = inv;
2783 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2784 }
2785
2786 tsx_inv_data->sdp_done = PJ_TRUE;
2787 }
2788}
2789
2790
2791/*
Benny Prijono8ad55352006-02-08 11:16:05 +00002792 * State NULL is before anything is sent/received.
2793 */
2794static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002795{
2796 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2797 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2798
2799 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2800
2801 if (tsx->method.id == PJSIP_INVITE_METHOD) {
2802
Benny Prijono64f851e2006-02-23 13:49:28 +00002803 /* Keep the initial INVITE transaction. */
2804 if (inv->invite_tsx == NULL)
2805 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00002806
Benny Prijono64f851e2006-02-23 13:49:28 +00002807 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00002808
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002809 /* Save the original INVITE request, if on_redirected() callback
2810 * is implemented. We may need to resend the INVITE if we receive
2811 * redirection response.
2812 */
2813 if (mod_inv.cb.on_redirected) {
2814 if (inv->invite_req) {
2815 pjsip_tx_data_dec_ref(inv->invite_req);
2816 inv->invite_req = NULL;
2817 }
2818 inv->invite_req = tsx->last_tx;
2819 pjsip_tx_data_add_ref(inv->invite_req);
2820 }
2821
Benny Prijono268ca612006-02-07 12:34:11 +00002822 switch (tsx->state) {
2823 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002824 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002825 break;
2826 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002827 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002828 break;
2829 }
2830
2831 } else {
2832 switch (tsx->state) {
2833 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002834 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002835 break;
Benny Prijono38998232006-02-08 22:44:25 +00002836 case PJSIP_TSX_STATE_PROCEEDING:
2837 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
2838 if (tsx->status_code > 100)
2839 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
2840 break;
Benny Prijono2285e7e2008-12-17 14:28:18 +00002841 case PJSIP_TSX_STATE_TERMINATED:
2842 /* there is a failure in sending response. */
2843 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2844 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2845 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002846 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002847 inv_on_state_incoming(inv, e);
2848 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002849 }
2850 }
2851
2852 } else {
2853 pj_assert(!"Unexpected transaction type");
2854 }
2855}
2856
Benny Prijono8ad55352006-02-08 11:16:05 +00002857/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002858 * Generic UAC transaction handler:
2859 * - resend request on 401 or 407 response.
2860 * - terminate dialog on 408 and 481 response.
2861 */
2862static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
2863 pjsip_event *e)
2864{
2865 /* RFC 3261 Section 12.2.1.2:
2866 * If the response for a request within a dialog is a 481
2867 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
2868 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
2869 * no response at all is received for the request (the client
2870 * transaction would inform the TU about the timeout.)
2871 *
2872 * For INVITE initiated dialogs, terminating the dialog consists of
2873 * sending a BYE.
2874 *
2875 * Note:
2876 * according to X, this should terminate dialog usage only, not the
2877 * dialog.
2878 */
2879 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2880
2881 pj_assert(tsx->role == PJSIP_UAC_ROLE);
2882
2883 /* Note that 481 response to CANCEL does not terminate dialog usage,
2884 * but only the transaction.
2885 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00002886 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
2887 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002888 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00002889 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
2890 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
2891 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002892 {
2893 pjsip_tx_data *bye;
2894 pj_status_t status;
2895
2896 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2897 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2898
2899 /* Send BYE */
2900 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2901 -1, &bye);
2902 if (status == PJ_SUCCESS) {
2903 pjsip_inv_send_msg(inv, bye);
2904 }
2905
2906 return PJ_TRUE; /* Handled */
2907
2908 }
2909 /* Handle 401/407 challenge. */
2910 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2911 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
2912 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
2913 {
2914
2915 pjsip_tx_data *tdata;
2916 pj_status_t status;
2917
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002918 if (tsx->method.id == PJSIP_INVITE_METHOD)
2919 inv->invite_tsx = NULL;
2920
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002921 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2922 e->body.tsx_state.src.rdata,
2923 tsx->last_tx, &tdata);
2924
2925 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002926 /* Somehow failed. Probably it's not a good idea to terminate
2927 * the session since this is just a request within dialog. And
2928 * even if we terminate we should send BYE.
2929 */
2930 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002931 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2932 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002933 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002934
2935 } else {
2936 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002937 status = pjsip_inv_send_msg(inv, tdata);
2938 }
2939
2940 return PJ_TRUE; /* Handled */
2941
2942 } else {
2943 return PJ_FALSE; /* Unhandled */
2944 }
2945}
2946
2947
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002948/* Handle call rejection, especially with regard to processing call
2949 * redirection. We need to handle the following scenarios:
2950 * - 3xx response is received -- see if on_redirected() callback is
2951 * implemented. If so, add the Contact URIs in the response to the
2952 * target set and notify user.
2953 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
2954 * if so fetch the next target if any and notify the on_redirected()
2955 * callback.
2956 * - for other cases -- disconnect the session.
2957 */
2958static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
2959{
2960 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2961 pj_status_t status;
2962
2963 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
2964
2965 if (mod_inv.cb.on_redirected == NULL) {
2966
2967 /* Redirection callback is not implemented, disconnect the
2968 * call.
2969 */
2970 goto terminate_session;
2971
2972 } else {
2973 const pjsip_msg *res_msg;
2974
2975 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
2976
2977 /* Gather all Contact URI's in the response and add them
2978 * to target set. The function will take care of removing
2979 * duplicate URI's.
2980 */
2981 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
2982 inv->dlg->pool, res_msg);
2983
2984 /* Recurse to alternate targets if application allows us */
2985 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
2986 {
2987 /* Recursion fails, terminate session now */
2988 goto terminate_session;
2989 }
2990
2991 /* Done */
2992 }
2993
2994 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
2995 !inv->cancelling)
2996 {
2997
2998 /* Handle authentication failure:
2999 * Resend the request with Authorization header.
3000 */
3001 pjsip_tx_data *tdata;
3002
3003 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
3004 e->body.tsx_state.src.rdata,
3005 tsx->last_tx,
3006 &tdata);
3007
3008 if (status != PJ_SUCCESS) {
3009
3010 /* Does not have proper credentials. If we are currently
3011 * recursing, try the next target. Otherwise end the session.
3012 */
3013 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3014 {
3015 /* Recursion fails, terminate session now */
3016 goto terminate_session;
3017 }
3018
3019 } else {
3020
3021 /* Restart session. */
3022 pjsip_inv_uac_restart(inv, PJ_FALSE);
3023
3024 /* Send the request. */
3025 status = pjsip_inv_send_msg(inv, tdata);
3026 }
3027
3028 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3029 /* Global error */
3030 goto terminate_session;
3031
3032 } else {
3033 /* See if we have alternate target to try */
3034 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3035 /* Recursion fails, terminate session now */
3036 goto terminate_session;
3037 }
3038 }
3039 return;
3040
3041terminate_session:
3042 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3043 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3044}
3045
3046
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003047/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003048 * State CALLING is after sending initial INVITE request but before
3049 * any response (with tag) is received.
3050 */
3051static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003052{
3053 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3054 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003055 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003056
3057 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3058
Benny Prijono8ad55352006-02-08 11:16:05 +00003059 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003060
3061 switch (tsx->state) {
3062
Benny Prijono64f851e2006-02-23 13:49:28 +00003063 case PJSIP_TSX_STATE_CALLING:
3064 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3065 break;
3066
Benny Prijono268ca612006-02-07 12:34:11 +00003067 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003068 if (inv->pending_cancel) {
3069 pjsip_tx_data *cancel;
3070
3071 inv->pending_cancel = PJ_FALSE;
3072
3073 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3074 if (status == PJ_SUCCESS && cancel)
3075 status = pjsip_inv_send_msg(inv, cancel);
3076 }
3077
Benny Prijono268ca612006-02-07 12:34:11 +00003078 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003079
Benny Prijono8ad55352006-02-08 11:16:05 +00003080 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003081
3082 inv_check_sdp_in_incoming_msg(inv, tsx,
3083 e->body.tsx_state.src.rdata);
3084
Benny Prijono1f7767b2007-10-03 18:28:49 +00003085 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3086 inv_handle_incoming_reliable_response(
3087 inv, e->body.tsx_state.src.rdata);
3088 }
3089
Benny Prijono268ca612006-02-07 12:34:11 +00003090 } else {
3091 /* Ignore 100 (Trying) response, as it doesn't change
3092 * session state. It only ceases retransmissions.
3093 */
3094 }
3095 break;
3096
3097 case PJSIP_TSX_STATE_COMPLETED:
3098 if (tsx->status_code/100 == 2) {
3099
3100 /* This should not happen.
3101 * When transaction receives 2xx, it should be terminated
3102 */
3103 pj_assert(0);
Benny Prijono8ad55352006-02-08 11:16:05 +00003104 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003105
3106 inv_check_sdp_in_incoming_msg(inv, tsx,
3107 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003108
3109 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003110 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003111 }
3112 break;
3113
3114 case PJSIP_TSX_STATE_TERMINATED:
3115 /* INVITE transaction can be terminated either because UAC
3116 * transaction received 2xx response or because of transport
3117 * error.
3118 */
3119 if (tsx->status_code/100 == 2) {
3120 /* This must be receipt of 2xx response */
3121
3122 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003123 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003124
Benny Prijonoa66c7152006-02-09 01:26:14 +00003125 inv_check_sdp_in_incoming_msg(inv, tsx,
3126 e->body.tsx_state.src.rdata);
3127
Benny Prijono268ca612006-02-07 12:34:11 +00003128 /* Send ACK */
3129 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3130
Benny Prijonod5f9f422007-11-25 04:40:07 +00003131 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003132
Benny Prijono268ca612006-02-07 12:34:11 +00003133 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003134 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003135 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003136 }
3137 break;
3138
Benny Prijono34a404e2006-02-09 14:38:30 +00003139 default:
3140 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003141 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003142
Benny Prijono1f7767b2007-10-03 18:28:49 +00003143 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003144 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003145 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003146 * Transaction Does Not Exist), 408, or when it's timed out. In these
3147 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003148 * Note that 481 response to CANCEL does not terminate dialog usage,
3149 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003150 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003151 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3152 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003153 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3154 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003155 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003156 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003157 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003158 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3159 }
Benny Prijono268ca612006-02-07 12:34:11 +00003160 }
3161}
3162
Benny Prijono8ad55352006-02-08 11:16:05 +00003163/*
3164 * State INCOMING is after we received the request, but before
3165 * responses with tag are sent.
3166 */
3167static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003168{
3169 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3170 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3171
3172 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3173
Benny Prijono8ad55352006-02-08 11:16:05 +00003174 if (tsx == inv->invite_tsx) {
3175
3176 /*
3177 * Handle the INVITE state transition.
3178 */
3179
Benny Prijono268ca612006-02-07 12:34:11 +00003180 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003181
Benny Prijono64f851e2006-02-23 13:49:28 +00003182 case PJSIP_TSX_STATE_TRYING:
3183 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3184 break;
3185
Benny Prijono268ca612006-02-07 12:34:11 +00003186 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003187 /*
3188 * Transaction sent provisional response.
3189 */
Benny Prijono268ca612006-02-07 12:34:11 +00003190 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003191 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003192 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003193
Benny Prijono268ca612006-02-07 12:34:11 +00003194 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003195 /*
3196 * Transaction sent final response.
3197 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003198 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003199 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003200 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003201 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003202 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003203 }
Benny Prijono268ca612006-02-07 12:34:11 +00003204 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003205
Benny Prijono268ca612006-02-07 12:34:11 +00003206 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003207 /*
3208 * This happens on transport error (e.g. failed to send
3209 * response)
3210 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003211 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003212 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003213 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003214
Benny Prijono268ca612006-02-07 12:34:11 +00003215 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003216 pj_assert(!"Unexpected INVITE state");
3217 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003218 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003219
3220 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3221 tsx->role == PJSIP_ROLE_UAS &&
3222 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3223 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3224 {
3225
3226 /*
3227 * Handle incoming CANCEL request.
3228 */
3229
3230 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3231
Benny Prijono268ca612006-02-07 12:34:11 +00003232 }
3233}
3234
Benny Prijono8ad55352006-02-08 11:16:05 +00003235/*
3236 * State EARLY is for both UAS and UAC, after response with To tag
3237 * is sent/received.
3238 */
3239static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003240{
3241 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3242 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3243
3244 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3245
Benny Prijono8ad55352006-02-08 11:16:05 +00003246 if (tsx == inv->invite_tsx) {
3247
3248 /*
3249 * Handle the INVITE state progress.
3250 */
Benny Prijono268ca612006-02-07 12:34:11 +00003251
3252 switch (tsx->state) {
3253
3254 case PJSIP_TSX_STATE_PROCEEDING:
3255 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003256 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003257
3258 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3259 inv_check_sdp_in_incoming_msg(inv, tsx,
3260 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003261
3262 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3263 inv_handle_incoming_reliable_response(
3264 inv, e->body.tsx_state.src.rdata);
3265 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003266 }
Benny Prijono268ca612006-02-07 12:34:11 +00003267 break;
3268
3269 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003270 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003271 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003272 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3273 inv_check_sdp_in_incoming_msg(inv, tsx,
3274 e->body.tsx_state.src.rdata);
3275 }
3276
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003277 } else if (tsx->role == PJSIP_ROLE_UAC) {
3278
3279 handle_uac_call_rejection(inv, e);
3280
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003281 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003282 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003283 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003284 }
Benny Prijono268ca612006-02-07 12:34:11 +00003285 break;
3286
Benny Prijonof3195072006-02-14 21:15:30 +00003287 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003288 /* For some reason can go here (maybe when ACK for 2xx has
3289 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003290
Benny Prijono268ca612006-02-07 12:34:11 +00003291 case PJSIP_TSX_STATE_TERMINATED:
3292 /* INVITE transaction can be terminated either because UAC
3293 * transaction received 2xx response or because of transport
3294 * error.
3295 */
3296 if (tsx->status_code/100 == 2) {
3297
3298 /* This must be receipt of 2xx response */
3299
3300 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003301 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003302
Benny Prijonoa66c7152006-02-09 01:26:14 +00003303 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3304 inv_check_sdp_in_incoming_msg(inv, tsx,
3305 e->body.tsx_state.src.rdata);
3306 }
3307
Benny Prijono268ca612006-02-07 12:34:11 +00003308 /* if UAC, send ACK and move state to confirmed. */
3309 if (tsx->role == PJSIP_ROLE_UAC) {
3310 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3311
Benny Prijonod5f9f422007-11-25 04:40:07 +00003312 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003313 }
3314
3315 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003316 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003317 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003318 }
3319 break;
3320
3321 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003322 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003323 }
3324
Benny Prijono8ad55352006-02-08 11:16:05 +00003325 } else if (inv->role == PJSIP_ROLE_UAS &&
3326 tsx->role == PJSIP_ROLE_UAS &&
3327 tsx->method.id == PJSIP_CANCEL_METHOD &&
3328 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3329 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3330 {
Benny Prijono268ca612006-02-07 12:34:11 +00003331
Benny Prijono8ad55352006-02-08 11:16:05 +00003332 /*
3333 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003334 */
3335
Benny Prijono8ad55352006-02-08 11:16:05 +00003336 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3337
Benny Prijono1f7767b2007-10-03 18:28:49 +00003338 } else if (tsx->role == PJSIP_ROLE_UAS &&
3339 tsx->state == PJSIP_TSX_STATE_TRYING &&
3340 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003341 {
3342 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003343 * Handle incoming UPDATE
3344 */
3345 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3346
3347
3348 } else if (tsx->role == PJSIP_ROLE_UAC &&
3349 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3350 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3351 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3352 {
3353 /*
3354 * Handle response to outgoing UPDATE request.
3355 */
3356 inv_handle_update_response(inv, e);
3357
3358 } else if (tsx->role == PJSIP_ROLE_UAS &&
3359 tsx->state == PJSIP_TSX_STATE_TRYING &&
3360 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3361 {
3362 /*
3363 * Handle incoming PRACK
3364 */
3365 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3366
3367 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003368
3369 /* Generic handling for UAC tsx completion */
3370 handle_uac_tsx_response(inv, e);
Benny Prijono7efa2d62009-04-27 12:50:16 +00003371
3372 } else if (tsx->role == PJSIP_ROLE_UAS &&
3373 tsx->method.id == PJSIP_BYE_METHOD &&
3374 tsx->status_code < 200 &&
3375 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3376 {
3377 /* Received BYE before the 2xx/OK response to INVITE.
3378 * Assume that the 2xx/OK response is lost and the BYE
3379 * arrives earlier.
3380 */
3381 inv_respond_incoming_bye(inv, tsx, e->body.tsx_state.src.rdata, e);
3382
3383 /* Set timer just in case we will never get the final response
3384 * for INVITE.
3385 */
3386 pjsip_tsx_set_timeout(inv->invite_tsx, 64*pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00003387 }
3388}
3389
Benny Prijono8ad55352006-02-08 11:16:05 +00003390/*
3391 * State CONNECTING is after 2xx response to INVITE is sent/received.
3392 */
3393static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003394{
3395 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3396 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3397
3398 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3399
Benny Prijono8ad55352006-02-08 11:16:05 +00003400 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003401
Benny Prijono8ad55352006-02-08 11:16:05 +00003402 /*
3403 * Handle INVITE state progression.
3404 */
Benny Prijono268ca612006-02-07 12:34:11 +00003405 switch (tsx->state) {
3406
3407 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003408 /* It can only go here if incoming ACK request has the same Via
3409 * branch parameter as the INVITE transaction.
3410 */
3411 if (tsx->status_code/100 == 2) {
3412 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3413 inv_check_sdp_in_incoming_msg(inv, tsx,
3414 e->body.tsx_state.src.rdata);
3415 }
3416
Benny Prijono38998232006-02-08 22:44:25 +00003417 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003418 }
Benny Prijono268ca612006-02-07 12:34:11 +00003419 break;
3420
3421 case PJSIP_TSX_STATE_TERMINATED:
3422 /* INVITE transaction can be terminated either because UAC
3423 * transaction received 2xx response or because of transport
3424 * error.
3425 */
3426 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003427 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003428 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003429 }
3430 break;
3431
3432 case PJSIP_TSX_STATE_DESTROYED:
3433 /* Do nothing. */
3434 break;
3435
3436 default:
3437 pj_assert(!"Unexpected state");
3438 }
3439
Benny Prijono8ad55352006-02-08 11:16:05 +00003440 } else if (tsx->role == PJSIP_ROLE_UAS &&
3441 tsx->method.id == PJSIP_BYE_METHOD &&
3442 tsx->status_code < 200 &&
3443 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3444 {
3445
3446 /*
3447 * Handle incoming BYE.
3448 */
3449
3450 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3451
Benny Prijono38998232006-02-08 22:44:25 +00003452 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3453 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003454 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3455 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003456 {
3457
3458 /*
3459 * Outgoing BYE
3460 */
3461 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3462
Benny Prijono268ca612006-02-07 12:34:11 +00003463 }
Benny Prijono70127222006-07-02 14:53:05 +00003464 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3465 tsx->role == PJSIP_ROLE_UAS &&
3466 tsx->status_code < 200 &&
3467 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3468 {
Benny Prijono38998232006-02-08 22:44:25 +00003469
Benny Prijono70127222006-07-02 14:53:05 +00003470 /*
3471 * Handle strandled incoming CANCEL.
3472 */
3473 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3474 pjsip_tx_data *tdata;
3475 pj_status_t status;
3476
3477 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3478 if (status != PJ_SUCCESS) return;
3479
3480 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3481 if (status != PJ_SUCCESS) return;
3482
Benny Prijono1f7767b2007-10-03 18:28:49 +00003483 } else if (tsx->role == PJSIP_ROLE_UAS &&
3484 tsx->state == PJSIP_TSX_STATE_TRYING &&
3485 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3486 {
3487 /*
3488 * Handle incoming UPDATE
3489 */
3490 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3491
3492
3493 } else if (tsx->role == PJSIP_ROLE_UAC &&
3494 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3495 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3496 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3497 {
3498 /*
3499 * Handle response to outgoing UPDATE request.
3500 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003501 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003502 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003503
3504 } else if (tsx->role == PJSIP_ROLE_UAS &&
3505 tsx->state == PJSIP_TSX_STATE_TRYING &&
3506 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3507 {
3508 /*
3509 * Handle incoming PRACK
3510 */
3511 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3512
3513 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono87402382008-02-21 19:28:21 +00003514
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003515 /* Generic handling for UAC tsx completion */
3516 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003517 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003518
Benny Prijono268ca612006-02-07 12:34:11 +00003519}
3520
Benny Prijono8ad55352006-02-08 11:16:05 +00003521/*
3522 * State CONFIRMED is after ACK is sent/received.
3523 */
3524static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003525{
3526 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3527 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3528
3529 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3530
Benny Prijono268ca612006-02-07 12:34:11 +00003531
Benny Prijono8ad55352006-02-08 11:16:05 +00003532 if (tsx->method.id == PJSIP_BYE_METHOD &&
3533 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003534 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3535 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003536 {
Benny Prijono38998232006-02-08 22:44:25 +00003537
Benny Prijono8ad55352006-02-08 11:16:05 +00003538 /*
Benny Prijono38998232006-02-08 22:44:25 +00003539 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003540 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003541
Benny Prijonoa66c7152006-02-09 01:26:14 +00003542 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003543
Benny Prijono8ad55352006-02-08 11:16:05 +00003544 }
3545 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3546 tsx->role == PJSIP_ROLE_UAS &&
3547 tsx->status_code < 200 &&
3548 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3549 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003550
Benny Prijono8ad55352006-02-08 11:16:05 +00003551 /*
3552 * Handle incoming BYE.
3553 */
Benny Prijono268ca612006-02-07 12:34:11 +00003554
Benny Prijono8ad55352006-02-08 11:16:05 +00003555 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3556
Benny Prijono268ca612006-02-07 12:34:11 +00003557 }
Benny Prijono70127222006-07-02 14:53:05 +00003558 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3559 tsx->role == PJSIP_ROLE_UAS &&
3560 tsx->status_code < 200 &&
3561 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3562 {
3563
3564 /*
3565 * Handle strandled incoming CANCEL.
3566 */
3567 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3568 pjsip_tx_data *tdata;
3569 pj_status_t status;
3570
3571 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3572 if (status != PJ_SUCCESS) return;
3573
3574 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3575 if (status != PJ_SUCCESS) return;
3576
3577 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003578 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3579 tsx->role == PJSIP_ROLE_UAS)
3580 {
3581
3582 /*
3583 * Handle incoming re-INVITE
3584 */
3585 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3586
3587 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3588 pjsip_tx_data *tdata;
3589 pj_status_t status;
3590
3591 /* Check if we have INVITE pending. */
3592 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003593 pj_str_t reason;
3594
3595 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003596
3597 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003598 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3599 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003600 if (status != PJ_SUCCESS)
3601 return;
3602
3603 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3604
3605
3606 return;
3607 }
3608
3609 /* Save the invite transaction. */
3610 inv->invite_tsx = tsx;
3611
3612 /* Process SDP in incoming message. */
3613 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3614
3615 if (status != PJ_SUCCESS) {
3616
3617 /* Not Acceptable */
3618 const pjsip_hdr *accept;
3619
3620 status = pjsip_dlg_create_response(inv->dlg, rdata,
3621 488, NULL, &tdata);
3622 if (status != PJ_SUCCESS)
3623 return;
3624
3625
3626 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3627 NULL);
3628 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003629 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003630 pjsip_hdr_clone(tdata->pool, accept));
3631 }
3632
3633 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3634
3635 return;
3636 }
3637
3638 /* Create 2xx ANSWER */
3639 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3640 if (status != PJ_SUCCESS)
3641 return;
3642
Benny Prijono7d910092007-06-20 04:19:46 +00003643 /* If the INVITE request has SDP body, send answer.
3644 * Otherwise generate offer from local active SDP.
3645 */
3646 if (rdata->msg_info.msg->body != NULL) {
3647 status = process_answer(inv, 200, tdata, NULL);
3648 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003649 /* INVITE does not have SDP.
3650 * If on_create_offer() callback is implemented, ask app.
3651 * to generate an offer, otherwise just send active local
3652 * SDP to signal that nothing gets modified.
3653 */
3654 pjmedia_sdp_session *sdp = NULL;
3655
3656 if (mod_inv.cb.on_create_offer) {
3657 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3658 if (sdp) {
Benny Prijono60e31fc2009-04-23 11:50:25 +00003659 /* Notify negotiator about the new offer. This will
3660 * fix the offer with correct SDP origin.
3661 */
Benny Prijono77998ce2007-06-20 10:03:46 +00003662 status = pjmedia_sdp_neg_modify_local_offer(dlg->pool,
3663 inv->neg,
3664 sdp);
Benny Prijono60e31fc2009-04-23 11:50:25 +00003665
3666 /* Retrieve the "fixed" offer from negotiator */
Benny Prijonoc8fe3df2009-04-29 20:56:57 +00003667 if (status==PJ_SUCCESS) {
3668 const pjmedia_sdp_session *lsdp = NULL;
3669 pjmedia_sdp_neg_get_neg_local(inv->neg, &lsdp);
3670 sdp = (pjmedia_sdp_session*)lsdp;
3671 }
Benny Prijono77998ce2007-06-20 10:03:46 +00003672 }
3673 }
3674
3675 if (sdp == NULL) {
3676 const pjmedia_sdp_session *active_sdp = NULL;
3677 status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
3678 inv->neg,
3679 &active_sdp);
3680 if (status == PJ_SUCCESS)
3681 sdp = (pjmedia_sdp_session*) active_sdp;
3682 }
3683
3684 if (sdp) {
3685 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003686 }
3687 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003688
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003689 if (status != PJ_SUCCESS) {
3690 /*
3691 * SDP negotiation has failed.
3692 */
3693 pj_status_t rc;
3694 pj_str_t reason;
3695
3696 /* Delete the 2xx answer */
3697 pjsip_tx_data_dec_ref(tdata);
3698
3699 /* Create 500 response */
3700 reason = pj_str("SDP negotiation failed");
3701 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3702 &tdata);
3703 if (rc == PJ_SUCCESS) {
3704 pjsip_warning_hdr *w;
3705 const pj_str_t *endpt_name;
3706
3707 endpt_name = pjsip_endpt_name(dlg->endpt);
3708 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3709 endpt_name,
3710 status);
3711 if (w)
3712 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3713
3714 pjsip_inv_send_msg(inv, tdata);
3715 }
3716 return;
3717 }
3718
3719 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003720 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003721
Benny Prijono7d910092007-06-20 04:19:46 +00003722 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
3723 /* This is the case where ACK has the same branch as
3724 * the INVITE request.
3725 */
3726 if (tsx->status_code/100 == 2 &&
3727 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3728 {
3729 inv_check_sdp_in_incoming_msg(inv, tsx,
3730 e->body.tsx_state.src.rdata);
3731 }
3732
Benny Prijono26ff9062006-02-21 23:47:00 +00003733 }
3734
3735 }
3736 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3737 tsx->role == PJSIP_ROLE_UAC)
3738 {
Benny Prijono22e48c92008-03-20 14:40:50 +00003739
Benny Prijono26ff9062006-02-21 23:47:00 +00003740 /*
3741 * Handle outgoing re-INVITE
3742 */
Benny Prijono22e48c92008-03-20 14:40:50 +00003743 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
3744
Benny Prijono61fc5e62008-06-25 18:35:31 +00003745 /* Must not have other pending INVITE transaction */
3746 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
3747
Benny Prijono22e48c92008-03-20 14:40:50 +00003748 /* Save pending invite transaction */
3749 inv->invite_tsx = tsx;
3750
3751 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
3752 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00003753 {
3754
3755 /* Re-INVITE was accepted. */
3756
3757 /* Process SDP */
3758 inv_check_sdp_in_incoming_msg(inv, tsx,
3759 e->body.tsx_state.src.rdata);
3760
3761 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00003762 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003763
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003764 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00003765
3766 /* Handle response that terminates dialog */
3767 /* Nothing to do (already handled) */
3768
Benny Prijono77998ce2007-06-20 10:03:46 +00003769 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
3770
3771 pjmedia_sdp_neg_state neg_state;
3772
3773 /* Outgoing INVITE transaction has failed, cancel SDP nego */
3774 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
3775 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
3776 pjmedia_sdp_neg_cancel_offer(inv->neg);
3777 }
Benny Prijonoe641a742009-05-01 12:01:28 +00003778
3779 if (tsx == inv->invite_tsx)
3780 inv->invite_tsx = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00003781 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003782
3783 } else if (tsx->role == PJSIP_ROLE_UAS &&
3784 tsx->state == PJSIP_TSX_STATE_TRYING &&
3785 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3786 {
3787 /*
3788 * Handle incoming UPDATE
3789 */
3790 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3791
3792 } else if (tsx->role == PJSIP_ROLE_UAC &&
3793 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3794 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3795 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3796 {
3797 /*
3798 * Handle response to outgoing UPDATE request.
3799 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003800 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003801 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003802
3803 } else if (tsx->role == PJSIP_ROLE_UAS &&
3804 tsx->state == PJSIP_TSX_STATE_TRYING &&
3805 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3806 {
3807 /*
3808 * Handle strandled incoming PRACK
3809 */
3810 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3811
3812 } else if (tsx->role == PJSIP_ROLE_UAC) {
3813 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003814 * Handle 401/407/408/481 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00003815 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003816 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003817 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003818
Benny Prijono268ca612006-02-07 12:34:11 +00003819}
3820
Benny Prijono8ad55352006-02-08 11:16:05 +00003821/*
3822 * After session has been terminated, but before dialog is destroyed
3823 * (because dialog has other usages, or because dialog is waiting for
3824 * the last transaction to terminate).
3825 */
3826static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003827{
Benny Prijono8ad55352006-02-08 11:16:05 +00003828 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3829 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00003830
Benny Prijono8ad55352006-02-08 11:16:05 +00003831 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3832
Benny Prijono70127222006-07-02 14:53:05 +00003833 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00003834 tsx->status_code < 200 &&
3835 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3836 {
Benny Prijono70127222006-07-02 14:53:05 +00003837 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00003838
3839 /*
Benny Prijono70127222006-07-02 14:53:05 +00003840 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00003841 */
Benny Prijono70127222006-07-02 14:53:05 +00003842 if (tsx->method.id == PJSIP_BYE_METHOD) {
3843 inv_respond_incoming_bye( inv, tsx, rdata, e );
3844 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
3845 /*
3846 * Respond CANCEL with 200/OK too.
3847 */
3848 pjsip_tx_data *tdata;
3849 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00003850
Benny Prijono70127222006-07-02 14:53:05 +00003851 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3852 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00003853
Benny Prijono70127222006-07-02 14:53:05 +00003854 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3855 if (status != PJ_SUCCESS) return;
3856
3857 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00003858
3859 } else if (tsx->role == PJSIP_ROLE_UAC) {
3860 /*
3861 * Handle 401/407/408/481 response
3862 */
3863 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00003864 }
Benny Prijono268ca612006-02-07 12:34:11 +00003865}
3866