blob: e1bcd0df2896bd4578bf91a58150fcabab987c13 [file] [log] [blame]
Benny Prijono268ca612006-02-07 12:34:11 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono268ca612006-02-07 12:34:11 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjsip-ua/sip_inv.h>
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000020#include <pjsip-ua/sip_100rel.h>
Benny Prijono268ca612006-02-07 12:34:11 +000021#include <pjsip/sip_module.h>
22#include <pjsip/sip_endpoint.h>
23#include <pjsip/sip_event.h>
24#include <pjsip/sip_transaction.h>
25#include <pjmedia/sdp.h>
26#include <pjmedia/sdp_neg.h>
Benny Prijono95196582006-02-09 00:13:40 +000027#include <pjmedia/errno.h>
Benny Prijono268ca612006-02-07 12:34:11 +000028#include <pj/string.h>
29#include <pj/pool.h>
30#include <pj/assert.h>
Benny Prijono8ad55352006-02-08 11:16:05 +000031#include <pj/os.h>
Benny Prijonoa66c7152006-02-09 01:26:14 +000032#include <pj/log.h>
33
Benny Prijono1f7767b2007-10-03 18:28:49 +000034/*
35 * Note on offer/answer:
36 *
37 * The offer/answer framework in this implementation assumes the occurence
38 * of SDP in a particular request/response according to this table:
39
40 offer answer Note:
41 ========================================================================
42 INVITE X INVITE may contain offer
43 18x/INVITE X X Response may contain offer or answer
44 2xx/INVITE X X Response may contain offer or answer
45 ACK X ACK may contain answer
46
47 PRACK X PRACK can only contain answer
48 2xx/PRACK Response may not have offer nor answer
49
50 UPDATE X UPDATE may only contain offer
51 2xx/UPDATE X Response may only contain answer
52 ========================================================================
53
54 *
55 */
Benny Prijono268ca612006-02-07 12:34:11 +000056
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000057#define THIS_FILE "sip_inv.c"
Benny Prijono268ca612006-02-07 12:34:11 +000058
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000059static const char *inv_state_names[] =
60{
Benny Prijono4be63b52006-11-25 14:50:25 +000061 "NULL",
62 "CALLING",
63 "INCOMING",
64 "EARLY",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000065 "CONNECTING",
Benny Prijonoc5055702007-01-13 23:20:18 +000066 "CONFIRMED",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000067 "DISCONNCTD",
68 "TERMINATED",
69};
70
Benny Prijono1f7767b2007-10-03 18:28:49 +000071/* UPDATE method */
72const pjsip_method pjsip_update_method =
73{
74 PJSIP_OTHER_METHOD,
75 { "UPDATE", 6 }
76};
77
Benny Prijono268ca612006-02-07 12:34:11 +000078/*
79 * Static prototypes.
80 */
81static pj_status_t mod_inv_load(pjsip_endpoint *endpt);
82static pj_status_t mod_inv_unload(void);
83static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata);
84static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata);
85static void mod_inv_on_tsx_state(pjsip_transaction*, pjsip_event*);
86
Benny Prijono8ad55352006-02-08 11:16:05 +000087static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e);
88static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e);
89static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e);
90static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e);
91static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e);
92static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e);
93static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e);
Benny Prijono268ca612006-02-07 12:34:11 +000094
Benny Prijono7d910092007-06-20 04:19:46 +000095static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
96 pjsip_transaction *tsx,
97 pjsip_rx_data *rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +000098static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv );
99static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
100 const pjmedia_sdp_session *c_sdp);
Benny Prijono7d910092007-06-20 04:19:46 +0000101static pj_status_t process_answer( pjsip_inv_session *inv,
102 int st_code,
103 pjsip_tx_data *tdata,
104 const pjmedia_sdp_session *local_sdp);
105
Benny Prijono8ad55352006-02-08 11:16:05 +0000106static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
Benny Prijono268ca612006-02-07 12:34:11 +0000107{
108 &inv_on_state_null,
109 &inv_on_state_calling,
110 &inv_on_state_incoming,
111 &inv_on_state_early,
112 &inv_on_state_connecting,
113 &inv_on_state_confirmed,
114 &inv_on_state_disconnected,
Benny Prijono268ca612006-02-07 12:34:11 +0000115};
116
117static struct mod_inv
118{
119 pjsip_module mod;
120 pjsip_endpoint *endpt;
121 pjsip_inv_callback cb;
Benny Prijono268ca612006-02-07 12:34:11 +0000122} mod_inv =
123{
124 {
Benny Prijono2f8992b2006-02-25 21:16:36 +0000125 NULL, NULL, /* prev, next. */
126 { "mod-invite", 10 }, /* Name. */
127 -1, /* Id */
128 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
129 &mod_inv_load, /* load() */
130 NULL, /* start() */
131 NULL, /* stop() */
132 &mod_inv_unload, /* unload() */
133 &mod_inv_on_rx_request, /* on_rx_request() */
134 &mod_inv_on_rx_response, /* on_rx_response() */
135 NULL, /* on_tx_request. */
136 NULL, /* on_tx_response() */
137 &mod_inv_on_tsx_state, /* on_tsx_state() */
Benny Prijono268ca612006-02-07 12:34:11 +0000138 }
139};
140
141
Benny Prijonoa66c7152006-02-09 01:26:14 +0000142/* Invite session data to be attached to transaction. */
143struct tsx_inv_data
144{
Benny Prijono8fcb4332008-10-31 18:01:48 +0000145 pjsip_inv_session *inv; /* The invite session */
146 pj_bool_t sdp_done; /* SDP negotiation done for this tsx? */
147 pj_str_t done_tag; /* To tag in RX response with answer */
148 pj_bool_t done_early;/* Negotiation was done for early med? */
Benny Prijonoa66c7152006-02-09 01:26:14 +0000149};
150
Benny Prijono8ad55352006-02-08 11:16:05 +0000151/*
152 * Module load()
153 */
Benny Prijono268ca612006-02-07 12:34:11 +0000154static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
155{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000156 pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},
157 { "UPDATE", 6}};
Benny Prijono56315612006-07-18 14:39:40 +0000158 pj_str_t accepted = { "application/sdp", 15 };
Benny Prijono268ca612006-02-07 12:34:11 +0000159
Benny Prijono1f7767b2007-10-03 18:28:49 +0000160 /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */
Benny Prijono268ca612006-02-07 12:34:11 +0000161 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
162 PJ_ARRAY_SIZE(allowed), allowed);
163
Benny Prijono56315612006-07-18 14:39:40 +0000164 /* Register "application/sdp" in Accept header */
165 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
166 1, &accepted);
167
Benny Prijono268ca612006-02-07 12:34:11 +0000168 return PJ_SUCCESS;
169}
170
Benny Prijono8ad55352006-02-08 11:16:05 +0000171/*
172 * Module unload()
173 */
Benny Prijono268ca612006-02-07 12:34:11 +0000174static pj_status_t mod_inv_unload(void)
175{
176 /* Should remove capability here */
177 return PJ_SUCCESS;
178}
179
Benny Prijono8ad55352006-02-08 11:16:05 +0000180/*
Benny Prijono38998232006-02-08 22:44:25 +0000181 * Set session state.
182 */
183void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
184 pjsip_event *e)
185{
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000186 pjsip_inv_state prev_state = inv->state;
Benny Prijono7d910092007-06-20 04:19:46 +0000187 pj_status_t status;
188
189
190 /* If state is confirmed, check that SDP negotiation is done,
191 * otherwise disconnect the session.
192 */
193 if (state == PJSIP_INV_STATE_CONFIRMED) {
194 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
195 pjsip_tx_data *bye;
196
197 PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
198 "session"));
199
200 status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
201 NULL, &bye);
202 if (status == PJ_SUCCESS && bye)
203 status = pjsip_inv_send_msg(inv, bye);
204
205 return;
206 }
207 }
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000208
209 /* Set state. */
Benny Prijono38998232006-02-08 22:44:25 +0000210 inv->state = state;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000211
212 /* If state is DISCONNECTED, cause code MUST have been set. */
213 pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
214 inv->cause != 0);
215
216 /* Call on_state_changed() callback. */
217 if (mod_inv.cb.on_state_changed && inv->notify)
Benny Prijono38998232006-02-08 22:44:25 +0000218 (*mod_inv.cb.on_state_changed)(inv, e);
219
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000220 /* Only decrement when previous state is not already DISCONNECTED */
221 if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
222 prev_state != PJSIP_INV_STATE_DISCONNECTED)
223 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000224 if (inv->last_ack) {
225 pjsip_tx_data_dec_ref(inv->last_ack);
226 inv->last_ack = NULL;
227 }
Benny Prijono5e51a4e2008-11-27 00:06:46 +0000228 if (inv->invite_req) {
229 pjsip_tx_data_dec_ref(inv->invite_req);
230 inv->invite_req = NULL;
231 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000232 pjsip_100rel_end_session(inv);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000233 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000234 }
Benny Prijono38998232006-02-08 22:44:25 +0000235}
236
237
238/*
Benny Prijono0b6340c2006-06-13 22:21:23 +0000239 * Set cause code.
240 */
241void inv_set_cause(pjsip_inv_session *inv, int cause_code,
242 const pj_str_t *cause_text)
243{
244 if (cause_code > inv->cause) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000245 inv->cause = (pjsip_status_code) cause_code;
Benny Prijono0b6340c2006-06-13 22:21:23 +0000246 if (cause_text)
247 pj_strdup(inv->pool, &inv->cause_text, cause_text);
248 else if (cause_code/100 == 2)
249 inv->cause_text = pj_str("Normal call clearing");
250 else
251 inv->cause_text = *pjsip_get_status_text(cause_code);
252 }
253}
254
255
Benny Prijono1f7767b2007-10-03 18:28:49 +0000256/*
257 * Check if outgoing request needs to have SDP answer.
258 * This applies for both ACK and PRACK requests.
259 */
Benny Prijono9569a0b2007-10-04 15:35:26 +0000260static const pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv,
261 pjsip_transaction *tsx)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000262{
263 pjmedia_sdp_neg_state neg_state;
Benny Prijono9569a0b2007-10-04 15:35:26 +0000264 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000265 pj_status_t status;
266
267 /* If SDP negotiator is ready, start negotiation. */
268
269 /* Start nego when appropriate. */
270 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
271 PJMEDIA_SDP_NEG_STATE_NULL;
272
273 if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) {
274
275 /* Nothing to do */
276
277 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
278 pjmedia_sdp_neg_has_local_answer(inv->neg) )
279 {
280 struct tsx_inv_data *tsx_inv_data;
Benny Prijonod5f9f422007-11-25 04:40:07 +0000281 struct tsx_inv_data dummy;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000282
Benny Prijonod5f9f422007-11-25 04:40:07 +0000283 /* Get invite session's transaction data.
284 * Note that tsx may be NULL, for example when application sends
285 * delayed ACK request (at this time, the original INVITE
286 * transaction may have been destroyed.
287 */
288 if (tsx) {
289 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
290 } else {
291 tsx_inv_data = &dummy;
292 pj_bzero(&dummy, sizeof(dummy));
293 dummy.inv = inv;
294 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000295
296 status = inv_negotiate_sdp(inv);
297 if (status != PJ_SUCCESS)
298 return NULL;
299
300 /* Mark this transaction has having SDP offer/answer done. */
301 tsx_inv_data->sdp_done = 1;
302
303 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
304
305 } else {
306 /* This remark is only valid for ACK.
307 PJ_LOG(4,(inv->dlg->obj_name,
308 "FYI, the SDP negotiator state (%s) is in a mess "
309 "when sending this ACK/PRACK request",
310 pjmedia_sdp_neg_state_str(neg_state)));
311 */
312 }
313
314 return sdp;
315}
316
Benny Prijono0b6340c2006-06-13 22:21:23 +0000317
318/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000319 * Send ACK for 2xx response.
320 */
Benny Prijonod5f9f422007-11-25 04:40:07 +0000321static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +0000322{
Benny Prijonod5f9f422007-11-25 04:40:07 +0000323 pjsip_rx_data *rdata;
Benny Prijono268ca612006-02-07 12:34:11 +0000324 pj_status_t status;
325
Benny Prijonod5f9f422007-11-25 04:40:07 +0000326 if (e->type == PJSIP_EVENT_TSX_STATE)
327 rdata = e->body.tsx_state.src.rdata;
328 else if (e->type == PJSIP_EVENT_RX_MSG)
329 rdata = e->body.rx_msg.rdata;
330 else {
331 pj_assert(!"Unsupported event type");
332 return PJ_EBUG;
333 }
334
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000335 PJ_LOG(5,(inv->obj_name, "Received %s, sending ACK",
336 pjsip_rx_data_get_info(rdata)));
337
Benny Prijono1f7767b2007-10-03 18:28:49 +0000338 /* Check if we have cached ACK request */
339 if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000340
Benny Prijono1f7767b2007-10-03 18:28:49 +0000341 pjsip_tx_data_add_ref(inv->last_ack);
Benny Prijonod5f9f422007-11-25 04:40:07 +0000342
343 } else if (mod_inv.cb.on_send_ack) {
344 /* If application handles ACK transmission manually, just notify the
345 * callback
346 */
347 PJ_LOG(5,(inv->obj_name, "Received %s, notifying application callback",
348 pjsip_rx_data_get_info(rdata)));
349
350 (*mod_inv.cb.on_send_ack)(inv, rdata);
351 return PJ_SUCCESS;
352
Benny Prijono1f7767b2007-10-03 18:28:49 +0000353 } else {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000354 status = pjsip_inv_create_ack(inv, rdata->msg_info.cseq->cseq,
355 &inv->last_ack);
Benny Prijono268ca612006-02-07 12:34:11 +0000356 }
357
Benny Prijono1f7767b2007-10-03 18:28:49 +0000358 /* Send ACK */
359 status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000360 if (status != PJ_SUCCESS) {
361 /* Better luck next time */
362 pj_assert(!"Unable to send ACK!");
363 return status;
364 }
365
Benny Prijonod5f9f422007-11-25 04:40:07 +0000366
Benny Prijonoe6da48a2008-09-22 14:36:00 +0000367 /* Set state to CONFIRMED (if we're not in CONFIRMED yet).
368 * But don't set it to CONFIRMED if we're already DISCONNECTED
369 * (this may have been a late 200/OK response.
370 */
371 if (inv->state < PJSIP_INV_STATE_CONFIRMED) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000372 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
373 }
374
Benny Prijono268ca612006-02-07 12:34:11 +0000375 return PJ_SUCCESS;
376}
377
Benny Prijono8ad55352006-02-08 11:16:05 +0000378/*
379 * Module on_rx_request()
380 *
381 * This callback is called for these events:
382 * - endpoint receives request which was unhandled by higher priority
383 * modules (e.g. transaction layer, dialog layer).
384 * - dialog distributes incoming request to its usages.
385 */
386static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
387{
388 pjsip_method *method;
Benny Prijono38998232006-02-08 22:44:25 +0000389 pjsip_dialog *dlg;
390 pjsip_inv_session *inv;
Benny Prijono8ad55352006-02-08 11:16:05 +0000391
392 /* Only wants to receive request from a dialog. */
Benny Prijono38998232006-02-08 22:44:25 +0000393 dlg = pjsip_rdata_get_dlg(rdata);
394 if (dlg == NULL)
Benny Prijono8ad55352006-02-08 11:16:05 +0000395 return PJ_FALSE;
396
Benny Prijonoa1e69682007-05-11 15:14:34 +0000397 inv = (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono38998232006-02-08 22:44:25 +0000398
Benny Prijono8ad55352006-02-08 11:16:05 +0000399 /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
400 * If we need to send response, it will be sent in the state
401 * handlers.
402 */
403 method = &rdata->msg_info.msg->line.req.method;
404
Benny Prijono70127222006-07-02 14:53:05 +0000405 if (method->id == PJSIP_INVITE_METHOD) {
406 return PJ_TRUE;
407 }
408
409 /* BYE and CANCEL must have existing invite session */
410 if (method->id == PJSIP_BYE_METHOD ||
411 method->id == PJSIP_CANCEL_METHOD)
Benny Prijono8ad55352006-02-08 11:16:05 +0000412 {
Benny Prijono70127222006-07-02 14:53:05 +0000413 if (inv == NULL)
414 return PJ_FALSE;
415
Benny Prijono8ad55352006-02-08 11:16:05 +0000416 return PJ_TRUE;
417 }
418
Benny Prijono38998232006-02-08 22:44:25 +0000419 /* On receipt ACK request, when state is CONNECTING,
420 * move state to CONFIRMED.
421 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000422 if (method->id == PJSIP_ACK_METHOD && inv) {
Benny Prijono38998232006-02-08 22:44:25 +0000423
Benny Prijonof521eb02006-08-06 23:07:25 +0000424 /* Ignore ACK if pending INVITE transaction has not finished. */
425 if (inv->invite_tsx &&
426 inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
427 {
428 return PJ_TRUE;
429 }
430
Benny Prijono5eff0432006-02-09 14:14:21 +0000431 /* Terminate INVITE transaction, if it's still present. */
432 if (inv->invite_tsx &&
433 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
434 {
Benny Prijono7d910092007-06-20 04:19:46 +0000435 /* Before we terminate INVITE transaction, process the SDP
Benny Prijono59e9e952008-09-21 22:55:43 +0000436 * in the ACK request, if any.
437 * Only do this when invite state is not already disconnected
438 * (http://trac.pjsip.org/repos/ticket/640).
Benny Prijono7d910092007-06-20 04:19:46 +0000439 */
Benny Prijono59e9e952008-09-21 22:55:43 +0000440 if (inv->state < PJSIP_INV_STATE_DISCONNECTED) {
441 inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
442 }
Benny Prijono7d910092007-06-20 04:19:46 +0000443
444 /* Now we can terminate the INVITE transaction */
Benny Prijonof521eb02006-08-06 23:07:25 +0000445 pj_assert(inv->invite_tsx->status_code >= 200);
Benny Prijono5eff0432006-02-09 14:14:21 +0000446 pjsip_tsx_terminate(inv->invite_tsx,
447 inv->invite_tsx->status_code);
448 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000449 if (inv->last_answer) {
450 pjsip_tx_data_dec_ref(inv->last_answer);
451 inv->last_answer = NULL;
452 }
Benny Prijono5eff0432006-02-09 14:14:21 +0000453 }
454
Benny Prijono32ac8fe2006-03-02 21:16:55 +0000455 /* On receipt of ACK, only set state to confirmed when state
456 * is CONNECTING (e.g. we don't want to set the state to confirmed
457 * when we receive ACK retransmission after sending non-2xx!)
458 */
459 if (inv->state == PJSIP_INV_STATE_CONNECTING) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000460 pjsip_event event;
461
462 PJSIP_EVENT_INIT_RX_MSG(event, rdata);
463 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
464 }
Benny Prijono38998232006-02-08 22:44:25 +0000465 }
466
Benny Prijono8ad55352006-02-08 11:16:05 +0000467 return PJ_FALSE;
468}
469
470/*
471 * Module on_rx_response().
472 *
473 * This callback is called for these events:
474 * - dialog distributes incoming 2xx response to INVITE (outside
475 * transaction) to its usages.
476 * - endpoint distributes strayed responses.
477 */
Benny Prijono268ca612006-02-07 12:34:11 +0000478static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
479{
480 pjsip_dialog *dlg;
481 pjsip_inv_session *inv;
482 pjsip_msg *msg = rdata->msg_info.msg;
483
484 dlg = pjsip_rdata_get_dlg(rdata);
485
486 /* Ignore responses outside dialog */
487 if (dlg == NULL)
488 return PJ_FALSE;
489
490 /* Ignore responses not belonging to invite session */
491 inv = pjsip_dlg_get_inv_session(dlg);
492 if (inv == NULL)
493 return PJ_FALSE;
494
495 /* This MAY be retransmission of 2xx response to INVITE.
496 * If it is, we need to send ACK.
497 */
498 if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
Benny Prijono26ff9062006-02-21 23:47:00 +0000499 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
500 inv->invite_tsx == NULL)
501 {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000502 pjsip_event e;
Benny Prijono268ca612006-02-07 12:34:11 +0000503
Benny Prijonod5f9f422007-11-25 04:40:07 +0000504 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
505 inv_send_ack(inv, &e);
Benny Prijono268ca612006-02-07 12:34:11 +0000506 return PJ_TRUE;
507
508 }
509
510 /* No other processing needs to be done here. */
511 return PJ_FALSE;
512}
513
Benny Prijono8ad55352006-02-08 11:16:05 +0000514/*
515 * Module on_tsx_state()
516 *
517 * This callback is called by dialog framework for all transactions
518 * inside the dialog for all its dialog usages.
519 */
Benny Prijono268ca612006-02-07 12:34:11 +0000520static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
521{
522 pjsip_dialog *dlg;
523 pjsip_inv_session *inv;
524
525 dlg = pjsip_tsx_get_dlg(tsx);
526 if (dlg == NULL)
527 return;
528
529 inv = pjsip_dlg_get_inv_session(dlg);
530 if (inv == NULL)
531 return;
532
533 /* Call state handler for the invite session. */
534 (*inv_state_handler[inv->state])(inv, e);
535
536 /* Call on_tsx_state */
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000537 if (mod_inv.cb.on_tsx_state_changed && inv->notify)
Benny Prijono268ca612006-02-07 12:34:11 +0000538 (*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
539
Benny Prijono46249942007-02-19 22:23:14 +0000540 /* Clear invite transaction when tsx is confirmed.
541 * Previously we set invite_tsx to NULL only when transaction has
542 * terminated, but this didn't work when ACK has the same Via branch
543 * value as the INVITE (see http://www.pjsip.org/trac/ticket/113)
544 */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000545 if (tsx->state>=PJSIP_TSX_STATE_CONFIRMED && tsx == inv->invite_tsx) {
Benny Prijono46249942007-02-19 22:23:14 +0000546 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000547 if (inv->last_answer) {
548 pjsip_tx_data_dec_ref(inv->last_answer);
549 inv->last_answer = NULL;
550 }
551 }
Benny Prijono268ca612006-02-07 12:34:11 +0000552}
553
Benny Prijono8ad55352006-02-08 11:16:05 +0000554
555/*
556 * Initialize the invite module.
557 */
Benny Prijono268ca612006-02-07 12:34:11 +0000558PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
Benny Prijono268ca612006-02-07 12:34:11 +0000559 const pjsip_inv_callback *cb)
560{
561 pj_status_t status;
562
563 /* Check arguments. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000564 PJ_ASSERT_RETURN(endpt && cb, PJ_EINVAL);
Benny Prijono268ca612006-02-07 12:34:11 +0000565
566 /* Some callbacks are mandatory */
567 PJ_ASSERT_RETURN(cb->on_state_changed && cb->on_new_session, PJ_EINVAL);
568
569 /* Check if module already registered. */
570 PJ_ASSERT_RETURN(mod_inv.mod.id == -1, PJ_EINVALIDOP);
571
572 /* Copy param. */
573 pj_memcpy(&mod_inv.cb, cb, sizeof(pjsip_inv_callback));
574
575 mod_inv.endpt = endpt;
Benny Prijono268ca612006-02-07 12:34:11 +0000576
577 /* Register the module. */
578 status = pjsip_endpt_register_module(endpt, &mod_inv.mod);
Benny Prijono053f5222006-11-11 16:16:04 +0000579 if (status != PJ_SUCCESS)
580 return status;
Benny Prijono268ca612006-02-07 12:34:11 +0000581
Benny Prijono053f5222006-11-11 16:16:04 +0000582 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +0000583}
584
Benny Prijono8ad55352006-02-08 11:16:05 +0000585/*
586 * Get the instance of invite module.
587 */
Benny Prijono268ca612006-02-07 12:34:11 +0000588PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
589{
590 return &mod_inv.mod;
591}
592
593
Benny Prijono632ce712006-02-09 14:01:40 +0000594
Benny Prijono8ad55352006-02-08 11:16:05 +0000595/*
596 * Return the invite session for the specified dialog.
597 */
Benny Prijono268ca612006-02-07 12:34:11 +0000598PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
599{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000600 return (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono268ca612006-02-07 12:34:11 +0000601}
602
Benny Prijono8ad55352006-02-08 11:16:05 +0000603
Benny Prijono268ca612006-02-07 12:34:11 +0000604/*
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000605 * Get INVITE state name.
606 */
607PJ_DEF(const char *) pjsip_inv_state_name(pjsip_inv_state state)
608{
609 PJ_ASSERT_RETURN(state >= PJSIP_INV_STATE_NULL &&
610 state <= PJSIP_INV_STATE_DISCONNECTED,
611 "??");
612
613 return inv_state_names[state];
614}
615
616/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000617 * Create UAC invite session.
Benny Prijono268ca612006-02-07 12:34:11 +0000618 */
619PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
620 const pjmedia_sdp_session *local_sdp,
621 unsigned options,
622 pjsip_inv_session **p_inv)
623{
624 pjsip_inv_session *inv;
625 pj_status_t status;
626
627 /* Verify arguments. */
628 PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
629
Benny Prijono8eae8382006-08-10 21:44:26 +0000630 /* Must lock dialog first */
631 pjsip_dlg_inc_lock(dlg);
632
Benny Prijono268ca612006-02-07 12:34:11 +0000633 /* Normalize options */
634 if (options & PJSIP_INV_REQUIRE_100REL)
635 options |= PJSIP_INV_SUPPORT_100REL;
636
637 if (options & PJSIP_INV_REQUIRE_TIMER)
638 options |= PJSIP_INV_SUPPORT_TIMER;
639
640 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000641 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +0000642 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000643
644 inv->pool = dlg->pool;
645 inv->role = PJSIP_ROLE_UAC;
646 inv->state = PJSIP_INV_STATE_NULL;
647 inv->dlg = dlg;
648 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000649 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000650 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +0000651
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000652 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +0000653 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000654
Benny Prijono268ca612006-02-07 12:34:11 +0000655 /* Create negotiator if local_sdp is specified. */
656 if (local_sdp) {
657 status = pjmedia_sdp_neg_create_w_local_offer(dlg->pool, local_sdp,
658 &inv->neg);
Benny Prijono8eae8382006-08-10 21:44:26 +0000659 if (status != PJ_SUCCESS) {
660 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000661 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000662 }
Benny Prijono268ca612006-02-07 12:34:11 +0000663 }
664
665 /* Register invite as dialog usage. */
666 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +0000667 if (status != PJ_SUCCESS) {
668 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000669 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000670 }
Benny Prijono268ca612006-02-07 12:34:11 +0000671
672 /* Increment dialog session */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000673 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +0000674
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000675 /* Create 100rel handler */
676 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000677
Benny Prijono268ca612006-02-07 12:34:11 +0000678 /* Done */
679 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000680
Benny Prijono8eae8382006-08-10 21:44:26 +0000681 pjsip_dlg_dec_lock(dlg);
682
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000683 PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
684 dlg->obj_name));
685
Benny Prijono268ca612006-02-07 12:34:11 +0000686 return PJ_SUCCESS;
687}
688
689/*
690 * Verify incoming INVITE request.
691 */
Benny Prijono87a90212008-01-23 20:29:30 +0000692PJ_DEF(pj_status_t) pjsip_inv_verify_request2(pjsip_rx_data *rdata,
693 unsigned *options,
694 const pjmedia_sdp_session *r_sdp,
695 const pjmedia_sdp_session *l_sdp,
696 pjsip_dialog *dlg,
697 pjsip_endpoint *endpt,
698 pjsip_tx_data **p_tdata)
Benny Prijono268ca612006-02-07 12:34:11 +0000699{
700 pjsip_msg *msg;
701 pjsip_allow_hdr *allow;
702 pjsip_supported_hdr *sup_hdr;
703 pjsip_require_hdr *req_hdr;
704 int code = 200;
705 unsigned rem_option = 0;
706 pj_status_t status = PJ_SUCCESS;
707 pjsip_hdr res_hdr_list;
708
709 /* Init return arguments. */
710 if (p_tdata) *p_tdata = NULL;
711
712 /* Verify arguments. */
713 PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);
714
715 /* Normalize options */
716 if (*options & PJSIP_INV_REQUIRE_100REL)
717 *options |= PJSIP_INV_SUPPORT_100REL;
718
719 if (*options & PJSIP_INV_REQUIRE_TIMER)
720 *options |= PJSIP_INV_SUPPORT_TIMER;
721
722 /* Get the message in rdata */
723 msg = rdata->msg_info.msg;
724
725 /* Must be INVITE request. */
726 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
727 msg->line.req.method.id == PJSIP_INVITE_METHOD,
728 PJ_EINVAL);
729
730 /* If tdata is specified, then either dlg or endpt must be specified */
731 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
732
733 /* Get the endpoint */
734 endpt = endpt ? endpt : dlg->endpt;
735
736 /* Init response header list */
737 pj_list_init(&res_hdr_list);
738
Benny Prijono87a90212008-01-23 20:29:30 +0000739 /* Check the request body, see if it's something that we support,
740 * only when the body hasn't been parsed before.
Benny Prijono268ca612006-02-07 12:34:11 +0000741 */
Benny Prijono87a90212008-01-23 20:29:30 +0000742 if (r_sdp==NULL && msg->body) {
Benny Prijono268ca612006-02-07 12:34:11 +0000743 pjsip_msg_body *body = msg->body;
744 pj_str_t str_application = {"application", 11};
745 pj_str_t str_sdp = { "sdp", 3 };
746 pjmedia_sdp_session *sdp;
747
748 /* Check content type. */
749 if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||
750 pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)
751 {
752 /* Not "application/sdp" */
753 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
754 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
755
756 if (p_tdata) {
757 /* Add Accept header to response */
758 pjsip_accept_hdr *acc;
759
760 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
761 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
762 acc->values[acc->count++] = pj_str("application/sdp");
763 pj_list_push_back(&res_hdr_list, acc);
764 }
765
766 goto on_return;
767 }
768
769 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000770 status = pjmedia_sdp_parse(rdata->tp_info.pool,
771 (char*)body->data, body->len, &sdp);
Benny Prijono268ca612006-02-07 12:34:11 +0000772 if (status == PJ_SUCCESS)
773 status = pjmedia_sdp_validate(sdp);
774
775 if (status != PJ_SUCCESS) {
776 /* Unparseable or invalid SDP */
777 code = PJSIP_SC_BAD_REQUEST;
778
779 if (p_tdata) {
780 /* Add Warning header. */
781 pjsip_warning_hdr *w;
782
783 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
784 pjsip_endpt_name(endpt),
785 status);
786 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
787
788 pj_list_push_back(&res_hdr_list, w);
789 }
790
791 goto on_return;
792 }
793
Benny Prijono87a90212008-01-23 20:29:30 +0000794 r_sdp = sdp;
795 }
796
797 if (r_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +0000798 /* Negotiate with local SDP */
799 if (l_sdp) {
800 pjmedia_sdp_neg *neg;
801
802 /* Local SDP must be valid! */
803 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
804 status);
805
806 /* Create SDP negotiator */
807 status = pjmedia_sdp_neg_create_w_remote_offer(
Benny Prijono87a90212008-01-23 20:29:30 +0000808 rdata->tp_info.pool, l_sdp, r_sdp, &neg);
Benny Prijono268ca612006-02-07 12:34:11 +0000809 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
810
811 /* Negotiate SDP */
812 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
813 if (status != PJ_SUCCESS) {
814
815 /* Incompatible media */
816 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000817
818 if (p_tdata) {
819 pjsip_accept_hdr *acc;
820 pjsip_warning_hdr *w;
821
822 /* Add Warning header. */
823 w = pjsip_warning_hdr_create_from_status(
824 rdata->tp_info.pool,
825 pjsip_endpt_name(endpt), status);
826 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
827
828 pj_list_push_back(&res_hdr_list, w);
829
830 /* Add Accept header to response */
831 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
832 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
833 acc->values[acc->count++] = pj_str("application/sdp");
834 pj_list_push_back(&res_hdr_list, acc);
835
836 }
837
838 goto on_return;
839 }
840 }
841 }
842
843 /* Check supported methods, see if peer supports UPDATE.
844 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
845 * implicitly by sending this INVITE.
846 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000847 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000848 if (allow) {
849 unsigned i;
850 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
851
852 for (i=0; i<allow->count; ++i) {
853 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
854 break;
855 }
856
857 if (i != allow->count) {
858 /* UPDATE is present in Allow */
859 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
860 }
861
862 }
863
864 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000865 sup_hdr = (pjsip_supported_hdr*)
866 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000867 if (sup_hdr) {
868 unsigned i;
869 pj_str_t STR_100REL = { "100rel", 6};
870 pj_str_t STR_TIMER = { "timer", 5 };
871
872 for (i=0; i<sup_hdr->count; ++i) {
873 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
874 rem_option |= PJSIP_INV_SUPPORT_100REL;
875 else if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
876 rem_option |= PJSIP_INV_SUPPORT_TIMER;
877 }
878 }
879
880 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000881 req_hdr = (pjsip_require_hdr*)
882 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000883 if (req_hdr) {
884 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +0000885 const pj_str_t STR_100REL = { "100rel", 6};
886 const pj_str_t STR_TIMER = { "timer", 5 };
887 const pj_str_t STR_REPLACES = { "replaces", 8 };
Benny Prijono268ca612006-02-07 12:34:11 +0000888 unsigned unsupp_cnt = 0;
889 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
890
891 for (i=0; i<req_hdr->count; ++i) {
892 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
893 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
894 {
895 rem_option |= PJSIP_INV_REQUIRE_100REL;
896
897 } else if ((*options && PJSIP_INV_SUPPORT_TIMER) &&
898 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
899 {
900 rem_option |= PJSIP_INV_REQUIRE_TIMER;
901
Benny Prijono053f5222006-11-11 16:16:04 +0000902 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
903 pj_bool_t supp;
904
905 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
906 NULL, &STR_REPLACES);
907 if (!supp)
908 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
909
Benny Prijono268ca612006-02-07 12:34:11 +0000910 } else {
911 /* Unknown/unsupported extension tag! */
912 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
913 }
914 }
915
916 /* Check if there are required tags that we don't support */
917 if (unsupp_cnt) {
918
919 code = PJSIP_SC_BAD_EXTENSION;
920 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
921
922 if (p_tdata) {
923 pjsip_unsupported_hdr *unsupp_hdr;
924 const pjsip_hdr *h;
925
926 /* Add Unsupported header. */
927 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
928 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
929
930 unsupp_hdr->count = unsupp_cnt;
931 for (i=0; i<unsupp_cnt; ++i)
932 unsupp_hdr->values[i] = unsupp_tags[i];
933
934 pj_list_push_back(&res_hdr_list, unsupp_hdr);
935
936 /* Add Supported header. */
937 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
938 NULL);
939 pj_assert(h);
940 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000941 sup_hdr = (pjsip_supported_hdr*)
942 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000943 pj_list_push_back(&res_hdr_list, sup_hdr);
944 }
945 }
946
947 goto on_return;
948 }
949 }
950
951 /* Check if there are local requirements that are not supported
952 * by peer.
953 */
954 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
955 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
956 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
957 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
958 {
959 code = PJSIP_SC_EXTENSION_REQUIRED;
960 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
961
962 if (p_tdata) {
963 const pjsip_hdr *h;
964
965 /* Add Require header. */
966 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
967 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
968
969 if (*options & PJSIP_INV_REQUIRE_100REL)
970 req_hdr->values[req_hdr->count++] = pj_str("100rel");
971
972 if (*options & PJSIP_INV_REQUIRE_TIMER)
973 req_hdr->values[req_hdr->count++] = pj_str("timer");
974
975 pj_list_push_back(&res_hdr_list, req_hdr);
976
977 /* Add Supported header. */
978 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
979 NULL);
980 pj_assert(h);
981 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000982 sup_hdr = (pjsip_supported_hdr*)
983 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000984 pj_list_push_back(&res_hdr_list, sup_hdr);
985 }
986
987 }
988
989 goto on_return;
990 }
991
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000992 /* If remote Require something that we support, make us Require
993 * that feature too.
994 */
995 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
996 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
997 *options |= PJSIP_INV_REQUIRE_100REL;
998 }
999 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1000 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1001 *options |= PJSIP_INV_REQUIRE_TIMER;
1002 }
1003
Benny Prijono268ca612006-02-07 12:34:11 +00001004on_return:
1005
1006 /* Create response if necessary */
1007 if (code != 200 && p_tdata) {
1008 pjsip_tx_data *tdata;
1009 const pjsip_hdr *h;
1010
1011 if (dlg) {
1012 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1013 &tdata);
1014 } else {
1015 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1016 &tdata);
1017 }
1018
1019 if (status != PJ_SUCCESS)
1020 return status;
1021
1022 /* Add response headers. */
1023 h = res_hdr_list.next;
1024 while (h != &res_hdr_list) {
1025 pjsip_hdr *cloned;
1026
Benny Prijonoa1e69682007-05-11 15:14:34 +00001027 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001028 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1029
1030 pjsip_msg_add_hdr(tdata->msg, cloned);
1031
1032 h = h->next;
1033 }
1034
1035 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001036
1037 /* Can not return PJ_SUCCESS when response message is produced.
1038 * Ref: PROTOS test ~#2490
1039 */
1040 if (status == PJ_SUCCESS)
1041 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1042
Benny Prijono268ca612006-02-07 12:34:11 +00001043 }
1044
1045 return status;
1046}
1047
Benny Prijono87a90212008-01-23 20:29:30 +00001048
1049/*
1050 * Verify incoming INVITE request.
1051 */
1052PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1053 unsigned *options,
1054 const pjmedia_sdp_session *l_sdp,
1055 pjsip_dialog *dlg,
1056 pjsip_endpoint *endpt,
1057 pjsip_tx_data **p_tdata)
1058{
1059 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1060 endpt, p_tdata);
1061}
1062
Benny Prijono268ca612006-02-07 12:34:11 +00001063/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001064 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001065 */
1066PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1067 pjsip_rx_data *rdata,
1068 const pjmedia_sdp_session *local_sdp,
1069 unsigned options,
1070 pjsip_inv_session **p_inv)
1071{
1072 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001073 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001074 pjsip_msg *msg;
1075 pjmedia_sdp_session *rem_sdp = NULL;
1076 pj_status_t status;
1077
1078 /* Verify arguments. */
1079 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1080
1081 /* Dialog MUST have been initialised. */
1082 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1083
1084 msg = rdata->msg_info.msg;
1085
1086 /* rdata MUST contain INVITE request */
1087 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1088 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1089 PJ_EINVALIDOP);
1090
Benny Prijono8eae8382006-08-10 21:44:26 +00001091 /* Lock dialog */
1092 pjsip_dlg_inc_lock(dlg);
1093
Benny Prijono268ca612006-02-07 12:34:11 +00001094 /* Normalize options */
1095 if (options & PJSIP_INV_REQUIRE_100REL)
1096 options |= PJSIP_INV_SUPPORT_100REL;
1097
1098 if (options & PJSIP_INV_REQUIRE_TIMER)
1099 options |= PJSIP_INV_SUPPORT_TIMER;
1100
1101 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001102 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001103 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001104
1105 inv->pool = dlg->pool;
1106 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001107 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001108 inv->dlg = dlg;
1109 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001110 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001111 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001112
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001113 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001114 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001115
Benny Prijono268ca612006-02-07 12:34:11 +00001116 /* Parse SDP in message body, if present. */
1117 if (msg->body) {
1118 pjsip_msg_body *body = msg->body;
1119
1120 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001121 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001122 &rem_sdp);
1123 if (status == PJ_SUCCESS)
1124 status = pjmedia_sdp_validate(rem_sdp);
1125
Benny Prijono8eae8382006-08-10 21:44:26 +00001126 if (status != PJ_SUCCESS) {
1127 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001128 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001129 }
Benny Prijono268ca612006-02-07 12:34:11 +00001130 }
1131
1132 /* Create negotiator. */
1133 if (rem_sdp) {
1134 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp,
1135 rem_sdp, &inv->neg);
1136
1137 } else if (local_sdp) {
1138 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1139 &inv->neg);
1140 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001141 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001142 }
1143
Benny Prijono8eae8382006-08-10 21:44:26 +00001144 if (status != PJ_SUCCESS) {
1145 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001146 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001147 }
Benny Prijono268ca612006-02-07 12:34:11 +00001148
1149 /* Register invite as dialog usage. */
1150 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001151 if (status != PJ_SUCCESS) {
1152 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001153 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001154 }
Benny Prijono268ca612006-02-07 12:34:11 +00001155
1156 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001157 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001158
1159 /* Save the invite transaction. */
1160 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001161
1162 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001163 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001164 tsx_inv_data->inv = inv;
1165 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001166
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001167 /* Create 100rel handler */
1168 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1169 pjsip_100rel_attach(inv);
1170 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001171
Benny Prijono268ca612006-02-07 12:34:11 +00001172 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001173 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001174 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001175
1176 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1177 dlg->obj_name));
1178
Benny Prijono268ca612006-02-07 12:34:11 +00001179 return PJ_SUCCESS;
1180}
1181
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001182/*
1183 * Forcefully terminate the session.
1184 */
1185PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1186 int st_code,
1187 pj_bool_t notify)
1188{
1189 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1190
1191 /* Lock dialog. */
1192 pjsip_dlg_inc_lock(inv->dlg);
1193
1194 /* Set callback notify flag. */
1195 inv->notify = notify;
1196
1197 /* If there's pending transaction, terminate the transaction.
1198 * This may subsequently set the INVITE session state to
1199 * disconnected.
1200 */
1201 if (inv->invite_tsx &&
1202 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1203 {
1204 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1205
1206 }
1207
1208 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001209 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001210
1211 /* Forcefully terminate the session if state is not DISCONNECTED */
1212 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1213 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1214 }
1215
1216 /* Done.
1217 * The dec_lock() below will actually destroys the dialog if it
1218 * has no other session.
1219 */
1220 pjsip_dlg_dec_lock(inv->dlg);
1221
1222 return PJ_SUCCESS;
1223}
1224
1225
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001226/*
1227 * Restart UAC session, possibly because app or us wants to re-send the
1228 * INVITE request due to 401/407 challenge or 3xx response.
1229 */
1230PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1231 pj_bool_t new_offer)
1232{
1233 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1234
1235 inv->state = PJSIP_INV_STATE_NULL;
1236 inv->invite_tsx = NULL;
1237 if (inv->last_answer) {
1238 pjsip_tx_data_dec_ref(inv->last_answer);
1239 inv->last_answer = NULL;
1240 }
1241
1242 if (new_offer && inv->neg) {
1243 pjmedia_sdp_neg_state neg_state;
1244
1245 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1246 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1247 pjmedia_sdp_neg_cancel_offer(inv->neg);
1248 }
1249 }
1250
1251 return PJ_SUCCESS;
1252}
1253
1254
Benny Prijono268ca612006-02-07 12:34:11 +00001255static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1256{
1257 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001258 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001259}
1260
1261static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1262{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001263 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001264}
1265
Benny Prijono56315612006-07-18 14:39:40 +00001266
1267PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1268 pjmedia_sdp_session *sdp,
1269 pjsip_msg_body **p_body)
1270{
1271 const pj_str_t STR_APPLICATION = { "application", 11};
1272 const pj_str_t STR_SDP = { "sdp", 3 };
1273 pjsip_msg_body *body;
1274
Benny Prijonoa1e69682007-05-11 15:14:34 +00001275 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001276 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1277
1278 body->content_type.type = STR_APPLICATION;
1279 body->content_type.subtype = STR_SDP;
1280 body->data = sdp;
1281 body->len = 0;
1282 body->clone_data = &clone_sdp;
1283 body->print_body = &print_sdp;
1284
1285 *p_body = body;
1286
1287 return PJ_SUCCESS;
1288}
1289
Benny Prijono268ca612006-02-07 12:34:11 +00001290static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1291 const pjmedia_sdp_session *c_sdp)
1292{
1293 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001294 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001295
Benny Prijono56315612006-07-18 14:39:40 +00001296 status = pjsip_create_sdp_body(pool,
1297 pjmedia_sdp_session_clone(pool, c_sdp),
1298 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001299
Benny Prijono56315612006-07-18 14:39:40 +00001300 if (status != PJ_SUCCESS)
1301 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001302
1303 return body;
1304}
1305
1306/*
1307 * Create initial INVITE request.
1308 */
1309PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1310 pjsip_tx_data **p_tdata )
1311{
1312 pjsip_tx_data *tdata;
1313 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001314 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001315 pj_status_t status;
1316
1317 /* Verify arguments. */
1318 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1319
Benny Prijono26ff9062006-02-21 23:47:00 +00001320 /* State MUST be NULL or CONFIRMED. */
1321 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1322 inv->state == PJSIP_INV_STATE_CONFIRMED,
1323 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001324
Benny Prijono64f851e2006-02-23 13:49:28 +00001325 /* Lock dialog. */
1326 pjsip_dlg_inc_lock(inv->dlg);
1327
Benny Prijono268ca612006-02-07 12:34:11 +00001328 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001329 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001330 &tdata);
1331 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001332 goto on_return;
1333
Benny Prijono268ca612006-02-07 12:34:11 +00001334
Benny Prijono26ff9062006-02-21 23:47:00 +00001335 /* If this is the first INVITE, then copy the headers from inv_hdr.
1336 * These are the headers parsed from the request URI when the
1337 * dialog was created.
1338 */
1339 if (inv->state == PJSIP_INV_STATE_NULL) {
1340 hdr = inv->dlg->inv_hdr.next;
1341
1342 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001343 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001344 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1345 hdr = hdr->next;
1346 }
1347 }
1348
1349 /* See if we have SDP to send. */
1350 if (inv->neg) {
1351 pjmedia_sdp_neg_state neg_state;
1352
1353 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1354
1355 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1356 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1357 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1358
1359
1360 } else {
1361 has_sdp = PJ_FALSE;
1362 }
1363
Benny Prijono268ca612006-02-07 12:34:11 +00001364 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001365 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001366 const pjmedia_sdp_session *offer;
1367
1368 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
1369 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001370 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001371
1372 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1373 }
1374
1375 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001376 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001377 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1378 if (hdr) {
1379 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1380 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1381 }
Benny Prijono268ca612006-02-07 12:34:11 +00001382 }
1383
1384 /* Add Supported header */
1385 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1386 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001387 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001388 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1389 }
1390
1391 /* Add Require header. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001392 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1393 const pj_str_t HREQ = { "Require", 7 };
1394 const pj_str_t tag_100rel = { "100rel", 6 };
1395 pjsip_generic_string_hdr *hreq;
1396
1397 hreq = pjsip_generic_string_hdr_create(tdata->pool, &HREQ,
1398 &tag_100rel);
1399 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
1400 }
Benny Prijono268ca612006-02-07 12:34:11 +00001401
1402 /* Done. */
1403 *p_tdata = tdata;
1404
Benny Prijono64f851e2006-02-23 13:49:28 +00001405
1406on_return:
1407 pjsip_dlg_dec_lock(inv->dlg);
1408 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001409}
1410
1411
1412/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001413 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001414 */
1415static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1416{
1417 pj_status_t status;
1418
1419 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1420 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1421 PJMEDIA_SDPNEG_EINSTATE);
1422
1423 status = pjmedia_sdp_neg_negotiate(inv->pool, inv->neg, 0);
1424
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001425 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1426
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001427 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001428 (*mod_inv.cb.on_media_update)(inv, status);
1429
1430 return status;
1431}
1432
1433/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001434 * Check in incoming message for SDP offer/answer.
1435 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001436static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1437 pjsip_transaction *tsx,
1438 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001439{
1440 struct tsx_inv_data *tsx_inv_data;
1441 static const pj_str_t str_application = { "application", 11 };
1442 static const pj_str_t str_sdp = { "sdp", 3 };
1443 pj_status_t status;
1444 pjsip_msg *msg;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001445 pjmedia_sdp_session *rem_sdp;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001446
1447 /* Check if SDP is present in the message. */
1448
1449 msg = rdata->msg_info.msg;
1450 if (msg->body == NULL) {
1451 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001452 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001453 }
1454
1455 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1456 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1457 {
1458 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001459 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001460 }
1461
Benny Prijono8fcb4332008-10-31 18:01:48 +00001462 /* Get/attach invite session's transaction data */
1463 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1464 if (tsx_inv_data == NULL) {
1465 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1466 tsx_inv_data->inv = inv;
1467 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1468 }
1469
1470 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1471 * EXCEPT if:
1472 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1473 * - the previous negotiation was done on an early media (18x) and
1474 * this response is a final/2xx response, and
1475 * - the 2xx response has different To tag than the 18x response
1476 * (i.e. the request has forked).
1477 *
1478 * The exception above is to add a rudimentary support for early media
1479 * forking (sample case: custom ringback). See this ticket for more
1480 * info: http://trac.pjsip.org/repos/ticket/657
1481 */
1482 if (tsx_inv_data->sdp_done) {
1483 pj_str_t res_tag;
1484
1485 res_tag = rdata->msg_info.to->tag;
1486
1487 /* Allow final response after SDP has been negotiated in early
1488 * media, IF this response is a final response with different
1489 * tag.
1490 */
1491 if (tsx->role == PJSIP_ROLE_UAC &&
1492 rdata->msg_info.msg->line.status.code/100 == 2 &&
1493 tsx_inv_data->done_early &&
1494 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1495 {
1496 const pjmedia_sdp_session *reoffer_sdp = NULL;
1497
1498 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1499 "after SDP negotiation has been done in early "
1500 "media. Renegotiating SDP.."));
1501
1502 /* Retrieve original SDP offer from INVITE request */
1503 reoffer_sdp = (const pjmedia_sdp_session*)
1504 tsx->last_tx->msg->body->data;
1505
1506 /* Feed the original offer to negotiator */
1507 status = pjmedia_sdp_neg_modify_local_offer(inv->pool, inv->neg,
1508 reoffer_sdp);
1509 if (status != PJ_SUCCESS) {
1510 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1511 "forked 2xx response (err=%d)", status));
1512 return status;
1513 }
1514
1515 } else {
1516
1517 if (rdata->msg_info.msg->body) {
1518 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1519 "body is ignored"));
1520 }
1521 return PJ_SUCCESS;
1522 }
1523 }
1524
Benny Prijonoa66c7152006-02-09 01:26:14 +00001525 /* Parse the SDP body. */
1526
Benny Prijonoa1e69682007-05-11 15:14:34 +00001527 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1528 (char*)msg->body->data,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001529 msg->body->len, &rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001530 if (status == PJ_SUCCESS)
Benny Prijono8fcb4332008-10-31 18:01:48 +00001531 status = pjmedia_sdp_validate(rem_sdp);
Benny Prijonoc1b1c0a2007-11-06 08:48:02 +00001532
Benny Prijonoa66c7152006-02-09 01:26:14 +00001533 if (status != PJ_SUCCESS) {
1534 char errmsg[PJ_ERR_MSG_SIZE];
1535 pj_strerror(status, errmsg, sizeof(errmsg));
1536 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1537 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001538 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001539 }
1540
1541 /* The SDP can be an offer or answer, depending on negotiator's state */
1542
1543 if (inv->neg == NULL ||
1544 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1545 {
1546
1547 /* This is an offer. */
1548
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001549 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1550 pjsip_rx_data_get_info(rdata)));
1551
Benny Prijonoa66c7152006-02-09 01:26:14 +00001552 if (inv->neg == NULL) {
1553 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001554 rem_sdp, &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001555 } else {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001556 status=pjmedia_sdp_neg_set_remote_offer(inv->pool, inv->neg,
1557 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001558 }
1559
1560 if (status != PJ_SUCCESS) {
1561 char errmsg[PJ_ERR_MSG_SIZE];
1562 pj_strerror(status, errmsg, sizeof(errmsg));
1563 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1564 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001565 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001566 }
1567
1568 /* Inform application about remote offer. */
1569
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001570 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001571
Benny Prijono8fcb4332008-10-31 18:01:48 +00001572 (*mod_inv.cb.on_rx_offer)(inv, rem_sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001573
1574 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001575
1576 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1577 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1578 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001579 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001580
1581 /* This is an answer.
1582 * Process and negotiate remote answer.
1583 */
1584
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001585 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1586 pjsip_rx_data_get_info(rdata)));
1587
Benny Prijono8fcb4332008-10-31 18:01:48 +00001588 status = pjmedia_sdp_neg_set_remote_answer(inv->pool, inv->neg,
1589 rem_sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001590
1591 if (status != PJ_SUCCESS) {
1592 char errmsg[PJ_ERR_MSG_SIZE];
1593 pj_strerror(status, errmsg, sizeof(errmsg));
1594 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1595 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001596 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001597 }
1598
1599 /* Negotiate SDP */
1600
1601 inv_negotiate_sdp(inv);
1602
Benny Prijono8fcb4332008-10-31 18:01:48 +00001603 /* Mark this transaction has having SDP offer/answer done, and
1604 * save the reference to the To tag
1605 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001606
1607 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001608 status_code = rdata->msg_info.msg->line.status.code;
1609 tsx_inv_data->done_early = (status_code/100==1);
1610 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1611 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001612
1613 } else {
1614
1615 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1616 pjsip_rx_data_get_info(rdata),
1617 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1618 }
1619
Benny Prijono26ff9062006-02-21 23:47:00 +00001620 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001621}
1622
1623
Benny Prijono26ff9062006-02-21 23:47:00 +00001624/*
1625 * Process INVITE answer, for both initial and subsequent re-INVITE
1626 */
1627static pj_status_t process_answer( pjsip_inv_session *inv,
1628 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001629 pjsip_tx_data *tdata,
1630 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001631{
1632 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001633 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001634
Benny Prijono64f851e2006-02-23 13:49:28 +00001635 /* If local_sdp is specified, then we MUST NOT have answered the
1636 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001637 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001638 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1639
1640 if (inv->neg == NULL) {
1641 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1642 &inv->neg);
1643 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1644 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1645 {
1646 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
1647 local_sdp);
1648 } else {
1649
1650 /* Can not specify local SDP at this state. */
1651 pj_assert(0);
1652 status = PJMEDIA_SDPNEG_EINSTATE;
1653 }
1654
1655 if (status != PJ_SUCCESS)
1656 return status;
1657
1658 }
1659
1660
1661 /* If SDP negotiator is ready, start negotiation. */
1662 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001663
1664 pjmedia_sdp_neg_state neg_state;
1665
Benny Prijono64f851e2006-02-23 13:49:28 +00001666 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001667 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1668 PJMEDIA_SDP_NEG_STATE_NULL;
1669
1670 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1671
1672 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1673
1674 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1675 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1676 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001677 struct tsx_inv_data *tsx_inv_data;
1678
1679 /* Get invite session's transaction data */
1680 tsx_inv_data = (struct tsx_inv_data*)
1681 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001682
1683 status = inv_negotiate_sdp(inv);
1684 if (status != PJ_SUCCESS)
1685 return status;
1686
Benny Prijono77998ce2007-06-20 10:03:46 +00001687 /* Mark this transaction has having SDP offer/answer done. */
1688 tsx_inv_data->sdp_done = 1;
1689
Benny Prijono26ff9062006-02-21 23:47:00 +00001690 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1691 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001692 }
1693
Benny Prijono64f851e2006-02-23 13:49:28 +00001694 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001695 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001696 *
1697 * Note note:
1698 * - When offer/answer has been completed in reliable 183, we MUST NOT
1699 * send SDP in 2xx response. So if we don't have SDP to send, clear
1700 * the SDP in the message body ONLY if 100rel is active in this
1701 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001702 */
1703 if (sdp) {
1704 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001705 } else {
1706 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1707 tdata->msg->body = NULL;
1708 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001709 }
1710
Benny Prijono26ff9062006-02-21 23:47:00 +00001711
1712 return PJ_SUCCESS;
1713}
1714
Benny Prijonoa66c7152006-02-09 01:26:14 +00001715
1716/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001717 * Create first response to INVITE
1718 */
1719PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1720 pjsip_rx_data *rdata,
1721 int st_code,
1722 const pj_str_t *st_text,
1723 const pjmedia_sdp_session *sdp,
1724 pjsip_tx_data **p_tdata)
1725{
1726 pjsip_tx_data *tdata;
1727 pj_status_t status;
1728
1729 /* Verify arguments. */
1730 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1731
1732 /* Must have INVITE transaction. */
1733 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1734
1735 pjsip_dlg_inc_lock(inv->dlg);
1736
1737 /* Create response */
1738 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1739 &tdata);
1740 if (status != PJ_SUCCESS)
1741 goto on_return;
1742
1743 /* Process SDP in answer */
1744 status = process_answer(inv, st_code, tdata, sdp);
1745 if (status != PJ_SUCCESS) {
1746 pjsip_tx_data_dec_ref(tdata);
1747 goto on_return;
1748 }
1749
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001750 /* Save this answer */
1751 inv->last_answer = tdata;
1752 pjsip_tx_data_add_ref(inv->last_answer);
1753 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1754 pjsip_tx_data_get_info(inv->last_answer)));
1755
Benny Prijono64f851e2006-02-23 13:49:28 +00001756 *p_tdata = tdata;
1757
1758on_return:
1759 pjsip_dlg_dec_lock(inv->dlg);
1760 return status;
1761}
1762
1763
1764/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001765 * Answer initial INVITE
1766 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001767 */
1768PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1769 int st_code,
1770 const pj_str_t *st_text,
1771 const pjmedia_sdp_session *local_sdp,
1772 pjsip_tx_data **p_tdata )
1773{
1774 pjsip_tx_data *last_res;
1775 pj_status_t status;
1776
1777 /* Verify arguments. */
1778 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1779
1780 /* Must have INVITE transaction. */
1781 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1782
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001783 /* Must have created an answer before */
1784 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001785
Benny Prijono64f851e2006-02-23 13:49:28 +00001786 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001787
1788 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001789 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001790 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1791 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001792 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001793
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001794 /* For non-2xx final response, strip message body */
1795 if (st_code >= 300) {
1796 last_res->msg->body = NULL;
1797 }
Benny Prijono268ca612006-02-07 12:34:11 +00001798
Benny Prijono26ff9062006-02-21 23:47:00 +00001799 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001800 status = process_answer(inv, st_code, last_res, local_sdp);
1801 if (status != PJ_SUCCESS) {
1802 pjsip_tx_data_dec_ref(last_res);
1803 goto on_return;
1804 }
Benny Prijono268ca612006-02-07 12:34:11 +00001805
Benny Prijono268ca612006-02-07 12:34:11 +00001806
1807 *p_tdata = last_res;
1808
Benny Prijono64f851e2006-02-23 13:49:28 +00001809on_return:
1810 pjsip_dlg_dec_lock(inv->dlg);
1811 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001812}
1813
1814
1815/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001816 * Set SDP answer.
1817 */
1818PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1819 const pjmedia_sdp_session *sdp )
1820{
1821 pj_status_t status;
1822
1823 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1824
1825 pjsip_dlg_inc_lock(inv->dlg);
1826 status = pjmedia_sdp_neg_set_local_answer( inv->pool, inv->neg, sdp);
1827 pjsip_dlg_dec_lock(inv->dlg);
1828
1829 return status;
1830}
1831
1832
1833/*
Benny Prijono268ca612006-02-07 12:34:11 +00001834 * End session.
1835 */
1836PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
1837 int st_code,
1838 const pj_str_t *st_text,
1839 pjsip_tx_data **p_tdata )
1840{
1841 pjsip_tx_data *tdata;
1842 pj_status_t status;
1843
1844 /* Verify arguments. */
1845 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1846
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001847 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001848 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001849
Benny Prijono268ca612006-02-07 12:34:11 +00001850 /* Create appropriate message. */
1851 switch (inv->state) {
1852 case PJSIP_INV_STATE_CALLING:
1853 case PJSIP_INV_STATE_EARLY:
1854 case PJSIP_INV_STATE_INCOMING:
1855
1856 if (inv->role == PJSIP_ROLE_UAC) {
1857
1858 /* For UAC when session has not been confirmed, create CANCEL. */
1859
1860 /* MUST have the original UAC INVITE transaction. */
1861 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
1862
1863 /* But CANCEL should only be called when we have received a
1864 * provisional response. If we haven't received any responses,
1865 * just destroy the transaction.
1866 */
1867 if (inv->invite_tsx->status_code < 100) {
1868
Benny Prijono1dc8be02007-05-30 04:26:40 +00001869 pjsip_tsx_stop_retransmit(inv->invite_tsx);
1870 inv->cancelling = PJ_TRUE;
1871 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00001872 *p_tdata = NULL;
Benny Prijono1dc8be02007-05-30 04:26:40 +00001873 PJ_LOG(4, (inv->obj_name, "Stopping retransmission, "
1874 "delaying CANCEL"));
Benny Prijonofccab712006-02-22 22:23:22 +00001875 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001876 }
1877
1878 /* The CSeq here assumes that the dialog is started with an
1879 * INVITE session. This may not be correct; dialog can be
1880 * started as SUBSCRIBE session.
1881 * So fix this!
1882 */
1883 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
1884 inv->invite_tsx->last_tx,
1885 &tdata);
1886
1887 } else {
1888
1889 /* For UAS, send a final response. */
1890 tdata = inv->invite_tsx->last_tx;
1891 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
1892
Benny Prijono26ff9062006-02-21 23:47:00 +00001893 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
1894 // st_text);
1895 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001896 }
1897 break;
1898
1899 case PJSIP_INV_STATE_CONNECTING:
1900 case PJSIP_INV_STATE_CONFIRMED:
1901 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001902 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
1903 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001904 break;
1905
1906 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00001907 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001908 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00001909
1910 default:
1911 pj_assert("!Invalid operation!");
1912 return PJ_EINVALIDOP;
1913 }
1914
1915 if (status != PJ_SUCCESS)
1916 return status;
1917
1918
1919 /* Done */
1920
Benny Prijono0606e702007-05-22 12:21:40 +00001921 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00001922 *p_tdata = tdata;
1923
1924 return PJ_SUCCESS;
1925}
1926
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001927/* Following redirection recursion, get next target from the target set and
1928 * notify user.
1929 *
1930 * Returns PJ_FALSE if recursion fails (either because there's no more target
1931 * or user rejects the recursion). If we return PJ_FALSE, caller should
1932 * disconnect the session.
1933 *
1934 * Note:
1935 * the event 'e' argument may be NULL.
1936 */
1937static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
1938 const pj_str_t *reason, pjsip_event *e)
1939{
Benny Prijono08a48b82008-11-27 12:42:07 +00001940 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001941 pjsip_target *target;
1942
1943 /* Won't redirect if the callback is not implemented. */
1944 if (mod_inv.cb.on_redirected == NULL)
1945 return PJ_FALSE;
1946
1947 if (reason == NULL)
1948 reason = pjsip_get_status_text(code);
1949
1950 /* Set status of current target */
1951 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
1952 code, reason);
1953
1954 /* Fetch next target from the target set. We only want to
1955 * process SIP/SIPS URI for now.
1956 */
1957 for (;;) {
1958 target = pjsip_target_set_get_next(&inv->dlg->target_set);
1959 if (target == NULL) {
1960 /* No more target. */
1961 return PJ_FALSE;
1962 }
1963
1964 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
1965 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
1966 {
1967 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
1968 reason = pjsip_get_status_text(code);
1969
1970 /* Mark this target as unusable and fetch next target. */
1971 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
1972 } else {
1973 /* Found a target */
1974 break;
1975 }
1976 }
1977
1978 /* We have target in 'target'. Set this target as current target
1979 * and notify callback.
1980 */
1981 pjsip_target_set_set_current(&inv->dlg->target_set, target);
1982
Benny Prijono08a48b82008-11-27 12:42:07 +00001983 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001984
1985
1986 /* Check what the application wants to do now */
1987 switch (op) {
1988 case PJSIP_REDIRECT_ACCEPT:
1989 case PJSIP_REDIRECT_STOP:
1990 /* Must increment session counter, that's the convention of the
1991 * pjsip_inv_process_redirect().
1992 */
1993 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
1994
1995 /* Act on the recursion */
1996 pjsip_inv_process_redirect(inv, op, e);
1997 return PJ_TRUE;
1998
1999 case PJSIP_REDIRECT_PENDING:
2000 /* Increment session so that the dialog/session is not destroyed
2001 * while we're waiting for user confirmation.
2002 */
2003 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2004
2005 /* Also clear the invite_tsx variable, otherwise when this tsx is
2006 * terminated, it will also terminate the session.
2007 */
2008 inv->invite_tsx = NULL;
2009
2010 /* Done. The processing will continue once the application calls
2011 * pjsip_inv_process_redirect().
2012 */
2013 return PJ_TRUE;
2014
2015 case PJSIP_REDIRECT_REJECT:
2016 /* Recursively call this function again to fetch next target, if any.
2017 */
2018 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2019
2020 }
2021
2022 pj_assert(!"Should not reach here");
2023 return PJ_FALSE;
2024}
2025
2026
2027/* Process redirection/recursion */
2028PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2029 pjsip_redirect_op op,
2030 pjsip_event *e)
2031{
2032 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2033 pjsip_event usr_event;
2034 pj_status_t status = PJ_SUCCESS;
2035
2036 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2037
2038 if (e == NULL) {
2039 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2040 e = &usr_event;
2041 }
2042
2043 pjsip_dlg_inc_lock(inv->dlg);
2044
2045 /* Decrement session. That's the convention here to prevent the dialog
2046 * or session from being destroyed while we're waiting for user
2047 * confirmation.
2048 */
2049 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2050
2051 /* See what the application wants to do now */
2052 switch (op) {
2053 case PJSIP_REDIRECT_ACCEPT:
2054 /* User accept the redirection. Reset the session and resend the
2055 * INVITE request.
2056 */
2057 {
2058 pjsip_tx_data *tdata;
2059 pjsip_via_hdr *via;
2060
2061 /* Get the original INVITE request. */
2062 tdata = inv->invite_req;
2063 pjsip_tx_data_add_ref(tdata);
2064
2065 /* Restore strict route set.
2066 * See http://trac.pjsip.org/repos/ticket/492
2067 */
2068 pjsip_restore_strict_route_set(tdata);
2069
2070 /* Set target */
2071 tdata->msg->line.req.uri =
2072 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2073
2074 /* Remove branch param in Via header. */
2075 via = (pjsip_via_hdr*)
2076 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2077 via->branch_param.slen = 0;
2078
2079 /* Must invalidate the message! */
2080 pjsip_tx_data_invalidate_msg(tdata);
2081
2082 /* Reset the session */
2083 pjsip_inv_uac_restart(inv, PJ_FALSE);
2084
2085 /* (re)Send the INVITE request */
2086 status = pjsip_inv_send_msg(inv, tdata);
2087 }
2088 break;
2089
2090 case PJSIP_REDIRECT_STOP:
2091 /* User doesn't want the redirection. Disconnect the session now. */
2092 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2093 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2094
2095 /* Caller should expect that the invite session is gone now, so
2096 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2097 */
2098 break;
2099
2100 case PJSIP_REDIRECT_REJECT:
2101 /* Current target is rejected. Fetch next target if any. */
2102 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2103 inv_set_cause(inv, cancel_code,
2104 pjsip_get_status_text(cancel_code));
2105 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2106
2107 /* Tell caller that the invite session is gone now */
2108 status = PJSIP_ESESSIONTERMINATED;
2109 }
2110 break;
2111
2112
2113 case PJSIP_REDIRECT_PENDING:
2114 pj_assert(!"Should not happen");
2115 break;
2116 }
2117
2118
2119 pjsip_dlg_dec_lock(inv->dlg);
2120
2121 return status;
2122}
2123
Benny Prijono268ca612006-02-07 12:34:11 +00002124
2125/*
2126 * Create re-INVITE.
2127 */
2128PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2129 const pj_str_t *new_contact,
2130 const pjmedia_sdp_session *new_offer,
2131 pjsip_tx_data **p_tdata )
2132{
Benny Prijono26ff9062006-02-21 23:47:00 +00002133 pj_status_t status;
2134 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002135
Benny Prijono26ff9062006-02-21 23:47:00 +00002136 /* Check arguments. */
2137 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2138
2139 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002140 if (inv->invite_tsx!=NULL)
2141 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002142
2143
2144 pjsip_dlg_inc_lock(inv->dlg);
2145
2146 if (new_contact) {
2147 pj_str_t tmp;
2148 const pj_str_t STR_CONTACT = { "Contact", 7 };
2149
2150 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002151 contact_hdr = (pjsip_contact_hdr*)
2152 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002153 tmp.ptr, tmp.slen, NULL);
2154 if (!contact_hdr) {
2155 status = PJSIP_EINVALIDURI;
2156 goto on_return;
2157 }
2158 }
2159
2160
2161 if (new_offer) {
2162 if (!inv->neg) {
2163 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer,
2164 &inv->neg);
2165 if (status != PJ_SUCCESS)
2166 goto on_return;
2167
2168 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2169
2170 case PJMEDIA_SDP_NEG_STATE_NULL:
2171 pj_assert(!"Unexpected SDP neg state NULL");
2172 status = PJ_EBUG;
2173 goto on_return;
2174
2175 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2176 PJ_LOG(4,(inv->obj_name,
2177 "pjsip_inv_reinvite: already have an offer, new "
2178 "offer is ignored"));
2179 break;
2180
2181 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
2182 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
2183 new_offer);
2184 if (status != PJ_SUCCESS)
2185 goto on_return;
2186 break;
2187
2188 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2189 PJ_LOG(4,(inv->obj_name,
2190 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2191 "offer is ignored"));
2192 break;
2193
2194 case PJMEDIA_SDP_NEG_STATE_DONE:
2195 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2196 new_offer);
2197 if (status != PJ_SUCCESS)
2198 goto on_return;
2199 break;
2200 }
2201 }
2202
2203 if (contact_hdr)
2204 inv->dlg->local.contact = contact_hdr;
2205
2206 status = pjsip_inv_invite(inv, p_tdata);
2207
2208on_return:
2209 pjsip_dlg_dec_lock(inv->dlg);
2210 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002211}
2212
2213/*
2214 * Create UPDATE.
2215 */
2216PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2217 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002218 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002219 pjsip_tx_data **p_tdata )
2220{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002221 pjsip_contact_hdr *contact_hdr = NULL;
2222 pjsip_tx_data *tdata = NULL;
2223 pjmedia_sdp_session *sdp_copy;
2224 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002225
Benny Prijono1f7767b2007-10-03 18:28:49 +00002226 /* Verify arguments. */
2227 PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL);
2228
2229 /* Dialog must have been established */
2230 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2231 PJ_EINVALIDOP);
2232
2233 /* Invite session must not have been disconnected */
2234 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2235 PJ_EINVALIDOP);
2236
2237 /* Lock dialog. */
2238 pjsip_dlg_inc_lock(inv->dlg);
2239
2240 /* Process offer */
2241 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2242 PJ_LOG(4,(inv->dlg->obj_name,
2243 "Invalid SDP offer/answer state for UPDATE"));
2244 status = PJ_EINVALIDOP;
2245 goto on_error;
2246 }
2247
2248 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
2249 offer);
2250 if (status != PJ_SUCCESS)
2251 goto on_error;
2252
2253
2254 /* Update Contact if required */
2255 if (new_contact) {
2256 pj_str_t tmp;
2257 const pj_str_t STR_CONTACT = { "Contact", 7 };
2258
2259 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2260 contact_hdr = (pjsip_contact_hdr*)
2261 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2262 tmp.ptr, tmp.slen, NULL);
2263 if (!contact_hdr) {
2264 status = PJSIP_EINVALIDURI;
2265 goto on_error;
2266 }
2267
2268 inv->dlg->local.contact = contact_hdr;
2269 }
2270
2271 /* Create request */
2272 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2273 -1, &tdata);
2274 if (status != PJ_SUCCESS)
2275 goto on_error;
2276
2277 /* Attach SDP body */
2278 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2279 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2280
2281 /* Unlock dialog. */
2282 pjsip_dlg_dec_lock(inv->dlg);
2283
2284 *p_tdata = tdata;
2285
2286 return PJ_SUCCESS;
2287
2288on_error:
2289 if (tdata)
2290 pjsip_tx_data_dec_ref(tdata);
2291
2292 /* Unlock dialog. */
2293 pjsip_dlg_dec_lock(inv->dlg);
2294
2295 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002296}
2297
2298/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002299 * Create an ACK request.
2300 */
2301PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2302 int cseq,
2303 pjsip_tx_data **p_tdata)
2304{
2305 const pjmedia_sdp_session *sdp = NULL;
2306 pj_status_t status;
2307
2308 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2309
2310 /* Lock dialog. */
2311 pjsip_dlg_inc_lock(inv->dlg);
2312
2313 /* Destroy last_ack */
2314 if (inv->last_ack) {
2315 pjsip_tx_data_dec_ref(inv->last_ack);
2316 inv->last_ack = NULL;
2317 }
2318
2319 /* Create new ACK request */
2320 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2321 cseq, &inv->last_ack);
2322 if (status != PJ_SUCCESS) {
2323 pjsip_dlg_dec_lock(inv->dlg);
2324 return status;
2325 }
2326
2327 /* See if we have pending SDP answer to send */
2328 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2329 if (sdp) {
2330 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2331 }
2332
2333 /* Keep this for subsequent response retransmission */
2334 inv->last_ack_cseq = cseq;
2335 pjsip_tx_data_add_ref(inv->last_ack);
2336
2337 /* Done */
2338 *p_tdata = inv->last_ack;
2339
2340 /* Unlock dialog. */
2341 pjsip_dlg_dec_lock(inv->dlg);
2342
2343 return PJ_SUCCESS;
2344}
2345
2346/*
Benny Prijono268ca612006-02-07 12:34:11 +00002347 * Send a request or response message.
2348 */
2349PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002350 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002351{
2352 pj_status_t status;
2353
2354 /* Verify arguments. */
2355 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2356
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002357 PJ_LOG(5,(inv->obj_name, "Sending %s",
2358 pjsip_tx_data_get_info(tdata)));
2359
Benny Prijono268ca612006-02-07 12:34:11 +00002360 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002361 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002362
Benny Prijono64158af2006-04-04 11:06:34 +00002363 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002364
Benny Prijono22e48c92008-03-20 14:40:50 +00002365 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002366 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2367 inv->invite_tsx)
2368 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002369 pjsip_tx_data_dec_ref(tdata);
2370 pjsip_dlg_dec_lock(inv->dlg);
2371 return PJ_EINVALIDOP;
2372 }
2373
2374 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002375 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002376 tsx_inv_data->inv = inv;
2377
Benny Prijono64158af2006-04-04 11:06:34 +00002378 pjsip_dlg_dec_lock(inv->dlg);
2379
2380 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2381 tsx_inv_data);
2382 if (status != PJ_SUCCESS)
2383 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002384
2385 } else {
2386 pjsip_cseq_hdr *cseq;
2387
2388 /* Can only do this to send response to original INVITE
2389 * request.
2390 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002391 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 +00002392 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002393 PJ_EINVALIDOP);
2394
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002395 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002396 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002397 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002398 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002399 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002400 }
2401
Benny Prijono268ca612006-02-07 12:34:11 +00002402 if (status != PJ_SUCCESS)
2403 return status;
2404 }
2405
2406 /* Done (?) */
2407 return PJ_SUCCESS;
2408}
2409
2410
Benny Prijono8ad55352006-02-08 11:16:05 +00002411/*
2412 * Respond to incoming CANCEL request.
2413 */
2414static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2415 pjsip_transaction *cancel_tsx,
2416 pjsip_rx_data *rdata)
2417{
2418 pjsip_tx_data *tdata;
2419 pjsip_transaction *invite_tsx;
2420 pj_str_t key;
2421 pj_status_t status;
2422
2423 /* See if we have matching INVITE server transaction: */
2424
2425 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002426 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002427 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2428
2429 if (invite_tsx == NULL) {
2430
2431 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002432 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002433 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002434 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002435 &tdata);
2436
2437 } else {
2438 /* Always answer CANCEL will 200 (OK) regardless of
2439 * the state of the INVITE transaction.
2440 */
2441 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2442 &tdata);
2443 }
2444
2445 /* See if we have created the response successfully. */
2446 if (status != PJ_SUCCESS) return;
2447
2448 /* Send the CANCEL response */
2449 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2450 if (status != PJ_SUCCESS) return;
2451
2452
2453 /* See if we need to terminate the UAS INVITE transaction
2454 * with 487 (Request Terminated) response.
2455 */
2456 if (invite_tsx && invite_tsx->status_code < 200) {
2457
2458 pj_assert(invite_tsx->last_tx != NULL);
2459
2460 tdata = invite_tsx->last_tx;
2461
2462 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002463 if (status == PJ_SUCCESS) {
2464 /* Remove the message body */
2465 tdata->msg->body = NULL;
Benny Prijono8ad55352006-02-08 11:16:05 +00002466 pjsip_dlg_send_response(inv->dlg, invite_tsx, tdata);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002467 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002468 }
2469
2470 if (invite_tsx)
2471 pj_mutex_unlock(invite_tsx->mutex);
2472}
2473
2474
2475/*
2476 * Respond to incoming BYE request.
2477 */
2478static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2479 pjsip_transaction *bye_tsx,
2480 pjsip_rx_data *rdata,
2481 pjsip_event *e )
2482{
2483 pj_status_t status;
2484 pjsip_tx_data *tdata;
2485
2486 /* Respond BYE with 200: */
2487
2488 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2489 if (status != PJ_SUCCESS) return;
2490
2491 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2492 if (status != PJ_SUCCESS) return;
2493
2494 /* Terminate session: */
2495
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002496 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002497 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002498 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002499 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002500}
2501
2502/*
Benny Prijono38998232006-02-08 22:44:25 +00002503 * Respond to BYE request.
2504 */
2505static void inv_handle_bye_response( pjsip_inv_session *inv,
2506 pjsip_transaction *tsx,
2507 pjsip_rx_data *rdata,
2508 pjsip_event *e )
2509{
2510 pj_status_t status;
2511
2512 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002513 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002514 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2515 return;
2516 }
2517
2518 /* Handle 401/407 challenge. */
2519 if (tsx->status_code == 401 || tsx->status_code == 407) {
2520
2521 pjsip_tx_data *tdata;
2522
2523 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2524 rdata,
2525 tsx->last_tx,
2526 &tdata);
2527
2528 if (status != PJ_SUCCESS) {
2529
2530 /* Does not have proper credentials.
2531 * End the session anyway.
2532 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002533 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002534 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2535
2536 } else {
2537 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002538 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002539 }
2540
2541 } else {
2542
2543 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002544 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002545 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2546 }
2547
2548}
2549
2550/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002551 * Respond to incoming UPDATE request.
2552 */
2553static void inv_respond_incoming_update(pjsip_inv_session *inv,
2554 pjsip_rx_data *rdata)
2555{
2556 pjmedia_sdp_neg_state neg_state;
2557 pj_status_t status;
2558 pjsip_tx_data *tdata = NULL;
2559
2560 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2561
2562 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2563 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2564 status = pjsip_dlg_create_response(inv->dlg, rdata,
2565 PJSIP_SC_REQUEST_PENDING, NULL,
2566 &tdata);
2567 }
2568 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2569 * receive UPDATE while we haven't sent answer.
2570 */
2571 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2572 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2573 status = pjsip_dlg_create_response(inv->dlg, rdata,
2574 PJSIP_SC_INTERNAL_SERVER_ERROR,
2575 NULL, &tdata);
2576
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002577 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2578 * This is a valid scenario according to session-timer draft.
2579 */
2580 } else if (rdata->msg_info.msg->body == NULL) {
2581
2582 status = pjsip_dlg_create_response(inv->dlg, rdata,
2583 200, NULL, &tdata);
2584
Benny Prijono1f7767b2007-10-03 18:28:49 +00002585 } else {
2586 /* We receive new offer from remote */
2587 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2588
2589 /* Application MUST have supplied the answer by now.
2590 * If so, negotiate the SDP.
2591 */
2592 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2593 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2594 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2595 {
2596 /* Negotiation has failed */
2597 status = pjsip_dlg_create_response(inv->dlg, rdata,
2598 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2599 NULL, &tdata);
2600 } else {
2601 /* New media has been negotiated successfully, send 200/OK */
2602 status = pjsip_dlg_create_response(inv->dlg, rdata,
2603 PJSIP_SC_OK, NULL, &tdata);
2604 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002605 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002606 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2607 if (status == PJ_SUCCESS)
2608 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2609 }
2610 }
2611 }
2612
2613 if (status != PJ_SUCCESS) {
2614 if (tdata != NULL) {
2615 pjsip_tx_data_dec_ref(tdata);
2616 tdata = NULL;
2617 }
2618 return;
2619 }
2620
2621 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2622}
2623
2624
2625/*
2626 * Handle incoming response to UAC UPDATE request.
2627 */
2628static void inv_handle_update_response( pjsip_inv_session *inv,
2629 pjsip_event *e)
2630{
2631 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2632 struct tsx_inv_data *tsx_inv_data = NULL;
2633 pj_status_t status = -1;
2634
Benny Prijono48ab2b72007-11-08 09:24:30 +00002635 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002636 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono48ab2b72007-11-08 09:24:30 +00002637 (tsx->status_code == 401 || tsx->status_code == 407)) {
2638
2639 pjsip_tx_data *tdata;
2640
2641 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2642 e->body.tsx_state.src.rdata,
2643 tsx->last_tx,
2644 &tdata);
2645
2646 if (status != PJ_SUCCESS) {
2647
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002648 /* Somehow failed. Probably it's not a good idea to terminate
2649 * the session since this is just a request within dialog. And
2650 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002651 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002652 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002653 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2654 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002655 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002656
2657 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002658 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002659 status = pjsip_inv_send_msg(inv, tdata);
2660 }
2661
2662 /* Process 2xx response */
2663 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002664 tsx->status_code/100 == 2 &&
2665 e->body.tsx_state.src.rdata->msg_info.msg->body)
2666 {
2667 status = inv_check_sdp_in_incoming_msg(inv, tsx,
2668 e->body.tsx_state.src.rdata);
2669
2670 } else {
2671 /* Get/attach invite session's transaction data */
2672 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2673 if (tsx_inv_data == NULL) {
2674 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2675 tsx_inv_data->inv = inv;
2676 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2677 }
2678 }
2679
2680 /* Otherwise if we don't get successful response, cancel
2681 * our negotiator.
2682 */
2683 if (status != PJ_SUCCESS &&
2684 pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
2685 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2686 {
2687 pjmedia_sdp_neg_cancel_offer(inv->neg);
2688
2689 /* Prevent from us cancelling different offer! */
2690 tsx_inv_data->sdp_done = PJ_TRUE;
2691 }
2692}
2693
2694
2695/*
2696 * Handle incoming reliable response.
2697 */
2698static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2699 pjsip_rx_data *rdata)
2700{
2701 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002702 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002703 pj_status_t status;
2704
2705 /* Create PRACK */
2706 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2707 if (status != PJ_SUCCESS)
2708 return;
2709
2710 /* See if we need to attach SDP answer on the PRACK request */
2711 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2712 if (sdp) {
2713 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2714 }
2715
2716 /* Send PRACK (must be using 100rel module!) */
2717 pjsip_100rel_send_prack(inv, tdata);
2718}
2719
2720
2721/*
2722 * Handle incoming PRACK.
2723 */
2724static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2725 pjsip_rx_data *rdata)
2726{
2727 pj_status_t status;
2728
2729 /* Run through 100rel module to see if we can accept this
2730 * PRACK request. The 100rel will send 200/OK to PRACK request.
2731 */
2732 status = pjsip_100rel_on_rx_prack(inv, rdata);
2733 if (status != PJ_SUCCESS)
2734 return;
2735
2736 /* Now check for SDP answer in the PRACK request */
2737 if (rdata->msg_info.msg->body) {
2738 status = inv_check_sdp_in_incoming_msg(inv,
2739 pjsip_rdata_get_tsx(rdata), rdata);
2740 } else {
2741 /* No SDP body */
2742 status = -1;
2743 }
2744
2745 /* If SDP negotiation has been successful, also mark the
2746 * SDP negotiation flag in the invite transaction to be
2747 * done too.
2748 */
2749 if (status == PJ_SUCCESS && inv->invite_tsx) {
2750 struct tsx_inv_data *tsx_inv_data;
2751
2752 /* Get/attach invite session's transaction data */
2753 tsx_inv_data = (struct tsx_inv_data*)
2754 inv->invite_tsx->mod_data[mod_inv.mod.id];
2755 if (tsx_inv_data == NULL) {
2756 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2757 struct tsx_inv_data);
2758 tsx_inv_data->inv = inv;
2759 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2760 }
2761
2762 tsx_inv_data->sdp_done = PJ_TRUE;
2763 }
2764}
2765
2766
2767/*
Benny Prijono8ad55352006-02-08 11:16:05 +00002768 * State NULL is before anything is sent/received.
2769 */
2770static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002771{
2772 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2773 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2774
2775 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2776
2777 if (tsx->method.id == PJSIP_INVITE_METHOD) {
2778
Benny Prijono64f851e2006-02-23 13:49:28 +00002779 /* Keep the initial INVITE transaction. */
2780 if (inv->invite_tsx == NULL)
2781 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00002782
Benny Prijono64f851e2006-02-23 13:49:28 +00002783 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00002784
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002785 /* Save the original INVITE request, if on_redirected() callback
2786 * is implemented. We may need to resend the INVITE if we receive
2787 * redirection response.
2788 */
2789 if (mod_inv.cb.on_redirected) {
2790 if (inv->invite_req) {
2791 pjsip_tx_data_dec_ref(inv->invite_req);
2792 inv->invite_req = NULL;
2793 }
2794 inv->invite_req = tsx->last_tx;
2795 pjsip_tx_data_add_ref(inv->invite_req);
2796 }
2797
Benny Prijono268ca612006-02-07 12:34:11 +00002798 switch (tsx->state) {
2799 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002800 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002801 break;
2802 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002803 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002804 break;
2805 }
2806
2807 } else {
2808 switch (tsx->state) {
2809 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002810 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002811 break;
Benny Prijono38998232006-02-08 22:44:25 +00002812 case PJSIP_TSX_STATE_PROCEEDING:
2813 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
2814 if (tsx->status_code > 100)
2815 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
2816 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002817 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002818 inv_on_state_incoming(inv, e);
2819 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002820 }
2821 }
2822
2823 } else {
2824 pj_assert(!"Unexpected transaction type");
2825 }
2826}
2827
Benny Prijono8ad55352006-02-08 11:16:05 +00002828/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002829 * Generic UAC transaction handler:
2830 * - resend request on 401 or 407 response.
2831 * - terminate dialog on 408 and 481 response.
2832 */
2833static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
2834 pjsip_event *e)
2835{
2836 /* RFC 3261 Section 12.2.1.2:
2837 * If the response for a request within a dialog is a 481
2838 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
2839 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
2840 * no response at all is received for the request (the client
2841 * transaction would inform the TU about the timeout.)
2842 *
2843 * For INVITE initiated dialogs, terminating the dialog consists of
2844 * sending a BYE.
2845 *
2846 * Note:
2847 * according to X, this should terminate dialog usage only, not the
2848 * dialog.
2849 */
2850 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2851
2852 pj_assert(tsx->role == PJSIP_UAC_ROLE);
2853
2854 /* Note that 481 response to CANCEL does not terminate dialog usage,
2855 * but only the transaction.
2856 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00002857 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
2858 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002859 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00002860 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
2861 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
2862 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002863 {
2864 pjsip_tx_data *bye;
2865 pj_status_t status;
2866
2867 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2868 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2869
2870 /* Send BYE */
2871 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2872 -1, &bye);
2873 if (status == PJ_SUCCESS) {
2874 pjsip_inv_send_msg(inv, bye);
2875 }
2876
2877 return PJ_TRUE; /* Handled */
2878
2879 }
2880 /* Handle 401/407 challenge. */
2881 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2882 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
2883 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
2884 {
2885
2886 pjsip_tx_data *tdata;
2887 pj_status_t status;
2888
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002889 if (tsx->method.id == PJSIP_INVITE_METHOD)
2890 inv->invite_tsx = NULL;
2891
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002892 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2893 e->body.tsx_state.src.rdata,
2894 tsx->last_tx, &tdata);
2895
2896 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002897 /* Somehow failed. Probably it's not a good idea to terminate
2898 * the session since this is just a request within dialog. And
2899 * even if we terminate we should send BYE.
2900 */
2901 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002902 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2903 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002904 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002905
2906 } else {
2907 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002908 status = pjsip_inv_send_msg(inv, tdata);
2909 }
2910
2911 return PJ_TRUE; /* Handled */
2912
2913 } else {
2914 return PJ_FALSE; /* Unhandled */
2915 }
2916}
2917
2918
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002919/* Handle call rejection, especially with regard to processing call
2920 * redirection. We need to handle the following scenarios:
2921 * - 3xx response is received -- see if on_redirected() callback is
2922 * implemented. If so, add the Contact URIs in the response to the
2923 * target set and notify user.
2924 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
2925 * if so fetch the next target if any and notify the on_redirected()
2926 * callback.
2927 * - for other cases -- disconnect the session.
2928 */
2929static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
2930{
2931 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2932 pj_status_t status;
2933
2934 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
2935
2936 if (mod_inv.cb.on_redirected == NULL) {
2937
2938 /* Redirection callback is not implemented, disconnect the
2939 * call.
2940 */
2941 goto terminate_session;
2942
2943 } else {
2944 const pjsip_msg *res_msg;
2945
2946 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
2947
2948 /* Gather all Contact URI's in the response and add them
2949 * to target set. The function will take care of removing
2950 * duplicate URI's.
2951 */
2952 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
2953 inv->dlg->pool, res_msg);
2954
2955 /* Recurse to alternate targets if application allows us */
2956 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
2957 {
2958 /* Recursion fails, terminate session now */
2959 goto terminate_session;
2960 }
2961
2962 /* Done */
2963 }
2964
2965 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
2966 !inv->cancelling)
2967 {
2968
2969 /* Handle authentication failure:
2970 * Resend the request with Authorization header.
2971 */
2972 pjsip_tx_data *tdata;
2973
2974 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
2975 e->body.tsx_state.src.rdata,
2976 tsx->last_tx,
2977 &tdata);
2978
2979 if (status != PJ_SUCCESS) {
2980
2981 /* Does not have proper credentials. If we are currently
2982 * recursing, try the next target. Otherwise end the session.
2983 */
2984 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
2985 {
2986 /* Recursion fails, terminate session now */
2987 goto terminate_session;
2988 }
2989
2990 } else {
2991
2992 /* Restart session. */
2993 pjsip_inv_uac_restart(inv, PJ_FALSE);
2994
2995 /* Send the request. */
2996 status = pjsip_inv_send_msg(inv, tdata);
2997 }
2998
2999 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3000 /* Global error */
3001 goto terminate_session;
3002
3003 } else {
3004 /* See if we have alternate target to try */
3005 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3006 /* Recursion fails, terminate session now */
3007 goto terminate_session;
3008 }
3009 }
3010 return;
3011
3012terminate_session:
3013 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3014 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3015}
3016
3017
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003018/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003019 * State CALLING is after sending initial INVITE request but before
3020 * any response (with tag) is received.
3021 */
3022static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003023{
3024 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3025 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003026 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003027
3028 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3029
Benny Prijono8ad55352006-02-08 11:16:05 +00003030 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003031
3032 switch (tsx->state) {
3033
Benny Prijono64f851e2006-02-23 13:49:28 +00003034 case PJSIP_TSX_STATE_CALLING:
3035 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3036 break;
3037
Benny Prijono268ca612006-02-07 12:34:11 +00003038 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003039 if (inv->pending_cancel) {
3040 pjsip_tx_data *cancel;
3041
3042 inv->pending_cancel = PJ_FALSE;
3043
3044 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3045 if (status == PJ_SUCCESS && cancel)
3046 status = pjsip_inv_send_msg(inv, cancel);
3047 }
3048
Benny Prijono268ca612006-02-07 12:34:11 +00003049 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003050
Benny Prijono8ad55352006-02-08 11:16:05 +00003051 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003052
3053 inv_check_sdp_in_incoming_msg(inv, tsx,
3054 e->body.tsx_state.src.rdata);
3055
Benny Prijono1f7767b2007-10-03 18:28:49 +00003056 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3057 inv_handle_incoming_reliable_response(
3058 inv, e->body.tsx_state.src.rdata);
3059 }
3060
Benny Prijono268ca612006-02-07 12:34:11 +00003061 } else {
3062 /* Ignore 100 (Trying) response, as it doesn't change
3063 * session state. It only ceases retransmissions.
3064 */
3065 }
3066 break;
3067
3068 case PJSIP_TSX_STATE_COMPLETED:
3069 if (tsx->status_code/100 == 2) {
3070
3071 /* This should not happen.
3072 * When transaction receives 2xx, it should be terminated
3073 */
3074 pj_assert(0);
Benny Prijono8ad55352006-02-08 11:16:05 +00003075 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003076
3077 inv_check_sdp_in_incoming_msg(inv, tsx,
3078 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003079
3080 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003081 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003082 }
3083 break;
3084
3085 case PJSIP_TSX_STATE_TERMINATED:
3086 /* INVITE transaction can be terminated either because UAC
3087 * transaction received 2xx response or because of transport
3088 * error.
3089 */
3090 if (tsx->status_code/100 == 2) {
3091 /* This must be receipt of 2xx response */
3092
3093 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003094 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003095
Benny Prijonoa66c7152006-02-09 01:26:14 +00003096 inv_check_sdp_in_incoming_msg(inv, tsx,
3097 e->body.tsx_state.src.rdata);
3098
Benny Prijono268ca612006-02-07 12:34:11 +00003099 /* Send ACK */
3100 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3101
Benny Prijonod5f9f422007-11-25 04:40:07 +00003102 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003103
Benny Prijono268ca612006-02-07 12:34:11 +00003104 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003105 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003106 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003107 }
3108 break;
3109
Benny Prijono34a404e2006-02-09 14:38:30 +00003110 default:
3111 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003112 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003113
Benny Prijono1f7767b2007-10-03 18:28:49 +00003114 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003115 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003116 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003117 * Transaction Does Not Exist), 408, or when it's timed out. In these
3118 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003119 * Note that 481 response to CANCEL does not terminate dialog usage,
3120 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003121 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003122 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3123 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003124 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3125 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003126 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003127 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003128 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003129 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3130 }
Benny Prijono268ca612006-02-07 12:34:11 +00003131 }
3132}
3133
Benny Prijono8ad55352006-02-08 11:16:05 +00003134/*
3135 * State INCOMING is after we received the request, but before
3136 * responses with tag are sent.
3137 */
3138static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003139{
3140 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3141 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3142
3143 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3144
Benny Prijono8ad55352006-02-08 11:16:05 +00003145 if (tsx == inv->invite_tsx) {
3146
3147 /*
3148 * Handle the INVITE state transition.
3149 */
3150
Benny Prijono268ca612006-02-07 12:34:11 +00003151 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003152
Benny Prijono64f851e2006-02-23 13:49:28 +00003153 case PJSIP_TSX_STATE_TRYING:
3154 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3155 break;
3156
Benny Prijono268ca612006-02-07 12:34:11 +00003157 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003158 /*
3159 * Transaction sent provisional response.
3160 */
Benny Prijono268ca612006-02-07 12:34:11 +00003161 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003162 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003163 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003164
Benny Prijono268ca612006-02-07 12:34:11 +00003165 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003166 /*
3167 * Transaction sent final response.
3168 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003169 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003170 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003171 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003172 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003173 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003174 }
Benny Prijono268ca612006-02-07 12:34:11 +00003175 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003176
Benny Prijono268ca612006-02-07 12:34:11 +00003177 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003178 /*
3179 * This happens on transport error (e.g. failed to send
3180 * response)
3181 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003182 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003183 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003184 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003185
Benny Prijono268ca612006-02-07 12:34:11 +00003186 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003187 pj_assert(!"Unexpected INVITE state");
3188 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003189 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003190
3191 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3192 tsx->role == PJSIP_ROLE_UAS &&
3193 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3194 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3195 {
3196
3197 /*
3198 * Handle incoming CANCEL request.
3199 */
3200
3201 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3202
Benny Prijono268ca612006-02-07 12:34:11 +00003203 }
3204}
3205
Benny Prijono8ad55352006-02-08 11:16:05 +00003206/*
3207 * State EARLY is for both UAS and UAC, after response with To tag
3208 * is sent/received.
3209 */
3210static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003211{
3212 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3213 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3214
3215 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3216
Benny Prijono8ad55352006-02-08 11:16:05 +00003217 if (tsx == inv->invite_tsx) {
3218
3219 /*
3220 * Handle the INVITE state progress.
3221 */
Benny Prijono268ca612006-02-07 12:34:11 +00003222
3223 switch (tsx->state) {
3224
3225 case PJSIP_TSX_STATE_PROCEEDING:
3226 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003227 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003228
3229 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3230 inv_check_sdp_in_incoming_msg(inv, tsx,
3231 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003232
3233 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3234 inv_handle_incoming_reliable_response(
3235 inv, e->body.tsx_state.src.rdata);
3236 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003237 }
Benny Prijono268ca612006-02-07 12:34:11 +00003238 break;
3239
3240 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003241 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003242 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003243 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3244 inv_check_sdp_in_incoming_msg(inv, tsx,
3245 e->body.tsx_state.src.rdata);
3246 }
3247
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003248 } else if (tsx->role == PJSIP_ROLE_UAC) {
3249
3250 handle_uac_call_rejection(inv, e);
3251
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003252 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003253 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003254 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003255 }
Benny Prijono268ca612006-02-07 12:34:11 +00003256 break;
3257
Benny Prijonof3195072006-02-14 21:15:30 +00003258 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003259 /* For some reason can go here (maybe when ACK for 2xx has
3260 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003261
Benny Prijono268ca612006-02-07 12:34:11 +00003262 case PJSIP_TSX_STATE_TERMINATED:
3263 /* INVITE transaction can be terminated either because UAC
3264 * transaction received 2xx response or because of transport
3265 * error.
3266 */
3267 if (tsx->status_code/100 == 2) {
3268
3269 /* This must be receipt of 2xx response */
3270
3271 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003272 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003273
Benny Prijonoa66c7152006-02-09 01:26:14 +00003274 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3275 inv_check_sdp_in_incoming_msg(inv, tsx,
3276 e->body.tsx_state.src.rdata);
3277 }
3278
Benny Prijono268ca612006-02-07 12:34:11 +00003279 /* if UAC, send ACK and move state to confirmed. */
3280 if (tsx->role == PJSIP_ROLE_UAC) {
3281 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3282
Benny Prijonod5f9f422007-11-25 04:40:07 +00003283 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003284 }
3285
3286 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003287 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003288 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003289 }
3290 break;
3291
3292 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003293 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003294 }
3295
Benny Prijono8ad55352006-02-08 11:16:05 +00003296 } else if (inv->role == PJSIP_ROLE_UAS &&
3297 tsx->role == PJSIP_ROLE_UAS &&
3298 tsx->method.id == PJSIP_CANCEL_METHOD &&
3299 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3300 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3301 {
Benny Prijono268ca612006-02-07 12:34:11 +00003302
Benny Prijono8ad55352006-02-08 11:16:05 +00003303 /*
3304 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003305 */
3306
Benny Prijono8ad55352006-02-08 11:16:05 +00003307 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3308
Benny Prijono1f7767b2007-10-03 18:28:49 +00003309 } else if (tsx->role == PJSIP_ROLE_UAS &&
3310 tsx->state == PJSIP_TSX_STATE_TRYING &&
3311 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003312 {
3313 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003314 * Handle incoming UPDATE
3315 */
3316 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3317
3318
3319 } else if (tsx->role == PJSIP_ROLE_UAC &&
3320 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3321 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3322 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3323 {
3324 /*
3325 * Handle response to outgoing UPDATE request.
3326 */
3327 inv_handle_update_response(inv, e);
3328
3329 } else if (tsx->role == PJSIP_ROLE_UAS &&
3330 tsx->state == PJSIP_TSX_STATE_TRYING &&
3331 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3332 {
3333 /*
3334 * Handle incoming PRACK
3335 */
3336 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3337
3338 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003339
3340 /* Generic handling for UAC tsx completion */
3341 handle_uac_tsx_response(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003342 }
3343}
3344
Benny Prijono8ad55352006-02-08 11:16:05 +00003345/*
3346 * State CONNECTING is after 2xx response to INVITE is sent/received.
3347 */
3348static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003349{
3350 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3351 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3352
3353 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3354
Benny Prijono8ad55352006-02-08 11:16:05 +00003355 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003356
Benny Prijono8ad55352006-02-08 11:16:05 +00003357 /*
3358 * Handle INVITE state progression.
3359 */
Benny Prijono268ca612006-02-07 12:34:11 +00003360 switch (tsx->state) {
3361
3362 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003363 /* It can only go here if incoming ACK request has the same Via
3364 * branch parameter as the INVITE transaction.
3365 */
3366 if (tsx->status_code/100 == 2) {
3367 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3368 inv_check_sdp_in_incoming_msg(inv, tsx,
3369 e->body.tsx_state.src.rdata);
3370 }
3371
Benny Prijono38998232006-02-08 22:44:25 +00003372 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003373 }
Benny Prijono268ca612006-02-07 12:34:11 +00003374 break;
3375
3376 case PJSIP_TSX_STATE_TERMINATED:
3377 /* INVITE transaction can be terminated either because UAC
3378 * transaction received 2xx response or because of transport
3379 * error.
3380 */
3381 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003382 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003383 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003384 }
3385 break;
3386
3387 case PJSIP_TSX_STATE_DESTROYED:
3388 /* Do nothing. */
3389 break;
3390
3391 default:
3392 pj_assert(!"Unexpected state");
3393 }
3394
Benny Prijono8ad55352006-02-08 11:16:05 +00003395 } else if (tsx->role == PJSIP_ROLE_UAS &&
3396 tsx->method.id == PJSIP_BYE_METHOD &&
3397 tsx->status_code < 200 &&
3398 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3399 {
3400
3401 /*
3402 * Handle incoming BYE.
3403 */
3404
3405 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3406
Benny Prijono38998232006-02-08 22:44:25 +00003407 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3408 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003409 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3410 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003411 {
3412
3413 /*
3414 * Outgoing BYE
3415 */
3416 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3417
Benny Prijono268ca612006-02-07 12:34:11 +00003418 }
Benny Prijono70127222006-07-02 14:53:05 +00003419 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3420 tsx->role == PJSIP_ROLE_UAS &&
3421 tsx->status_code < 200 &&
3422 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3423 {
Benny Prijono38998232006-02-08 22:44:25 +00003424
Benny Prijono70127222006-07-02 14:53:05 +00003425 /*
3426 * Handle strandled incoming CANCEL.
3427 */
3428 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3429 pjsip_tx_data *tdata;
3430 pj_status_t status;
3431
3432 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3433 if (status != PJ_SUCCESS) return;
3434
3435 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3436 if (status != PJ_SUCCESS) return;
3437
Benny Prijono1f7767b2007-10-03 18:28:49 +00003438 } else if (tsx->role == PJSIP_ROLE_UAS &&
3439 tsx->state == PJSIP_TSX_STATE_TRYING &&
3440 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3441 {
3442 /*
3443 * Handle incoming UPDATE
3444 */
3445 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3446
3447
3448 } else if (tsx->role == PJSIP_ROLE_UAC &&
3449 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3450 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3451 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3452 {
3453 /*
3454 * Handle response to outgoing UPDATE request.
3455 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003456 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003457 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003458
3459 } else if (tsx->role == PJSIP_ROLE_UAS &&
3460 tsx->state == PJSIP_TSX_STATE_TRYING &&
3461 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3462 {
3463 /*
3464 * Handle incoming PRACK
3465 */
3466 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3467
3468 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono87402382008-02-21 19:28:21 +00003469
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003470 /* Generic handling for UAC tsx completion */
3471 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003472 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003473
Benny Prijono268ca612006-02-07 12:34:11 +00003474}
3475
Benny Prijono8ad55352006-02-08 11:16:05 +00003476/*
3477 * State CONFIRMED is after ACK is sent/received.
3478 */
3479static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003480{
3481 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3482 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3483
3484 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3485
Benny Prijono268ca612006-02-07 12:34:11 +00003486
Benny Prijono8ad55352006-02-08 11:16:05 +00003487 if (tsx->method.id == PJSIP_BYE_METHOD &&
3488 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003489 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3490 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003491 {
Benny Prijono38998232006-02-08 22:44:25 +00003492
Benny Prijono8ad55352006-02-08 11:16:05 +00003493 /*
Benny Prijono38998232006-02-08 22:44:25 +00003494 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003495 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003496
Benny Prijonoa66c7152006-02-09 01:26:14 +00003497 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003498
Benny Prijono8ad55352006-02-08 11:16:05 +00003499 }
3500 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3501 tsx->role == PJSIP_ROLE_UAS &&
3502 tsx->status_code < 200 &&
3503 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3504 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003505
Benny Prijono8ad55352006-02-08 11:16:05 +00003506 /*
3507 * Handle incoming BYE.
3508 */
Benny Prijono268ca612006-02-07 12:34:11 +00003509
Benny Prijono8ad55352006-02-08 11:16:05 +00003510 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3511
Benny Prijono268ca612006-02-07 12:34:11 +00003512 }
Benny Prijono70127222006-07-02 14:53:05 +00003513 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3514 tsx->role == PJSIP_ROLE_UAS &&
3515 tsx->status_code < 200 &&
3516 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3517 {
3518
3519 /*
3520 * Handle strandled incoming CANCEL.
3521 */
3522 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3523 pjsip_tx_data *tdata;
3524 pj_status_t status;
3525
3526 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3527 if (status != PJ_SUCCESS) return;
3528
3529 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3530 if (status != PJ_SUCCESS) return;
3531
3532 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003533 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3534 tsx->role == PJSIP_ROLE_UAS)
3535 {
3536
3537 /*
3538 * Handle incoming re-INVITE
3539 */
3540 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3541
3542 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3543 pjsip_tx_data *tdata;
3544 pj_status_t status;
3545
3546 /* Check if we have INVITE pending. */
3547 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003548 pj_str_t reason;
3549
3550 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003551
3552 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003553 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3554 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003555 if (status != PJ_SUCCESS)
3556 return;
3557
3558 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3559
3560
3561 return;
3562 }
3563
3564 /* Save the invite transaction. */
3565 inv->invite_tsx = tsx;
3566
3567 /* Process SDP in incoming message. */
3568 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3569
3570 if (status != PJ_SUCCESS) {
3571
3572 /* Not Acceptable */
3573 const pjsip_hdr *accept;
3574
3575 status = pjsip_dlg_create_response(inv->dlg, rdata,
3576 488, NULL, &tdata);
3577 if (status != PJ_SUCCESS)
3578 return;
3579
3580
3581 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3582 NULL);
3583 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003584 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003585 pjsip_hdr_clone(tdata->pool, accept));
3586 }
3587
3588 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3589
3590 return;
3591 }
3592
3593 /* Create 2xx ANSWER */
3594 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3595 if (status != PJ_SUCCESS)
3596 return;
3597
Benny Prijono7d910092007-06-20 04:19:46 +00003598 /* If the INVITE request has SDP body, send answer.
3599 * Otherwise generate offer from local active SDP.
3600 */
3601 if (rdata->msg_info.msg->body != NULL) {
3602 status = process_answer(inv, 200, tdata, NULL);
3603 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003604 /* INVITE does not have SDP.
3605 * If on_create_offer() callback is implemented, ask app.
3606 * to generate an offer, otherwise just send active local
3607 * SDP to signal that nothing gets modified.
3608 */
3609 pjmedia_sdp_session *sdp = NULL;
3610
3611 if (mod_inv.cb.on_create_offer) {
3612 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3613 if (sdp) {
3614 status = pjmedia_sdp_neg_modify_local_offer(dlg->pool,
3615 inv->neg,
3616 sdp);
3617 }
3618 }
3619
3620 if (sdp == NULL) {
3621 const pjmedia_sdp_session *active_sdp = NULL;
3622 status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
3623 inv->neg,
3624 &active_sdp);
3625 if (status == PJ_SUCCESS)
3626 sdp = (pjmedia_sdp_session*) active_sdp;
3627 }
3628
3629 if (sdp) {
3630 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003631 }
3632 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003633
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003634 if (status != PJ_SUCCESS) {
3635 /*
3636 * SDP negotiation has failed.
3637 */
3638 pj_status_t rc;
3639 pj_str_t reason;
3640
3641 /* Delete the 2xx answer */
3642 pjsip_tx_data_dec_ref(tdata);
3643
3644 /* Create 500 response */
3645 reason = pj_str("SDP negotiation failed");
3646 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3647 &tdata);
3648 if (rc == PJ_SUCCESS) {
3649 pjsip_warning_hdr *w;
3650 const pj_str_t *endpt_name;
3651
3652 endpt_name = pjsip_endpt_name(dlg->endpt);
3653 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3654 endpt_name,
3655 status);
3656 if (w)
3657 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3658
3659 pjsip_inv_send_msg(inv, tdata);
3660 }
3661 return;
3662 }
3663
3664 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003665 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003666
Benny Prijono7d910092007-06-20 04:19:46 +00003667 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
3668 /* This is the case where ACK has the same branch as
3669 * the INVITE request.
3670 */
3671 if (tsx->status_code/100 == 2 &&
3672 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3673 {
3674 inv_check_sdp_in_incoming_msg(inv, tsx,
3675 e->body.tsx_state.src.rdata);
3676 }
3677
Benny Prijono26ff9062006-02-21 23:47:00 +00003678 }
3679
3680 }
3681 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3682 tsx->role == PJSIP_ROLE_UAC)
3683 {
Benny Prijono22e48c92008-03-20 14:40:50 +00003684
Benny Prijono26ff9062006-02-21 23:47:00 +00003685 /*
3686 * Handle outgoing re-INVITE
3687 */
Benny Prijono22e48c92008-03-20 14:40:50 +00003688 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
3689
Benny Prijono61fc5e62008-06-25 18:35:31 +00003690 /* Must not have other pending INVITE transaction */
3691 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
3692
Benny Prijono22e48c92008-03-20 14:40:50 +00003693 /* Save pending invite transaction */
3694 inv->invite_tsx = tsx;
3695
3696 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
3697 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00003698 {
3699
3700 /* Re-INVITE was accepted. */
3701
3702 /* Process SDP */
3703 inv_check_sdp_in_incoming_msg(inv, tsx,
3704 e->body.tsx_state.src.rdata);
3705
3706 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00003707 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003708
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003709 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00003710
3711 /* Handle response that terminates dialog */
3712 /* Nothing to do (already handled) */
3713
Benny Prijono77998ce2007-06-20 10:03:46 +00003714 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
3715
3716 pjmedia_sdp_neg_state neg_state;
3717
3718 /* Outgoing INVITE transaction has failed, cancel SDP nego */
3719 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
3720 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
3721 pjmedia_sdp_neg_cancel_offer(inv->neg);
3722 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003723 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003724
3725 } else if (tsx->role == PJSIP_ROLE_UAS &&
3726 tsx->state == PJSIP_TSX_STATE_TRYING &&
3727 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3728 {
3729 /*
3730 * Handle incoming UPDATE
3731 */
3732 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3733
3734 } else if (tsx->role == PJSIP_ROLE_UAC &&
3735 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3736 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3737 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3738 {
3739 /*
3740 * Handle response to outgoing UPDATE request.
3741 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003742 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003743 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003744
3745 } else if (tsx->role == PJSIP_ROLE_UAS &&
3746 tsx->state == PJSIP_TSX_STATE_TRYING &&
3747 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3748 {
3749 /*
3750 * Handle strandled incoming PRACK
3751 */
3752 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3753
3754 } else if (tsx->role == PJSIP_ROLE_UAC) {
3755 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003756 * Handle 401/407/408/481 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00003757 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003758 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00003759 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003760
Benny Prijono268ca612006-02-07 12:34:11 +00003761}
3762
Benny Prijono8ad55352006-02-08 11:16:05 +00003763/*
3764 * After session has been terminated, but before dialog is destroyed
3765 * (because dialog has other usages, or because dialog is waiting for
3766 * the last transaction to terminate).
3767 */
3768static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003769{
Benny Prijono8ad55352006-02-08 11:16:05 +00003770 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3771 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00003772
Benny Prijono8ad55352006-02-08 11:16:05 +00003773 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3774
Benny Prijono70127222006-07-02 14:53:05 +00003775 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00003776 tsx->status_code < 200 &&
3777 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3778 {
Benny Prijono70127222006-07-02 14:53:05 +00003779 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00003780
3781 /*
Benny Prijono70127222006-07-02 14:53:05 +00003782 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00003783 */
Benny Prijono70127222006-07-02 14:53:05 +00003784 if (tsx->method.id == PJSIP_BYE_METHOD) {
3785 inv_respond_incoming_bye( inv, tsx, rdata, e );
3786 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
3787 /*
3788 * Respond CANCEL with 200/OK too.
3789 */
3790 pjsip_tx_data *tdata;
3791 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00003792
Benny Prijono70127222006-07-02 14:53:05 +00003793 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3794 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00003795
Benny Prijono70127222006-07-02 14:53:05 +00003796 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3797 if (status != PJ_SUCCESS) return;
3798
3799 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00003800
3801 } else if (tsx->role == PJSIP_ROLE_UAC) {
3802 /*
3803 * Handle 401/407/408/481 response
3804 */
3805 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00003806 }
Benny Prijono268ca612006-02-07 12:34:11 +00003807}
3808