blob: b7130a6c0977338f6ddfc6ec265f6c181d12f0ec [file] [log] [blame]
Benny Prijono268ca612006-02-07 12:34:11 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono268ca612006-02-07 12:34:11 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjsip-ua/sip_inv.h>
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000021#include <pjsip-ua/sip_100rel.h>
Nanang Izzuddin59dffb12009-08-11 12:42:38 +000022#include <pjsip-ua/sip_timer.h>
Benny Prijono268ca612006-02-07 12:34:11 +000023#include <pjsip/sip_module.h>
24#include <pjsip/sip_endpoint.h>
25#include <pjsip/sip_event.h>
Benny Prijono1c1d7342010-08-01 09:48:51 +000026#include <pjsip/sip_multipart.h>
Benny Prijono268ca612006-02-07 12:34:11 +000027#include <pjsip/sip_transaction.h>
28#include <pjmedia/sdp.h>
29#include <pjmedia/sdp_neg.h>
Benny Prijono95196582006-02-09 00:13:40 +000030#include <pjmedia/errno.h>
Benny Prijono268ca612006-02-07 12:34:11 +000031#include <pj/string.h>
32#include <pj/pool.h>
33#include <pj/assert.h>
Benny Prijono8ad55352006-02-08 11:16:05 +000034#include <pj/os.h>
Benny Prijonoa66c7152006-02-09 01:26:14 +000035#include <pj/log.h>
36
Benny Prijono1f7767b2007-10-03 18:28:49 +000037/*
38 * Note on offer/answer:
39 *
40 * The offer/answer framework in this implementation assumes the occurence
41 * of SDP in a particular request/response according to this table:
42
43 offer answer Note:
44 ========================================================================
45 INVITE X INVITE may contain offer
46 18x/INVITE X X Response may contain offer or answer
47 2xx/INVITE X X Response may contain offer or answer
48 ACK X ACK may contain answer
49
50 PRACK X PRACK can only contain answer
51 2xx/PRACK Response may not have offer nor answer
52
53 UPDATE X UPDATE may only contain offer
54 2xx/UPDATE X Response may only contain answer
55 ========================================================================
56
57 *
58 */
Benny Prijono268ca612006-02-07 12:34:11 +000059
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000060#define THIS_FILE "sip_inv.c"
Benny Prijono268ca612006-02-07 12:34:11 +000061
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000062static const char *inv_state_names[] =
63{
Benny Prijono4be63b52006-11-25 14:50:25 +000064 "NULL",
65 "CALLING",
66 "INCOMING",
67 "EARLY",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000068 "CONNECTING",
Benny Prijonoc5055702007-01-13 23:20:18 +000069 "CONFIRMED",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000070 "DISCONNCTD",
71 "TERMINATED",
72};
73
Benny Prijono1f7767b2007-10-03 18:28:49 +000074/* UPDATE method */
Nanang Izzuddin9b93f862009-08-11 18:21:13 +000075static const pjsip_method pjsip_update_method =
Benny Prijono1f7767b2007-10-03 18:28:49 +000076{
77 PJSIP_OTHER_METHOD,
78 { "UPDATE", 6 }
79};
80
Benny Prijono40d62b62009-08-12 17:53:47 +000081#define POOL_INIT_SIZE 256
82#define POOL_INC_SIZE 256
83
Benny Prijono268ca612006-02-07 12:34:11 +000084/*
85 * Static prototypes.
86 */
87static pj_status_t mod_inv_load(pjsip_endpoint *endpt);
88static pj_status_t mod_inv_unload(void);
89static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata);
90static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata);
91static void mod_inv_on_tsx_state(pjsip_transaction*, pjsip_event*);
92
Benny Prijono8ad55352006-02-08 11:16:05 +000093static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e);
94static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e);
95static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e);
96static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e);
97static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e);
98static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e);
99static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e);
Benny Prijono268ca612006-02-07 12:34:11 +0000100
Benny Prijono7d910092007-06-20 04:19:46 +0000101static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
102 pjsip_transaction *tsx,
103 pjsip_rx_data *rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +0000104static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv );
105static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
106 const pjmedia_sdp_session *c_sdp);
Benny Prijono7d910092007-06-20 04:19:46 +0000107static pj_status_t process_answer( pjsip_inv_session *inv,
108 int st_code,
109 pjsip_tx_data *tdata,
110 const pjmedia_sdp_session *local_sdp);
111
Nanang Izzuddincf69c282009-10-16 06:28:56 +0000112static pj_status_t handle_timer_response(pjsip_inv_session *inv,
113 const pjsip_rx_data *rdata,
114 pj_bool_t end_sess_on_failure);
115
Benny Prijono8ad55352006-02-08 11:16:05 +0000116static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
Benny Prijono268ca612006-02-07 12:34:11 +0000117{
118 &inv_on_state_null,
119 &inv_on_state_calling,
120 &inv_on_state_incoming,
121 &inv_on_state_early,
122 &inv_on_state_connecting,
123 &inv_on_state_confirmed,
124 &inv_on_state_disconnected,
Benny Prijono268ca612006-02-07 12:34:11 +0000125};
126
127static struct mod_inv
128{
129 pjsip_module mod;
130 pjsip_endpoint *endpt;
131 pjsip_inv_callback cb;
Benny Prijono268ca612006-02-07 12:34:11 +0000132} mod_inv =
133{
134 {
Benny Prijono2f8992b2006-02-25 21:16:36 +0000135 NULL, NULL, /* prev, next. */
136 { "mod-invite", 10 }, /* Name. */
137 -1, /* Id */
138 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
139 &mod_inv_load, /* load() */
140 NULL, /* start() */
141 NULL, /* stop() */
142 &mod_inv_unload, /* unload() */
143 &mod_inv_on_rx_request, /* on_rx_request() */
144 &mod_inv_on_rx_response, /* on_rx_response() */
145 NULL, /* on_tx_request. */
146 NULL, /* on_tx_response() */
147 &mod_inv_on_tsx_state, /* on_tsx_state() */
Benny Prijono268ca612006-02-07 12:34:11 +0000148 }
149};
150
151
Benny Prijonoa66c7152006-02-09 01:26:14 +0000152/* Invite session data to be attached to transaction. */
153struct tsx_inv_data
154{
Benny Prijono8fcb4332008-10-31 18:01:48 +0000155 pjsip_inv_session *inv; /* The invite session */
156 pj_bool_t sdp_done; /* SDP negotiation done for this tsx? */
157 pj_str_t done_tag; /* To tag in RX response with answer */
158 pj_bool_t done_early;/* Negotiation was done for early med? */
Benny Prijonoa66c7152006-02-09 01:26:14 +0000159};
160
Benny Prijono8ad55352006-02-08 11:16:05 +0000161/*
162 * Module load()
163 */
Benny Prijono268ca612006-02-07 12:34:11 +0000164static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
165{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000166 pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},
167 { "UPDATE", 6}};
Benny Prijono56315612006-07-18 14:39:40 +0000168 pj_str_t accepted = { "application/sdp", 15 };
Benny Prijono268ca612006-02-07 12:34:11 +0000169
Benny Prijono1f7767b2007-10-03 18:28:49 +0000170 /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */
Benny Prijono268ca612006-02-07 12:34:11 +0000171 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
172 PJ_ARRAY_SIZE(allowed), allowed);
173
Benny Prijono56315612006-07-18 14:39:40 +0000174 /* Register "application/sdp" in Accept header */
175 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
176 1, &accepted);
177
Benny Prijono268ca612006-02-07 12:34:11 +0000178 return PJ_SUCCESS;
179}
180
Benny Prijono8ad55352006-02-08 11:16:05 +0000181/*
182 * Module unload()
183 */
Benny Prijono268ca612006-02-07 12:34:11 +0000184static pj_status_t mod_inv_unload(void)
185{
186 /* Should remove capability here */
187 return PJ_SUCCESS;
188}
189
Benny Prijono8ad55352006-02-08 11:16:05 +0000190/*
Benny Prijono38998232006-02-08 22:44:25 +0000191 * Set session state.
192 */
193void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
194 pjsip_event *e)
195{
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000196 pjsip_inv_state prev_state = inv->state;
Benny Prijono7d910092007-06-20 04:19:46 +0000197 pj_status_t status;
198
199
200 /* If state is confirmed, check that SDP negotiation is done,
201 * otherwise disconnect the session.
202 */
203 if (state == PJSIP_INV_STATE_CONFIRMED) {
204 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
205 pjsip_tx_data *bye;
206
207 PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
208 "session"));
209
210 status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
211 NULL, &bye);
212 if (status == PJ_SUCCESS && bye)
213 status = pjsip_inv_send_msg(inv, bye);
214
215 return;
216 }
217 }
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000218
219 /* Set state. */
Benny Prijono38998232006-02-08 22:44:25 +0000220 inv->state = state;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000221
222 /* If state is DISCONNECTED, cause code MUST have been set. */
223 pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
224 inv->cause != 0);
225
226 /* Call on_state_changed() callback. */
227 if (mod_inv.cb.on_state_changed && inv->notify)
Benny Prijono38998232006-02-08 22:44:25 +0000228 (*mod_inv.cb.on_state_changed)(inv, e);
229
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000230 /* Only decrement when previous state is not already DISCONNECTED */
231 if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
232 prev_state != PJSIP_INV_STATE_DISCONNECTED)
233 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000234 if (inv->last_ack) {
235 pjsip_tx_data_dec_ref(inv->last_ack);
236 inv->last_ack = NULL;
237 }
Benny Prijono5e51a4e2008-11-27 00:06:46 +0000238 if (inv->invite_req) {
239 pjsip_tx_data_dec_ref(inv->invite_req);
240 inv->invite_req = NULL;
241 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000242 pjsip_100rel_end_session(inv);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +0000243 pjsip_timer_end_session(inv);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000244 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
Benny Prijono40d62b62009-08-12 17:53:47 +0000245
246 /* Release the flip-flop pools */
247 pj_pool_release(inv->pool_prov);
Benny Prijonobcc8dd72010-02-09 12:28:03 +0000248 inv->pool_prov = NULL;
Benny Prijono40d62b62009-08-12 17:53:47 +0000249 pj_pool_release(inv->pool_active);
Benny Prijonobcc8dd72010-02-09 12:28:03 +0000250 inv->pool_active = NULL;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000251 }
Benny Prijono38998232006-02-08 22:44:25 +0000252}
253
254
255/*
Benny Prijono0b6340c2006-06-13 22:21:23 +0000256 * Set cause code.
257 */
258void inv_set_cause(pjsip_inv_session *inv, int cause_code,
259 const pj_str_t *cause_text)
260{
261 if (cause_code > inv->cause) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000262 inv->cause = (pjsip_status_code) cause_code;
Benny Prijono0b6340c2006-06-13 22:21:23 +0000263 if (cause_text)
264 pj_strdup(inv->pool, &inv->cause_text, cause_text);
265 else if (cause_code/100 == 2)
266 inv->cause_text = pj_str("Normal call clearing");
267 else
268 inv->cause_text = *pjsip_get_status_text(cause_code);
269 }
270}
271
272
Benny Prijono1f7767b2007-10-03 18:28:49 +0000273/*
274 * Check if outgoing request needs to have SDP answer.
275 * This applies for both ACK and PRACK requests.
276 */
Benny Prijono9569a0b2007-10-04 15:35:26 +0000277static const pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv,
278 pjsip_transaction *tsx)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000279{
280 pjmedia_sdp_neg_state neg_state;
Benny Prijono9569a0b2007-10-04 15:35:26 +0000281 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000282 pj_status_t status;
283
284 /* If SDP negotiator is ready, start negotiation. */
285
286 /* Start nego when appropriate. */
287 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
288 PJMEDIA_SDP_NEG_STATE_NULL;
289
290 if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) {
291
292 /* Nothing to do */
293
294 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
295 pjmedia_sdp_neg_has_local_answer(inv->neg) )
296 {
297 struct tsx_inv_data *tsx_inv_data;
Benny Prijonod5f9f422007-11-25 04:40:07 +0000298 struct tsx_inv_data dummy;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000299
Benny Prijonod5f9f422007-11-25 04:40:07 +0000300 /* Get invite session's transaction data.
301 * Note that tsx may be NULL, for example when application sends
302 * delayed ACK request (at this time, the original INVITE
303 * transaction may have been destroyed.
304 */
305 if (tsx) {
306 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
307 } else {
308 tsx_inv_data = &dummy;
309 pj_bzero(&dummy, sizeof(dummy));
310 dummy.inv = inv;
311 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000312
313 status = inv_negotiate_sdp(inv);
314 if (status != PJ_SUCCESS)
315 return NULL;
316
317 /* Mark this transaction has having SDP offer/answer done. */
318 tsx_inv_data->sdp_done = 1;
319
320 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
321
322 } else {
323 /* This remark is only valid for ACK.
324 PJ_LOG(4,(inv->dlg->obj_name,
325 "FYI, the SDP negotiator state (%s) is in a mess "
326 "when sending this ACK/PRACK request",
327 pjmedia_sdp_neg_state_str(neg_state)));
328 */
329 }
330
331 return sdp;
332}
333
Benny Prijono0b6340c2006-06-13 22:21:23 +0000334
335/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000336 * Send ACK for 2xx response.
337 */
Benny Prijonod5f9f422007-11-25 04:40:07 +0000338static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +0000339{
Benny Prijonod5f9f422007-11-25 04:40:07 +0000340 pjsip_rx_data *rdata;
Benny Prijono268ca612006-02-07 12:34:11 +0000341 pj_status_t status;
342
Benny Prijonod5f9f422007-11-25 04:40:07 +0000343 if (e->type == PJSIP_EVENT_TSX_STATE)
344 rdata = e->body.tsx_state.src.rdata;
345 else if (e->type == PJSIP_EVENT_RX_MSG)
346 rdata = e->body.rx_msg.rdata;
347 else {
348 pj_assert(!"Unsupported event type");
349 return PJ_EBUG;
350 }
351
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000352 PJ_LOG(5,(inv->obj_name, "Received %s, sending ACK",
353 pjsip_rx_data_get_info(rdata)));
354
Benny Prijono9a048642010-02-10 08:48:27 +0000355 /* Check if we have cached ACK request. Must not use the cached ACK
356 * if it's still marked as pending by transport (#1011)
357 */
358 if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq &&
359 !inv->last_ack->is_pending)
360 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000361 pjsip_tx_data_add_ref(inv->last_ack);
Benny Prijonod5f9f422007-11-25 04:40:07 +0000362
363 } else if (mod_inv.cb.on_send_ack) {
364 /* If application handles ACK transmission manually, just notify the
365 * callback
366 */
367 PJ_LOG(5,(inv->obj_name, "Received %s, notifying application callback",
368 pjsip_rx_data_get_info(rdata)));
369
370 (*mod_inv.cb.on_send_ack)(inv, rdata);
371 return PJ_SUCCESS;
372
Benny Prijono1f7767b2007-10-03 18:28:49 +0000373 } else {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000374 status = pjsip_inv_create_ack(inv, rdata->msg_info.cseq->cseq,
375 &inv->last_ack);
Benny Prijono268ca612006-02-07 12:34:11 +0000376 }
377
Benny Prijono1f7767b2007-10-03 18:28:49 +0000378 /* Send ACK */
379 status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000380 if (status != PJ_SUCCESS) {
381 /* Better luck next time */
382 pj_assert(!"Unable to send ACK!");
383 return status;
384 }
385
Benny Prijonod5f9f422007-11-25 04:40:07 +0000386
Benny Prijonoe6da48a2008-09-22 14:36:00 +0000387 /* Set state to CONFIRMED (if we're not in CONFIRMED yet).
388 * But don't set it to CONFIRMED if we're already DISCONNECTED
389 * (this may have been a late 200/OK response.
390 */
391 if (inv->state < PJSIP_INV_STATE_CONFIRMED) {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000392 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
393 }
394
Benny Prijono268ca612006-02-07 12:34:11 +0000395 return PJ_SUCCESS;
396}
397
Benny Prijono8ad55352006-02-08 11:16:05 +0000398/*
399 * Module on_rx_request()
400 *
401 * This callback is called for these events:
402 * - endpoint receives request which was unhandled by higher priority
403 * modules (e.g. transaction layer, dialog layer).
404 * - dialog distributes incoming request to its usages.
405 */
406static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
407{
408 pjsip_method *method;
Benny Prijono38998232006-02-08 22:44:25 +0000409 pjsip_dialog *dlg;
410 pjsip_inv_session *inv;
Benny Prijono8ad55352006-02-08 11:16:05 +0000411
412 /* Only wants to receive request from a dialog. */
Benny Prijono38998232006-02-08 22:44:25 +0000413 dlg = pjsip_rdata_get_dlg(rdata);
414 if (dlg == NULL)
Benny Prijono8ad55352006-02-08 11:16:05 +0000415 return PJ_FALSE;
416
Benny Prijonoa1e69682007-05-11 15:14:34 +0000417 inv = (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono38998232006-02-08 22:44:25 +0000418
Benny Prijono8ad55352006-02-08 11:16:05 +0000419 /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
420 * If we need to send response, it will be sent in the state
421 * handlers.
422 */
423 method = &rdata->msg_info.msg->line.req.method;
424
Benny Prijono70127222006-07-02 14:53:05 +0000425 if (method->id == PJSIP_INVITE_METHOD) {
426 return PJ_TRUE;
427 }
428
429 /* BYE and CANCEL must have existing invite session */
430 if (method->id == PJSIP_BYE_METHOD ||
431 method->id == PJSIP_CANCEL_METHOD)
Benny Prijono8ad55352006-02-08 11:16:05 +0000432 {
Benny Prijono70127222006-07-02 14:53:05 +0000433 if (inv == NULL)
434 return PJ_FALSE;
435
Benny Prijono8ad55352006-02-08 11:16:05 +0000436 return PJ_TRUE;
437 }
438
Benny Prijono38998232006-02-08 22:44:25 +0000439 /* On receipt ACK request, when state is CONNECTING,
440 * move state to CONFIRMED.
441 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000442 if (method->id == PJSIP_ACK_METHOD && inv) {
Benny Prijono38998232006-02-08 22:44:25 +0000443
Benny Prijonof521eb02006-08-06 23:07:25 +0000444 /* Ignore ACK if pending INVITE transaction has not finished. */
445 if (inv->invite_tsx &&
446 inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
447 {
448 return PJ_TRUE;
449 }
450
Benny Prijono5eff0432006-02-09 14:14:21 +0000451 /* Terminate INVITE transaction, if it's still present. */
452 if (inv->invite_tsx &&
453 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
454 {
Benny Prijono7d910092007-06-20 04:19:46 +0000455 /* Before we terminate INVITE transaction, process the SDP
Benny Prijono59e9e952008-09-21 22:55:43 +0000456 * in the ACK request, if any.
457 * Only do this when invite state is not already disconnected
458 * (http://trac.pjsip.org/repos/ticket/640).
Benny Prijono7d910092007-06-20 04:19:46 +0000459 */
Benny Prijono59e9e952008-09-21 22:55:43 +0000460 if (inv->state < PJSIP_INV_STATE_DISCONNECTED) {
461 inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
Nanang Izzuddin0fd92672010-06-16 15:26:18 +0000462
463 /* Check if local offer got no SDP answer and INVITE session
464 * is in CONFIRMED state.
465 */
466 if (pjmedia_sdp_neg_get_state(inv->neg)==
467 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
468 inv->state==PJSIP_INV_STATE_CONFIRMED)
469 {
470 pjmedia_sdp_neg_cancel_offer(inv->neg);
471 }
Benny Prijono59e9e952008-09-21 22:55:43 +0000472 }
Benny Prijono7d910092007-06-20 04:19:46 +0000473
474 /* Now we can terminate the INVITE transaction */
Benny Prijonof521eb02006-08-06 23:07:25 +0000475 pj_assert(inv->invite_tsx->status_code >= 200);
Benny Prijono5eff0432006-02-09 14:14:21 +0000476 pjsip_tsx_terminate(inv->invite_tsx,
477 inv->invite_tsx->status_code);
478 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000479 if (inv->last_answer) {
480 pjsip_tx_data_dec_ref(inv->last_answer);
481 inv->last_answer = NULL;
482 }
Benny Prijono5eff0432006-02-09 14:14:21 +0000483 }
484
Benny Prijono32ac8fe2006-03-02 21:16:55 +0000485 /* On receipt of ACK, only set state to confirmed when state
486 * is CONNECTING (e.g. we don't want to set the state to confirmed
487 * when we receive ACK retransmission after sending non-2xx!)
488 */
489 if (inv->state == PJSIP_INV_STATE_CONNECTING) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000490 pjsip_event event;
491
492 PJSIP_EVENT_INIT_RX_MSG(event, rdata);
493 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
494 }
Benny Prijono38998232006-02-08 22:44:25 +0000495 }
496
Benny Prijono8ad55352006-02-08 11:16:05 +0000497 return PJ_FALSE;
498}
499
Nanang Izzuddincf69c282009-10-16 06:28:56 +0000500/* This function will process Session Timer headers in received
501 * 2xx or 422 response of INVITE/UPDATE request.
502 */
503static pj_status_t handle_timer_response(pjsip_inv_session *inv,
504 const pjsip_rx_data *rdata,
505 pj_bool_t end_sess_on_failure)
506{
507 pjsip_status_code st_code;
508 pj_status_t status;
509
510 status = pjsip_timer_process_resp(inv, rdata, &st_code);
511 if (status != PJ_SUCCESS && end_sess_on_failure) {
512 pjsip_tx_data *tdata;
513 pj_status_t status2;
514
515 status2 = pjsip_inv_end_session(inv, st_code, NULL, &tdata);
516 if (tdata && status2 == PJ_SUCCESS)
517 pjsip_inv_send_msg(inv, tdata);
518 }
519
520 return status;
521}
522
Benny Prijono8ad55352006-02-08 11:16:05 +0000523/*
524 * Module on_rx_response().
525 *
526 * This callback is called for these events:
527 * - dialog distributes incoming 2xx response to INVITE (outside
528 * transaction) to its usages.
529 * - endpoint distributes strayed responses.
530 */
Benny Prijono268ca612006-02-07 12:34:11 +0000531static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
532{
533 pjsip_dialog *dlg;
534 pjsip_inv_session *inv;
535 pjsip_msg *msg = rdata->msg_info.msg;
536
537 dlg = pjsip_rdata_get_dlg(rdata);
538
539 /* Ignore responses outside dialog */
540 if (dlg == NULL)
541 return PJ_FALSE;
542
543 /* Ignore responses not belonging to invite session */
544 inv = pjsip_dlg_get_inv_session(dlg);
545 if (inv == NULL)
546 return PJ_FALSE;
547
548 /* This MAY be retransmission of 2xx response to INVITE.
549 * If it is, we need to send ACK.
550 */
551 if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
Benny Prijono26ff9062006-02-21 23:47:00 +0000552 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
553 inv->invite_tsx == NULL)
554 {
Benny Prijonod5f9f422007-11-25 04:40:07 +0000555 pjsip_event e;
Benny Prijono268ca612006-02-07 12:34:11 +0000556
Benny Prijonod5f9f422007-11-25 04:40:07 +0000557 PJSIP_EVENT_INIT_RX_MSG(e, rdata);
558 inv_send_ack(inv, &e);
Benny Prijono268ca612006-02-07 12:34:11 +0000559 return PJ_TRUE;
560
561 }
562
563 /* No other processing needs to be done here. */
564 return PJ_FALSE;
565}
566
Benny Prijono8ad55352006-02-08 11:16:05 +0000567/*
568 * Module on_tsx_state()
569 *
570 * This callback is called by dialog framework for all transactions
571 * inside the dialog for all its dialog usages.
572 */
Benny Prijono268ca612006-02-07 12:34:11 +0000573static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
574{
575 pjsip_dialog *dlg;
576 pjsip_inv_session *inv;
577
578 dlg = pjsip_tsx_get_dlg(tsx);
579 if (dlg == NULL)
580 return;
581
582 inv = pjsip_dlg_get_inv_session(dlg);
583 if (inv == NULL)
584 return;
585
586 /* Call state handler for the invite session. */
587 (*inv_state_handler[inv->state])(inv, e);
588
589 /* Call on_tsx_state */
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000590 if (mod_inv.cb.on_tsx_state_changed && inv->notify)
Benny Prijono268ca612006-02-07 12:34:11 +0000591 (*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
592
Benny Prijono46249942007-02-19 22:23:14 +0000593 /* Clear invite transaction when tsx is confirmed.
594 * Previously we set invite_tsx to NULL only when transaction has
595 * terminated, but this didn't work when ACK has the same Via branch
596 * value as the INVITE (see http://www.pjsip.org/trac/ticket/113)
597 */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000598 if (tsx->state>=PJSIP_TSX_STATE_CONFIRMED && tsx == inv->invite_tsx) {
Benny Prijono46249942007-02-19 22:23:14 +0000599 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000600 if (inv->last_answer) {
601 pjsip_tx_data_dec_ref(inv->last_answer);
602 inv->last_answer = NULL;
603 }
604 }
Benny Prijono268ca612006-02-07 12:34:11 +0000605}
606
Benny Prijono8ad55352006-02-08 11:16:05 +0000607
608/*
609 * Initialize the invite module.
610 */
Benny Prijono268ca612006-02-07 12:34:11 +0000611PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
Benny Prijono268ca612006-02-07 12:34:11 +0000612 const pjsip_inv_callback *cb)
613{
614 pj_status_t status;
615
616 /* Check arguments. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000617 PJ_ASSERT_RETURN(endpt && cb, PJ_EINVAL);
Benny Prijono268ca612006-02-07 12:34:11 +0000618
619 /* Some callbacks are mandatory */
620 PJ_ASSERT_RETURN(cb->on_state_changed && cb->on_new_session, PJ_EINVAL);
621
622 /* Check if module already registered. */
623 PJ_ASSERT_RETURN(mod_inv.mod.id == -1, PJ_EINVALIDOP);
624
625 /* Copy param. */
626 pj_memcpy(&mod_inv.cb, cb, sizeof(pjsip_inv_callback));
627
628 mod_inv.endpt = endpt;
Benny Prijono268ca612006-02-07 12:34:11 +0000629
630 /* Register the module. */
631 status = pjsip_endpt_register_module(endpt, &mod_inv.mod);
Benny Prijono053f5222006-11-11 16:16:04 +0000632 if (status != PJ_SUCCESS)
633 return status;
Benny Prijono268ca612006-02-07 12:34:11 +0000634
Benny Prijono053f5222006-11-11 16:16:04 +0000635 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +0000636}
637
Benny Prijono8ad55352006-02-08 11:16:05 +0000638/*
639 * Get the instance of invite module.
640 */
Benny Prijono268ca612006-02-07 12:34:11 +0000641PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
642{
643 return &mod_inv.mod;
644}
645
646
Benny Prijono632ce712006-02-09 14:01:40 +0000647
Benny Prijono8ad55352006-02-08 11:16:05 +0000648/*
649 * Return the invite session for the specified dialog.
650 */
Benny Prijono268ca612006-02-07 12:34:11 +0000651PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
652{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000653 return (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono268ca612006-02-07 12:34:11 +0000654}
655
Benny Prijono8ad55352006-02-08 11:16:05 +0000656
Benny Prijono268ca612006-02-07 12:34:11 +0000657/*
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000658 * Get INVITE state name.
659 */
660PJ_DEF(const char *) pjsip_inv_state_name(pjsip_inv_state state)
661{
662 PJ_ASSERT_RETURN(state >= PJSIP_INV_STATE_NULL &&
663 state <= PJSIP_INV_STATE_DISCONNECTED,
664 "??");
665
666 return inv_state_names[state];
667}
668
669/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000670 * Create UAC invite session.
Benny Prijono268ca612006-02-07 12:34:11 +0000671 */
672PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
673 const pjmedia_sdp_session *local_sdp,
674 unsigned options,
675 pjsip_inv_session **p_inv)
676{
677 pjsip_inv_session *inv;
678 pj_status_t status;
679
680 /* Verify arguments. */
681 PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
682
Benny Prijono8eae8382006-08-10 21:44:26 +0000683 /* Must lock dialog first */
684 pjsip_dlg_inc_lock(dlg);
685
Benny Prijono268ca612006-02-07 12:34:11 +0000686 /* Normalize options */
687 if (options & PJSIP_INV_REQUIRE_100REL)
688 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000689 if (options & PJSIP_INV_REQUIRE_TIMER)
690 options |= PJSIP_INV_SUPPORT_TIMER;
691
692 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000693 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +0000694 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000695
696 inv->pool = dlg->pool;
697 inv->role = PJSIP_ROLE_UAC;
698 inv->state = PJSIP_INV_STATE_NULL;
699 inv->dlg = dlg;
700 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000701 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000702 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +0000703
Benny Prijono40d62b62009-08-12 17:53:47 +0000704 /* Create flip-flop pool (see ticket #877) */
705 /* (using inv->obj_name as temporary variable for pool names */
706 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg->pool);
707 inv->pool_prov = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
708 POOL_INIT_SIZE, POOL_INC_SIZE);
709 inv->pool_active = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
710 POOL_INIT_SIZE, POOL_INC_SIZE);
711
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000712 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +0000713 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000714
Benny Prijono268ca612006-02-07 12:34:11 +0000715 /* Create negotiator if local_sdp is specified. */
716 if (local_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +0000717 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
718 local_sdp, &inv->neg);
Benny Prijono8eae8382006-08-10 21:44:26 +0000719 if (status != PJ_SUCCESS) {
720 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000721 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000722 }
Benny Prijono268ca612006-02-07 12:34:11 +0000723 }
724
725 /* Register invite as dialog usage. */
726 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +0000727 if (status != PJ_SUCCESS) {
728 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000729 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000730 }
Benny Prijono268ca612006-02-07 12:34:11 +0000731
732 /* Increment dialog session */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000733 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +0000734
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000735 /* Create 100rel handler */
736 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000737
Benny Prijono268ca612006-02-07 12:34:11 +0000738 /* Done */
739 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000740
Benny Prijono8eae8382006-08-10 21:44:26 +0000741 pjsip_dlg_dec_lock(dlg);
742
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000743 PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
744 dlg->obj_name));
745
Benny Prijono268ca612006-02-07 12:34:11 +0000746 return PJ_SUCCESS;
747}
748
Benny Prijono1c1d7342010-08-01 09:48:51 +0000749PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata)
750{
751 pjsip_rdata_sdp_info *sdp_info;
752 pjsip_msg_body *body = rdata->msg_info.msg->body;
753 pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype;
754 pjsip_media_type app_sdp;
755
756 sdp_info = (pjsip_rdata_sdp_info*)
757 rdata->endpt_info.mod_data[mod_inv.mod.id];
758 if (sdp_info)
759 return sdp_info;
760
761 sdp_info = PJ_POOL_ZALLOC_T(rdata->tp_info.pool,
762 pjsip_rdata_sdp_info);
763 PJ_ASSERT_RETURN(mod_inv.mod.id >= 0, sdp_info);
764 rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info;
765
766 pjsip_media_type_init2(&app_sdp, "application", "sdp");
767
768 if (body && ctype_hdr &&
769 pj_stricmp(&ctype_hdr->media.type, &app_sdp.type)==0 &&
770 pj_stricmp(&ctype_hdr->media.subtype, &app_sdp.subtype)==0)
771 {
772 sdp_info->body.ptr = (char*)body->data;
773 sdp_info->body.slen = body->len;
774 } else if (body && ctype_hdr &&
775 pj_stricmp2(&ctype_hdr->media.type, "multipart")==0 &&
776 (pj_stricmp2(&ctype_hdr->media.subtype, "mixed")==0 ||
777 pj_stricmp2(&ctype_hdr->media.subtype, "alternative")==0))
778 {
779 pjsip_multipart_part *part;
780
781 part = pjsip_multipart_find_part(body, &app_sdp, NULL);
782 if (part) {
783 sdp_info->body.ptr = (char*)part->body->data;
784 sdp_info->body.slen = part->body->len;
785 }
786 }
787
788 if (sdp_info->body.ptr) {
789 pj_status_t status;
790 status = pjmedia_sdp_parse(rdata->tp_info.pool,
791 sdp_info->body.ptr,
792 sdp_info->body.slen,
793 &sdp_info->sdp);
794 if (status == PJ_SUCCESS)
795 status = pjmedia_sdp_validate(sdp_info->sdp);
796
797 if (status != PJ_SUCCESS) {
798 sdp_info->sdp = NULL;
799 PJ_PERROR(1,(THIS_FILE, status,
800 "Error parsing/validating SDP body"));
801 }
802
803 sdp_info->sdp_err = status;
804 }
805
806 return sdp_info;
807}
808
809
Benny Prijono268ca612006-02-07 12:34:11 +0000810/*
811 * Verify incoming INVITE request.
812 */
Benny Prijono87a90212008-01-23 20:29:30 +0000813PJ_DEF(pj_status_t) pjsip_inv_verify_request2(pjsip_rx_data *rdata,
814 unsigned *options,
815 const pjmedia_sdp_session *r_sdp,
816 const pjmedia_sdp_session *l_sdp,
817 pjsip_dialog *dlg,
818 pjsip_endpoint *endpt,
819 pjsip_tx_data **p_tdata)
Benny Prijono268ca612006-02-07 12:34:11 +0000820{
821 pjsip_msg *msg;
822 pjsip_allow_hdr *allow;
823 pjsip_supported_hdr *sup_hdr;
824 pjsip_require_hdr *req_hdr;
Benny Prijono8b33bba2010-06-02 03:03:43 +0000825 pjsip_contact_hdr *c_hdr;
Benny Prijono268ca612006-02-07 12:34:11 +0000826 int code = 200;
827 unsigned rem_option = 0;
828 pj_status_t status = PJ_SUCCESS;
829 pjsip_hdr res_hdr_list;
Benny Prijono1c1d7342010-08-01 09:48:51 +0000830 pjsip_rdata_sdp_info *sdp_info;
Benny Prijono268ca612006-02-07 12:34:11 +0000831
832 /* Init return arguments. */
833 if (p_tdata) *p_tdata = NULL;
834
835 /* Verify arguments. */
836 PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);
837
838 /* Normalize options */
839 if (*options & PJSIP_INV_REQUIRE_100REL)
840 *options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +0000841 if (*options & PJSIP_INV_REQUIRE_TIMER)
842 *options |= PJSIP_INV_SUPPORT_TIMER;
Benny Prijono07fe2302010-06-24 12:33:18 +0000843 if (*options & PJSIP_INV_REQUIRE_ICE)
844 *options |= PJSIP_INV_SUPPORT_ICE;
Benny Prijono268ca612006-02-07 12:34:11 +0000845
846 /* Get the message in rdata */
847 msg = rdata->msg_info.msg;
848
849 /* Must be INVITE request. */
850 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
851 msg->line.req.method.id == PJSIP_INVITE_METHOD,
852 PJ_EINVAL);
853
854 /* If tdata is specified, then either dlg or endpt must be specified */
855 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
856
857 /* Get the endpoint */
858 endpt = endpt ? endpt : dlg->endpt;
859
860 /* Init response header list */
861 pj_list_init(&res_hdr_list);
862
Benny Prijono8b33bba2010-06-02 03:03:43 +0000863 /* Check the Contact header */
864 c_hdr = (pjsip_contact_hdr*)
865 pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
866 if (!c_hdr || !c_hdr->uri) {
867 /* Missing Contact header or Contact contains "*" */
868 pjsip_warning_hdr *w;
869 pj_str_t warn_text;
870
871 warn_text = pj_str("Bad/missing Contact header");
872 w = pjsip_warning_hdr_create(rdata->tp_info.pool, 399,
873 pjsip_endpt_name(endpt),
874 &warn_text);
875 if (w) {
876 pj_list_push_back(&res_hdr_list, w);
877 }
878
879 code = PJSIP_SC_BAD_REQUEST;
880 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
881 goto on_return;
882 }
883
Benny Prijono87a90212008-01-23 20:29:30 +0000884 /* Check the request body, see if it's something that we support,
885 * only when the body hasn't been parsed before.
Benny Prijono268ca612006-02-07 12:34:11 +0000886 */
Benny Prijono1c1d7342010-08-01 09:48:51 +0000887 if (r_sdp == NULL) {
888 sdp_info = pjsip_rdata_get_sdp_info(rdata);
889 } else {
890 sdp_info = NULL;
891 }
Benny Prijono268ca612006-02-07 12:34:11 +0000892
Benny Prijono1c1d7342010-08-01 09:48:51 +0000893 if (r_sdp==NULL && msg->body) {
894
895 /* Check if body really contains SDP. */
896 if (sdp_info->body.ptr == NULL) {
897 /* Couldn't find "application/sdp" */
Benny Prijono268ca612006-02-07 12:34:11 +0000898 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
899 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
900
901 if (p_tdata) {
902 /* Add Accept header to response */
903 pjsip_accept_hdr *acc;
904
905 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
906 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
907 acc->values[acc->count++] = pj_str("application/sdp");
908 pj_list_push_back(&res_hdr_list, acc);
909 }
910
911 goto on_return;
912 }
913
Benny Prijono1c1d7342010-08-01 09:48:51 +0000914 if (sdp_info->sdp_err != PJ_SUCCESS) {
Benny Prijono268ca612006-02-07 12:34:11 +0000915 /* Unparseable or invalid SDP */
916 code = PJSIP_SC_BAD_REQUEST;
917
918 if (p_tdata) {
919 /* Add Warning header. */
920 pjsip_warning_hdr *w;
921
922 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
923 pjsip_endpt_name(endpt),
Benny Prijono1c1d7342010-08-01 09:48:51 +0000924 sdp_info->sdp_err);
Benny Prijono268ca612006-02-07 12:34:11 +0000925 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
926
927 pj_list_push_back(&res_hdr_list, w);
928 }
929
930 goto on_return;
931 }
932
Benny Prijono1c1d7342010-08-01 09:48:51 +0000933 r_sdp = sdp_info->sdp;
Benny Prijono87a90212008-01-23 20:29:30 +0000934 }
935
936 if (r_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +0000937 /* Negotiate with local SDP */
938 if (l_sdp) {
939 pjmedia_sdp_neg *neg;
940
941 /* Local SDP must be valid! */
942 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
943 status);
944
945 /* Create SDP negotiator */
946 status = pjmedia_sdp_neg_create_w_remote_offer(
Benny Prijono87a90212008-01-23 20:29:30 +0000947 rdata->tp_info.pool, l_sdp, r_sdp, &neg);
Benny Prijono268ca612006-02-07 12:34:11 +0000948 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
949
950 /* Negotiate SDP */
951 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
952 if (status != PJ_SUCCESS) {
953
954 /* Incompatible media */
955 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000956
957 if (p_tdata) {
958 pjsip_accept_hdr *acc;
959 pjsip_warning_hdr *w;
960
961 /* Add Warning header. */
962 w = pjsip_warning_hdr_create_from_status(
963 rdata->tp_info.pool,
964 pjsip_endpt_name(endpt), status);
965 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
966
967 pj_list_push_back(&res_hdr_list, w);
968
969 /* Add Accept header to response */
970 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
971 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
972 acc->values[acc->count++] = pj_str("application/sdp");
973 pj_list_push_back(&res_hdr_list, acc);
974
975 }
976
977 goto on_return;
978 }
979 }
980 }
981
982 /* Check supported methods, see if peer supports UPDATE.
983 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
984 * implicitly by sending this INVITE.
985 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000986 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000987 if (allow) {
988 unsigned i;
989 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
990
991 for (i=0; i<allow->count; ++i) {
992 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
993 break;
994 }
995
996 if (i != allow->count) {
997 /* UPDATE is present in Allow */
998 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
999 }
1000
1001 }
1002
1003 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001004 sup_hdr = (pjsip_supported_hdr*)
1005 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001006 if (sup_hdr) {
1007 unsigned i;
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001008 const pj_str_t STR_100REL = { "100rel", 6};
1009 const pj_str_t STR_TIMER = { "timer", 5};
Benny Prijono07fe2302010-06-24 12:33:18 +00001010 const pj_str_t STR_ICE = { "ice", 3 };
Benny Prijono268ca612006-02-07 12:34:11 +00001011
1012 for (i=0; i<sup_hdr->count; ++i) {
1013 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
1014 rem_option |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono07fe2302010-06-24 12:33:18 +00001015 else if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +00001016 rem_option |= PJSIP_INV_SUPPORT_TIMER;
Benny Prijono07fe2302010-06-24 12:33:18 +00001017 else if (pj_stricmp(&sup_hdr->values[i], &STR_ICE)==0)
1018 rem_option |= PJSIP_INV_SUPPORT_ICE;
Benny Prijono268ca612006-02-07 12:34:11 +00001019 }
1020 }
1021
1022 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001023 req_hdr = (pjsip_require_hdr*)
1024 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001025 if (req_hdr) {
1026 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +00001027 const pj_str_t STR_100REL = { "100rel", 6};
Benny Prijono053f5222006-11-11 16:16:04 +00001028 const pj_str_t STR_REPLACES = { "replaces", 8 };
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001029 const pj_str_t STR_TIMER = { "timer", 5 };
Benny Prijono07fe2302010-06-24 12:33:18 +00001030 const pj_str_t STR_ICE = { "ice", 3 };
Benny Prijono268ca612006-02-07 12:34:11 +00001031 unsigned unsupp_cnt = 0;
1032 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
1033
1034 for (i=0; i<req_hdr->count; ++i) {
1035 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
1036 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
1037 {
1038 rem_option |= PJSIP_INV_REQUIRE_100REL;
1039
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001040 } else if ((*options & PJSIP_INV_SUPPORT_TIMER) &&
1041 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
Benny Prijono268ca612006-02-07 12:34:11 +00001042 {
1043 rem_option |= PJSIP_INV_REQUIRE_TIMER;
1044
Benny Prijono053f5222006-11-11 16:16:04 +00001045 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
1046 pj_bool_t supp;
1047
1048 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
1049 NULL, &STR_REPLACES);
1050 if (!supp)
1051 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
Benny Prijono07fe2302010-06-24 12:33:18 +00001052 } else if ((*options & PJSIP_INV_SUPPORT_ICE) &&
1053 pj_stricmp(&req_hdr->values[i], &STR_ICE)==0)
1054 {
1055 rem_option |= PJSIP_INV_REQUIRE_ICE;
Benny Prijono053f5222006-11-11 16:16:04 +00001056
Nanang Izzuddin5d5a20e2009-08-06 16:04:20 +00001057 } else if (!pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
1058 NULL, &req_hdr->values[i]))
1059 {
Benny Prijono268ca612006-02-07 12:34:11 +00001060 /* Unknown/unsupported extension tag! */
1061 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
1062 }
1063 }
1064
1065 /* Check if there are required tags that we don't support */
1066 if (unsupp_cnt) {
1067
1068 code = PJSIP_SC_BAD_EXTENSION;
1069 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1070
1071 if (p_tdata) {
1072 pjsip_unsupported_hdr *unsupp_hdr;
1073 const pjsip_hdr *h;
1074
1075 /* Add Unsupported header. */
1076 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
1077 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
1078
1079 unsupp_hdr->count = unsupp_cnt;
1080 for (i=0; i<unsupp_cnt; ++i)
1081 unsupp_hdr->values[i] = unsupp_tags[i];
1082
1083 pj_list_push_back(&res_hdr_list, unsupp_hdr);
1084
1085 /* Add Supported header. */
1086 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
1087 NULL);
1088 pj_assert(h);
1089 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001090 sup_hdr = (pjsip_supported_hdr*)
1091 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001092 pj_list_push_back(&res_hdr_list, sup_hdr);
1093 }
1094 }
1095
1096 goto on_return;
1097 }
1098 }
1099
1100 /* Check if there are local requirements that are not supported
1101 * by peer.
1102 */
1103 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
1104 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
Nanang Izzuddin65add622009-08-11 16:26:20 +00001105 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
1106 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
Benny Prijono268ca612006-02-07 12:34:11 +00001107 {
1108 code = PJSIP_SC_EXTENSION_REQUIRED;
1109 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1110
1111 if (p_tdata) {
1112 const pjsip_hdr *h;
1113
1114 /* Add Require header. */
1115 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
1116 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
1117
1118 if (*options & PJSIP_INV_REQUIRE_100REL)
1119 req_hdr->values[req_hdr->count++] = pj_str("100rel");
Benny Prijono268ca612006-02-07 12:34:11 +00001120 if (*options & PJSIP_INV_REQUIRE_TIMER)
1121 req_hdr->values[req_hdr->count++] = pj_str("timer");
1122
1123 pj_list_push_back(&res_hdr_list, req_hdr);
1124
1125 /* Add Supported header. */
1126 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
1127 NULL);
1128 pj_assert(h);
1129 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001130 sup_hdr = (pjsip_supported_hdr*)
1131 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001132 pj_list_push_back(&res_hdr_list, sup_hdr);
1133 }
1134
1135 }
1136
1137 goto on_return;
1138 }
1139
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001140 /* If remote Require something that we support, make us Require
1141 * that feature too.
1142 */
1143 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
1144 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
1145 *options |= PJSIP_INV_REQUIRE_100REL;
1146 }
1147 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
1148 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
1149 *options |= PJSIP_INV_REQUIRE_TIMER;
1150 }
1151
Benny Prijono268ca612006-02-07 12:34:11 +00001152on_return:
1153
1154 /* Create response if necessary */
1155 if (code != 200 && p_tdata) {
1156 pjsip_tx_data *tdata;
1157 const pjsip_hdr *h;
1158
1159 if (dlg) {
1160 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
1161 &tdata);
1162 } else {
1163 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
1164 &tdata);
1165 }
1166
1167 if (status != PJ_SUCCESS)
1168 return status;
1169
1170 /* Add response headers. */
1171 h = res_hdr_list.next;
1172 while (h != &res_hdr_list) {
1173 pjsip_hdr *cloned;
1174
Benny Prijonoa1e69682007-05-11 15:14:34 +00001175 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +00001176 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
1177
1178 pjsip_msg_add_hdr(tdata->msg, cloned);
1179
1180 h = h->next;
1181 }
1182
1183 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001184
1185 /* Can not return PJ_SUCCESS when response message is produced.
1186 * Ref: PROTOS test ~#2490
1187 */
1188 if (status == PJ_SUCCESS)
1189 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1190
Benny Prijono268ca612006-02-07 12:34:11 +00001191 }
1192
1193 return status;
1194}
1195
Benny Prijono87a90212008-01-23 20:29:30 +00001196
1197/*
1198 * Verify incoming INVITE request.
1199 */
1200PJ_DEF(pj_status_t) pjsip_inv_verify_request( pjsip_rx_data *rdata,
1201 unsigned *options,
1202 const pjmedia_sdp_session *l_sdp,
1203 pjsip_dialog *dlg,
1204 pjsip_endpoint *endpt,
1205 pjsip_tx_data **p_tdata)
1206{
1207 return pjsip_inv_verify_request2(rdata, options, NULL, l_sdp, dlg,
1208 endpt, p_tdata);
1209}
1210
Benny Prijono268ca612006-02-07 12:34:11 +00001211/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001212 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001213 */
1214PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1215 pjsip_rx_data *rdata,
1216 const pjmedia_sdp_session *local_sdp,
1217 unsigned options,
1218 pjsip_inv_session **p_inv)
1219{
1220 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001221 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001222 pjsip_msg *msg;
Benny Prijono1c1d7342010-08-01 09:48:51 +00001223 pjsip_rdata_sdp_info *sdp_info;
Benny Prijono268ca612006-02-07 12:34:11 +00001224 pj_status_t status;
1225
1226 /* Verify arguments. */
1227 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1228
1229 /* Dialog MUST have been initialised. */
1230 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1231
1232 msg = rdata->msg_info.msg;
1233
1234 /* rdata MUST contain INVITE request */
1235 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1236 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1237 PJ_EINVALIDOP);
1238
Benny Prijono8eae8382006-08-10 21:44:26 +00001239 /* Lock dialog */
1240 pjsip_dlg_inc_lock(dlg);
1241
Benny Prijono268ca612006-02-07 12:34:11 +00001242 /* Normalize options */
1243 if (options & PJSIP_INV_REQUIRE_100REL)
1244 options |= PJSIP_INV_SUPPORT_100REL;
Benny Prijono268ca612006-02-07 12:34:11 +00001245 if (options & PJSIP_INV_REQUIRE_TIMER)
1246 options |= PJSIP_INV_SUPPORT_TIMER;
1247
1248 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001249 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001250 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001251
1252 inv->pool = dlg->pool;
1253 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001254 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001255 inv->dlg = dlg;
1256 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001257 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001258 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001259
Benny Prijono40d62b62009-08-12 17:53:47 +00001260 /* Create flip-flop pool (see ticket #877) */
1261 /* (using inv->obj_name as temporary variable for pool names */
1262 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg->pool);
1263 inv->pool_prov = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1264 POOL_INIT_SIZE, POOL_INC_SIZE);
1265 inv->pool_active = pjsip_endpt_create_pool(dlg->endpt, inv->obj_name,
1266 POOL_INIT_SIZE, POOL_INC_SIZE);
1267
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001268 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001269 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001270
Benny Prijono1c1d7342010-08-01 09:48:51 +00001271 /* Process SDP in message body, if present. */
1272 sdp_info = pjsip_rdata_get_sdp_info(rdata);
1273 if (sdp_info->sdp_err) {
1274 pjsip_dlg_dec_lock(dlg);
1275 return sdp_info->sdp_err;
Benny Prijono268ca612006-02-07 12:34:11 +00001276 }
1277
1278 /* Create negotiator. */
Benny Prijono1c1d7342010-08-01 09:48:51 +00001279 if (sdp_info->sdp) {
1280 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp,
1281 sdp_info->sdp,
Benny Prijono40d62b62009-08-12 17:53:47 +00001282 &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001283
1284 } else if (local_sdp) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001285 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1286 local_sdp, &inv->neg);
Benny Prijono268ca612006-02-07 12:34:11 +00001287 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001288 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001289 }
1290
Benny Prijono8eae8382006-08-10 21:44:26 +00001291 if (status != PJ_SUCCESS) {
1292 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001293 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001294 }
Benny Prijono268ca612006-02-07 12:34:11 +00001295
1296 /* Register invite as dialog usage. */
1297 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001298 if (status != PJ_SUCCESS) {
1299 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001300 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001301 }
Benny Prijono268ca612006-02-07 12:34:11 +00001302
1303 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001304 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001305
1306 /* Save the invite transaction. */
1307 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001308
1309 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001310 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001311 tsx_inv_data->inv = inv;
1312 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001313
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001314 /* Create 100rel handler */
1315 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001316 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001317 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001318
Benny Prijono268ca612006-02-07 12:34:11 +00001319 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001320 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001321 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001322
1323 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1324 dlg->obj_name));
1325
Benny Prijono268ca612006-02-07 12:34:11 +00001326 return PJ_SUCCESS;
1327}
1328
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001329/*
1330 * Forcefully terminate the session.
1331 */
1332PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1333 int st_code,
1334 pj_bool_t notify)
1335{
1336 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1337
1338 /* Lock dialog. */
1339 pjsip_dlg_inc_lock(inv->dlg);
1340
1341 /* Set callback notify flag. */
1342 inv->notify = notify;
1343
1344 /* If there's pending transaction, terminate the transaction.
1345 * This may subsequently set the INVITE session state to
1346 * disconnected.
1347 */
1348 if (inv->invite_tsx &&
1349 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1350 {
1351 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1352
1353 }
1354
1355 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001356 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001357
1358 /* Forcefully terminate the session if state is not DISCONNECTED */
1359 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1360 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1361 }
1362
1363 /* Done.
1364 * The dec_lock() below will actually destroys the dialog if it
1365 * has no other session.
1366 */
1367 pjsip_dlg_dec_lock(inv->dlg);
1368
1369 return PJ_SUCCESS;
1370}
1371
1372
Benny Prijono5e51a4e2008-11-27 00:06:46 +00001373/*
1374 * Restart UAC session, possibly because app or us wants to re-send the
1375 * INVITE request due to 401/407 challenge or 3xx response.
1376 */
1377PJ_DEF(pj_status_t) pjsip_inv_uac_restart(pjsip_inv_session *inv,
1378 pj_bool_t new_offer)
1379{
1380 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1381
1382 inv->state = PJSIP_INV_STATE_NULL;
1383 inv->invite_tsx = NULL;
1384 if (inv->last_answer) {
1385 pjsip_tx_data_dec_ref(inv->last_answer);
1386 inv->last_answer = NULL;
1387 }
1388
1389 if (new_offer && inv->neg) {
1390 pjmedia_sdp_neg_state neg_state;
1391
1392 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1393 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1394 pjmedia_sdp_neg_cancel_offer(inv->neg);
1395 }
1396 }
1397
1398 return PJ_SUCCESS;
1399}
1400
1401
Benny Prijono268ca612006-02-07 12:34:11 +00001402static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1403{
1404 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001405 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001406}
1407
1408static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1409{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001410 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001411}
1412
Benny Prijono56315612006-07-18 14:39:40 +00001413
1414PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1415 pjmedia_sdp_session *sdp,
1416 pjsip_msg_body **p_body)
1417{
1418 const pj_str_t STR_APPLICATION = { "application", 11};
1419 const pj_str_t STR_SDP = { "sdp", 3 };
1420 pjsip_msg_body *body;
1421
Benny Prijonoa1e69682007-05-11 15:14:34 +00001422 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001423 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1424
Benny Prijono1c1d7342010-08-01 09:48:51 +00001425 pjsip_media_type_init(&body->content_type, (pj_str_t*)&STR_APPLICATION,
1426 (pj_str_t*)&STR_SDP);
Benny Prijono56315612006-07-18 14:39:40 +00001427 body->data = sdp;
1428 body->len = 0;
1429 body->clone_data = &clone_sdp;
1430 body->print_body = &print_sdp;
1431
1432 *p_body = body;
1433
1434 return PJ_SUCCESS;
1435}
1436
Benny Prijono268ca612006-02-07 12:34:11 +00001437static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1438 const pjmedia_sdp_session *c_sdp)
1439{
1440 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001441 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001442
Benny Prijono56315612006-07-18 14:39:40 +00001443 status = pjsip_create_sdp_body(pool,
1444 pjmedia_sdp_session_clone(pool, c_sdp),
1445 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001446
Benny Prijono56315612006-07-18 14:39:40 +00001447 if (status != PJ_SUCCESS)
1448 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001449
1450 return body;
1451}
1452
1453/*
1454 * Create initial INVITE request.
1455 */
1456PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1457 pjsip_tx_data **p_tdata )
1458{
1459 pjsip_tx_data *tdata;
1460 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001461 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001462 pj_status_t status;
1463
1464 /* Verify arguments. */
1465 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1466
Benny Prijono26ff9062006-02-21 23:47:00 +00001467 /* State MUST be NULL or CONFIRMED. */
1468 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1469 inv->state == PJSIP_INV_STATE_CONFIRMED,
1470 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001471
Benny Prijono64f851e2006-02-23 13:49:28 +00001472 /* Lock dialog. */
1473 pjsip_dlg_inc_lock(inv->dlg);
1474
Benny Prijono268ca612006-02-07 12:34:11 +00001475 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001476 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001477 &tdata);
1478 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001479 goto on_return;
1480
Benny Prijono268ca612006-02-07 12:34:11 +00001481
Benny Prijono26ff9062006-02-21 23:47:00 +00001482 /* If this is the first INVITE, then copy the headers from inv_hdr.
1483 * These are the headers parsed from the request URI when the
1484 * dialog was created.
1485 */
1486 if (inv->state == PJSIP_INV_STATE_NULL) {
1487 hdr = inv->dlg->inv_hdr.next;
1488
1489 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001490 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001491 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1492 hdr = hdr->next;
1493 }
1494 }
1495
1496 /* See if we have SDP to send. */
1497 if (inv->neg) {
1498 pjmedia_sdp_neg_state neg_state;
1499
1500 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1501
1502 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1503 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1504 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1505
1506
1507 } else {
1508 has_sdp = PJ_FALSE;
1509 }
1510
Benny Prijono268ca612006-02-07 12:34:11 +00001511 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001512 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001513 const pjmedia_sdp_session *offer;
1514
1515 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono176a11f2009-04-14 11:14:51 +00001516 if (status != PJ_SUCCESS) {
1517 pjsip_tx_data_dec_ref(tdata);
Benny Prijono64f851e2006-02-23 13:49:28 +00001518 goto on_return;
Benny Prijono176a11f2009-04-14 11:14:51 +00001519 }
Benny Prijono268ca612006-02-07 12:34:11 +00001520
1521 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1522 }
1523
1524 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001525 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001526 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1527 if (hdr) {
1528 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1529 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1530 }
Benny Prijono268ca612006-02-07 12:34:11 +00001531 }
1532
1533 /* Add Supported header */
1534 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1535 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001536 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001537 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1538 }
1539
1540 /* Add Require header. */
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001541 if ((inv->options & PJSIP_INV_REQUIRE_100REL) ||
1542 (inv->options & PJSIP_INV_REQUIRE_TIMER))
1543 {
1544 pjsip_require_hdr *hreq;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001545
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001546 hreq = pjsip_require_hdr_create(tdata->pool);
1547
1548 if (inv->options & PJSIP_INV_REQUIRE_100REL)
1549 hreq->values[hreq->count++] = pj_str("100rel");
1550 if (inv->options & PJSIP_INV_REQUIRE_TIMER)
1551 hreq->values[hreq->count++] = pj_str("timer");
1552
1553 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001554 }
Benny Prijono268ca612006-02-07 12:34:11 +00001555
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001556 status = pjsip_timer_update_req(inv, tdata);
1557 if (status != PJ_SUCCESS)
1558 goto on_return;
1559
Benny Prijono268ca612006-02-07 12:34:11 +00001560 /* Done. */
1561 *p_tdata = tdata;
1562
Benny Prijono64f851e2006-02-23 13:49:28 +00001563
1564on_return:
1565 pjsip_dlg_dec_lock(inv->dlg);
1566 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001567}
1568
1569
Benny Prijono40d62b62009-08-12 17:53:47 +00001570/* Util: swap pool */
1571static void swap_pool(pj_pool_t **p1, pj_pool_t **p2)
1572{
1573 pj_pool_t *tmp = *p1;
1574 *p1 = *p2;
1575 *p2 = tmp;
1576}
1577
Benny Prijono1c1d7342010-08-01 09:48:51 +00001578
Benny Prijono268ca612006-02-07 12:34:11 +00001579/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001580 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001581 */
1582static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1583{
1584 pj_status_t status;
1585
1586 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1587 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1588 PJMEDIA_SDPNEG_EINSTATE);
1589
Benny Prijono40d62b62009-08-12 17:53:47 +00001590 status = pjmedia_sdp_neg_negotiate(inv->pool_prov, inv->neg, 0);
Benny Prijono95196582006-02-09 00:13:40 +00001591
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001592 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1593
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001594 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001595 (*mod_inv.cb.on_media_update)(inv, status);
1596
Benny Prijonobcc8dd72010-02-09 12:28:03 +00001597 /* Invite session may have been terminated by the application even
1598 * after a successful SDP negotiation, for example when no audio
1599 * codec is present in the offer (see ticket #1034).
1600 */
1601 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Nanang Izzuddin756da442009-08-14 13:23:22 +00001602
Benny Prijonobcc8dd72010-02-09 12:28:03 +00001603 /* Swap the flip-flop pool when SDP negotiation success. */
1604 if (status == PJ_SUCCESS) {
1605 swap_pool(&inv->pool_prov, &inv->pool_active);
1606 }
1607
1608 /* Reset the provisional pool regardless SDP negotiation result. */
1609 pj_pool_reset(inv->pool_prov);
1610
1611 } else {
1612
1613 status = PJSIP_ERRNO_FROM_SIP_STATUS(inv->cause);
1614 }
Benny Prijono40d62b62009-08-12 17:53:47 +00001615
Benny Prijono95196582006-02-09 00:13:40 +00001616 return status;
1617}
1618
1619/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001620 * Check in incoming message for SDP offer/answer.
1621 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001622static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1623 pjsip_transaction *tsx,
1624 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001625{
1626 struct tsx_inv_data *tsx_inv_data;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001627 pj_status_t status;
1628 pjsip_msg *msg;
Benny Prijono1c1d7342010-08-01 09:48:51 +00001629 pjsip_rdata_sdp_info *sdp_info;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001630
1631 /* Check if SDP is present in the message. */
1632
1633 msg = rdata->msg_info.msg;
1634 if (msg->body == NULL) {
1635 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001636 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001637 }
1638
Benny Prijono1c1d7342010-08-01 09:48:51 +00001639 sdp_info = pjsip_rdata_get_sdp_info(rdata);
1640 if (sdp_info->body.ptr == NULL) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00001641 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001642 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001643 }
1644
Benny Prijono8fcb4332008-10-31 18:01:48 +00001645 /* Get/attach invite session's transaction data */
1646 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
1647 if (tsx_inv_data == NULL) {
1648 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
1649 tsx_inv_data->inv = inv;
1650 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1651 }
1652
1653 /* MUST NOT do multiple SDP offer/answer in a single transaction,
1654 * EXCEPT if:
1655 * - this is an initial UAC INVITE transaction (i.e. not re-INVITE), and
1656 * - the previous negotiation was done on an early media (18x) and
1657 * this response is a final/2xx response, and
1658 * - the 2xx response has different To tag than the 18x response
1659 * (i.e. the request has forked).
1660 *
1661 * The exception above is to add a rudimentary support for early media
1662 * forking (sample case: custom ringback). See this ticket for more
1663 * info: http://trac.pjsip.org/repos/ticket/657
1664 */
1665 if (tsx_inv_data->sdp_done) {
1666 pj_str_t res_tag;
1667
1668 res_tag = rdata->msg_info.to->tag;
1669
1670 /* Allow final response after SDP has been negotiated in early
1671 * media, IF this response is a final response with different
1672 * tag.
1673 */
1674 if (tsx->role == PJSIP_ROLE_UAC &&
1675 rdata->msg_info.msg->line.status.code/100 == 2 &&
1676 tsx_inv_data->done_early &&
1677 pj_strcmp(&tsx_inv_data->done_tag, &res_tag))
1678 {
1679 const pjmedia_sdp_session *reoffer_sdp = NULL;
1680
1681 PJ_LOG(4,(inv->obj_name, "Received forked final response "
1682 "after SDP negotiation has been done in early "
1683 "media. Renegotiating SDP.."));
1684
1685 /* Retrieve original SDP offer from INVITE request */
1686 reoffer_sdp = (const pjmedia_sdp_session*)
1687 tsx->last_tx->msg->body->data;
1688
1689 /* Feed the original offer to negotiator */
Benny Prijono40d62b62009-08-12 17:53:47 +00001690 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
1691 inv->neg,
Benny Prijono8fcb4332008-10-31 18:01:48 +00001692 reoffer_sdp);
1693 if (status != PJ_SUCCESS) {
1694 PJ_LOG(1,(inv->obj_name, "Error updating local offer for "
1695 "forked 2xx response (err=%d)", status));
1696 return status;
1697 }
1698
1699 } else {
1700
1701 if (rdata->msg_info.msg->body) {
1702 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1703 "body is ignored"));
1704 }
1705 return PJ_SUCCESS;
1706 }
1707 }
1708
Benny Prijono1c1d7342010-08-01 09:48:51 +00001709 /* Process the SDP body. */
1710 if (sdp_info->sdp_err) {
1711 PJ_PERROR(4,(THIS_FILE, sdp_info->sdp_err,
1712 "Error parsing SDP in %s",
1713 pjsip_rx_data_get_info(rdata)));
Benny Prijono26ff9062006-02-21 23:47:00 +00001714 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001715 }
1716
Benny Prijono1c1d7342010-08-01 09:48:51 +00001717 pj_assert(sdp_info->sdp != NULL);
1718
Benny Prijonoa66c7152006-02-09 01:26:14 +00001719 /* The SDP can be an offer or answer, depending on negotiator's state */
1720
1721 if (inv->neg == NULL ||
1722 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1723 {
1724
1725 /* This is an offer. */
1726
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001727 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1728 pjsip_rx_data_get_info(rdata)));
1729
Benny Prijonoa66c7152006-02-09 01:26:14 +00001730 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001731 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
Benny Prijono1c1d7342010-08-01 09:48:51 +00001732 sdp_info->sdp,
1733 &inv->neg);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001734 } else {
Benny Prijono40d62b62009-08-12 17:53:47 +00001735 status=pjmedia_sdp_neg_set_remote_offer(inv->pool_prov, inv->neg,
Benny Prijono1c1d7342010-08-01 09:48:51 +00001736 sdp_info->sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001737 }
1738
1739 if (status != PJ_SUCCESS) {
Benny Prijono1c1d7342010-08-01 09:48:51 +00001740 PJ_PERROR(4,(THIS_FILE, status, "Error processing SDP offer in %",
1741 pjsip_rx_data_get_info(rdata)));
Benny Prijono26ff9062006-02-21 23:47:00 +00001742 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001743 }
1744
1745 /* Inform application about remote offer. */
1746
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001747 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001748
Benny Prijono1c1d7342010-08-01 09:48:51 +00001749 (*mod_inv.cb.on_rx_offer)(inv, sdp_info->sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00001750
1751 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001752
1753 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1754 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1755 {
Benny Prijono8fcb4332008-10-31 18:01:48 +00001756 int status_code;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001757
1758 /* This is an answer.
1759 * Process and negotiate remote answer.
1760 */
1761
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001762 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1763 pjsip_rx_data_get_info(rdata)));
1764
Benny Prijono40d62b62009-08-12 17:53:47 +00001765 status = pjmedia_sdp_neg_set_remote_answer(inv->pool_prov, inv->neg,
Benny Prijono1c1d7342010-08-01 09:48:51 +00001766 sdp_info->sdp);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001767
1768 if (status != PJ_SUCCESS) {
Benny Prijono1c1d7342010-08-01 09:48:51 +00001769 PJ_PERROR(4,(THIS_FILE, status, "Error processing SDP answer in %s",
1770 pjsip_rx_data_get_info(rdata)));
Benny Prijono26ff9062006-02-21 23:47:00 +00001771 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001772 }
1773
1774 /* Negotiate SDP */
1775
1776 inv_negotiate_sdp(inv);
1777
Benny Prijono8fcb4332008-10-31 18:01:48 +00001778 /* Mark this transaction has having SDP offer/answer done, and
1779 * save the reference to the To tag
1780 */
Benny Prijonoa66c7152006-02-09 01:26:14 +00001781
1782 tsx_inv_data->sdp_done = 1;
Benny Prijono8fcb4332008-10-31 18:01:48 +00001783 status_code = rdata->msg_info.msg->line.status.code;
1784 tsx_inv_data->done_early = (status_code/100==1);
1785 pj_strdup(tsx->pool, &tsx_inv_data->done_tag,
1786 &rdata->msg_info.to->tag);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001787
1788 } else {
1789
1790 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1791 pjsip_rx_data_get_info(rdata),
1792 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1793 }
1794
Benny Prijono26ff9062006-02-21 23:47:00 +00001795 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001796}
1797
1798
Benny Prijono26ff9062006-02-21 23:47:00 +00001799/*
1800 * Process INVITE answer, for both initial and subsequent re-INVITE
1801 */
1802static pj_status_t process_answer( pjsip_inv_session *inv,
1803 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001804 pjsip_tx_data *tdata,
1805 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001806{
1807 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001808 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001809
Benny Prijono64f851e2006-02-23 13:49:28 +00001810 /* If local_sdp is specified, then we MUST NOT have answered the
1811 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001812 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001813 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1814
1815 if (inv->neg == NULL) {
Benny Prijono40d62b62009-08-12 17:53:47 +00001816 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
1817 local_sdp,
Benny Prijono64f851e2006-02-23 13:49:28 +00001818 &inv->neg);
1819 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1820 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1821 {
Benny Prijono40d62b62009-08-12 17:53:47 +00001822 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov, inv->neg,
Benny Prijono64f851e2006-02-23 13:49:28 +00001823 local_sdp);
1824 } else {
1825
1826 /* Can not specify local SDP at this state. */
1827 pj_assert(0);
1828 status = PJMEDIA_SDPNEG_EINSTATE;
1829 }
1830
1831 if (status != PJ_SUCCESS)
1832 return status;
1833
1834 }
1835
1836
1837 /* If SDP negotiator is ready, start negotiation. */
1838 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001839
1840 pjmedia_sdp_neg_state neg_state;
1841
Benny Prijono64f851e2006-02-23 13:49:28 +00001842 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001843 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1844 PJMEDIA_SDP_NEG_STATE_NULL;
1845
1846 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1847
1848 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1849
1850 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1851 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1852 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001853 struct tsx_inv_data *tsx_inv_data;
1854
1855 /* Get invite session's transaction data */
1856 tsx_inv_data = (struct tsx_inv_data*)
1857 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001858
1859 status = inv_negotiate_sdp(inv);
1860 if (status != PJ_SUCCESS)
1861 return status;
1862
Benny Prijono77998ce2007-06-20 10:03:46 +00001863 /* Mark this transaction has having SDP offer/answer done. */
1864 tsx_inv_data->sdp_done = 1;
1865
Benny Prijono26ff9062006-02-21 23:47:00 +00001866 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1867 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001868 }
1869
Benny Prijono64f851e2006-02-23 13:49:28 +00001870 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001871 * Subsequent response will include this SDP.
Benny Prijono48ab2b72007-11-08 09:24:30 +00001872 *
1873 * Note note:
1874 * - When offer/answer has been completed in reliable 183, we MUST NOT
1875 * send SDP in 2xx response. So if we don't have SDP to send, clear
1876 * the SDP in the message body ONLY if 100rel is active in this
1877 * session.
Benny Prijono26ff9062006-02-21 23:47:00 +00001878 */
1879 if (sdp) {
1880 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono48ab2b72007-11-08 09:24:30 +00001881 } else {
1882 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1883 tdata->msg->body = NULL;
1884 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001885 }
1886
Benny Prijono26ff9062006-02-21 23:47:00 +00001887
1888 return PJ_SUCCESS;
1889}
1890
Benny Prijonoa66c7152006-02-09 01:26:14 +00001891
1892/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001893 * Create first response to INVITE
1894 */
1895PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1896 pjsip_rx_data *rdata,
1897 int st_code,
1898 const pj_str_t *st_text,
1899 const pjmedia_sdp_session *sdp,
1900 pjsip_tx_data **p_tdata)
1901{
1902 pjsip_tx_data *tdata;
1903 pj_status_t status;
Nanang Izzuddin65add622009-08-11 16:26:20 +00001904 pjsip_status_code st_code2;
Benny Prijono64f851e2006-02-23 13:49:28 +00001905
1906 /* Verify arguments. */
1907 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1908
1909 /* Must have INVITE transaction. */
1910 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1911
1912 pjsip_dlg_inc_lock(inv->dlg);
1913
1914 /* Create response */
1915 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1916 &tdata);
1917 if (status != PJ_SUCCESS)
1918 goto on_return;
1919
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001920 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00001921 status = pjsip_timer_process_req(inv, rdata, &st_code2);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001922 if (status != PJ_SUCCESS) {
1923 pj_status_t status2;
1924
Nanang Izzuddin65add622009-08-11 16:26:20 +00001925 status2 = pjsip_dlg_modify_response(inv->dlg, tdata, st_code2, NULL);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001926 if (status2 != PJ_SUCCESS) {
1927 pjsip_tx_data_dec_ref(tdata);
1928 goto on_return;
1929 }
1930 status2 = pjsip_timer_update_resp(inv, tdata);
1931 if (status2 == PJ_SUCCESS)
1932 *p_tdata = tdata;
1933 else
1934 pjsip_tx_data_dec_ref(tdata);
1935
1936 goto on_return;
1937 }
1938
Benny Prijono64f851e2006-02-23 13:49:28 +00001939 /* Process SDP in answer */
1940 status = process_answer(inv, st_code, tdata, sdp);
1941 if (status != PJ_SUCCESS) {
1942 pjsip_tx_data_dec_ref(tdata);
1943 goto on_return;
1944 }
1945
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001946 /* Save this answer */
1947 inv->last_answer = tdata;
1948 pjsip_tx_data_add_ref(inv->last_answer);
1949 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1950 pjsip_tx_data_get_info(inv->last_answer)));
1951
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00001952 /* Invoke Session Timers */
1953 pjsip_timer_update_resp(inv, tdata);
1954
Benny Prijono64f851e2006-02-23 13:49:28 +00001955 *p_tdata = tdata;
1956
1957on_return:
1958 pjsip_dlg_dec_lock(inv->dlg);
1959 return status;
1960}
1961
1962
1963/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001964 * Answer initial INVITE
1965 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001966 */
1967PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1968 int st_code,
1969 const pj_str_t *st_text,
1970 const pjmedia_sdp_session *local_sdp,
1971 pjsip_tx_data **p_tdata )
1972{
1973 pjsip_tx_data *last_res;
1974 pj_status_t status;
1975
1976 /* Verify arguments. */
1977 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1978
1979 /* Must have INVITE transaction. */
1980 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1981
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001982 /* Must have created an answer before */
1983 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001984
Benny Prijono64f851e2006-02-23 13:49:28 +00001985 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001986
1987 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001988 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001989 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1990 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001991 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001992
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001993 /* For non-2xx final response, strip message body */
1994 if (st_code >= 300) {
1995 last_res->msg->body = NULL;
1996 }
Benny Prijono268ca612006-02-07 12:34:11 +00001997
Benny Prijono26ff9062006-02-21 23:47:00 +00001998 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001999 status = process_answer(inv, st_code, last_res, local_sdp);
2000 if (status != PJ_SUCCESS) {
2001 pjsip_tx_data_dec_ref(last_res);
2002 goto on_return;
2003 }
Benny Prijono268ca612006-02-07 12:34:11 +00002004
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002005 /* Invoke Session Timers */
2006 pjsip_timer_update_resp(inv, last_res);
Benny Prijono268ca612006-02-07 12:34:11 +00002007
2008 *p_tdata = last_res;
2009
Benny Prijono64f851e2006-02-23 13:49:28 +00002010on_return:
2011 pjsip_dlg_dec_lock(inv->dlg);
2012 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002013}
2014
2015
2016/*
Benny Prijono26ff9062006-02-21 23:47:00 +00002017 * Set SDP answer.
2018 */
2019PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
2020 const pjmedia_sdp_session *sdp )
2021{
2022 pj_status_t status;
2023
2024 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
2025
2026 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono40d62b62009-08-12 17:53:47 +00002027 status = pjmedia_sdp_neg_set_local_answer( inv->pool_prov, inv->neg, sdp);
Benny Prijono26ff9062006-02-21 23:47:00 +00002028 pjsip_dlg_dec_lock(inv->dlg);
2029
2030 return status;
2031}
2032
2033
2034/*
Benny Prijono268ca612006-02-07 12:34:11 +00002035 * End session.
2036 */
2037PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
2038 int st_code,
2039 const pj_str_t *st_text,
2040 pjsip_tx_data **p_tdata )
2041{
2042 pjsip_tx_data *tdata;
2043 pj_status_t status;
2044
2045 /* Verify arguments. */
2046 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2047
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002048 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002049 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002050
Benny Prijono268ca612006-02-07 12:34:11 +00002051 /* Create appropriate message. */
2052 switch (inv->state) {
2053 case PJSIP_INV_STATE_CALLING:
2054 case PJSIP_INV_STATE_EARLY:
2055 case PJSIP_INV_STATE_INCOMING:
2056
2057 if (inv->role == PJSIP_ROLE_UAC) {
2058
2059 /* For UAC when session has not been confirmed, create CANCEL. */
2060
2061 /* MUST have the original UAC INVITE transaction. */
2062 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
2063
2064 /* But CANCEL should only be called when we have received a
2065 * provisional response. If we haven't received any responses,
2066 * just destroy the transaction.
2067 */
2068 if (inv->invite_tsx->status_code < 100) {
2069
Benny Prijono006a4e82009-04-26 11:30:22 +00002070 /* Do not stop INVITE retransmission, see ticket #506 */
2071 //pjsip_tsx_stop_retransmit(inv->invite_tsx);
Benny Prijono1dc8be02007-05-30 04:26:40 +00002072 inv->cancelling = PJ_TRUE;
2073 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00002074 *p_tdata = NULL;
Benny Prijono006a4e82009-04-26 11:30:22 +00002075 PJ_LOG(4, (inv->obj_name, "Delaying CANCEL since no "
2076 "provisional response is received yet"));
Benny Prijonofccab712006-02-22 22:23:22 +00002077 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002078 }
2079
2080 /* The CSeq here assumes that the dialog is started with an
2081 * INVITE session. This may not be correct; dialog can be
2082 * started as SUBSCRIBE session.
2083 * So fix this!
2084 */
2085 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
2086 inv->invite_tsx->last_tx,
2087 &tdata);
Benny Prijono99b04372009-04-26 11:02:04 +00002088 if (status != PJ_SUCCESS)
2089 return status;
2090
2091 /* Set timeout for the INVITE transaction, in case UAS is not
2092 * able to respond the INVITE with 487 final response. The
2093 * timeout value is 64*T1.
2094 */
2095 pjsip_tsx_set_timeout(inv->invite_tsx, 64 * pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00002096
2097 } else {
2098
2099 /* For UAS, send a final response. */
2100 tdata = inv->invite_tsx->last_tx;
2101 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
2102
Benny Prijono26ff9062006-02-21 23:47:00 +00002103 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
2104 // st_text);
2105 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002106 }
2107 break;
2108
2109 case PJSIP_INV_STATE_CONNECTING:
2110 case PJSIP_INV_STATE_CONFIRMED:
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002111 /* End Session Timer */
2112 pjsip_timer_end_session(inv);
2113
Benny Prijono268ca612006-02-07 12:34:11 +00002114 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002115 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
2116 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002117 break;
2118
2119 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00002120 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002121 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00002122
2123 default:
2124 pj_assert("!Invalid operation!");
2125 return PJ_EINVALIDOP;
2126 }
2127
2128 if (status != PJ_SUCCESS)
2129 return status;
2130
2131
2132 /* Done */
2133
Benny Prijono0606e702007-05-22 12:21:40 +00002134 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00002135 *p_tdata = tdata;
2136
2137 return PJ_SUCCESS;
2138}
2139
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002140/* Following redirection recursion, get next target from the target set and
2141 * notify user.
2142 *
2143 * Returns PJ_FALSE if recursion fails (either because there's no more target
2144 * or user rejects the recursion). If we return PJ_FALSE, caller should
2145 * disconnect the session.
2146 *
2147 * Note:
2148 * the event 'e' argument may be NULL.
2149 */
2150static pj_bool_t inv_uac_recurse(pjsip_inv_session *inv, int code,
2151 const pj_str_t *reason, pjsip_event *e)
2152{
Benny Prijono08a48b82008-11-27 12:42:07 +00002153 pjsip_redirect_op op;
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002154 pjsip_target *target;
2155
2156 /* Won't redirect if the callback is not implemented. */
2157 if (mod_inv.cb.on_redirected == NULL)
2158 return PJ_FALSE;
2159
2160 if (reason == NULL)
2161 reason = pjsip_get_status_text(code);
2162
2163 /* Set status of current target */
2164 pjsip_target_assign_status(inv->dlg->target_set.current, inv->dlg->pool,
2165 code, reason);
2166
2167 /* Fetch next target from the target set. We only want to
2168 * process SIP/SIPS URI for now.
2169 */
2170 for (;;) {
2171 target = pjsip_target_set_get_next(&inv->dlg->target_set);
2172 if (target == NULL) {
2173 /* No more target. */
2174 return PJ_FALSE;
2175 }
2176
2177 if (!PJSIP_URI_SCHEME_IS_SIP(target->uri) &&
2178 !PJSIP_URI_SCHEME_IS_SIPS(target->uri))
2179 {
2180 code = PJSIP_SC_UNSUPPORTED_URI_SCHEME;
2181 reason = pjsip_get_status_text(code);
2182
2183 /* Mark this target as unusable and fetch next target. */
2184 pjsip_target_assign_status(target, inv->dlg->pool, code, reason);
2185 } else {
2186 /* Found a target */
2187 break;
2188 }
2189 }
2190
2191 /* We have target in 'target'. Set this target as current target
2192 * and notify callback.
2193 */
2194 pjsip_target_set_set_current(&inv->dlg->target_set, target);
2195
Benny Prijono08a48b82008-11-27 12:42:07 +00002196 op = (*mod_inv.cb.on_redirected)(inv, target->uri, e);
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002197
2198
2199 /* Check what the application wants to do now */
2200 switch (op) {
2201 case PJSIP_REDIRECT_ACCEPT:
2202 case PJSIP_REDIRECT_STOP:
2203 /* Must increment session counter, that's the convention of the
2204 * pjsip_inv_process_redirect().
2205 */
2206 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2207
2208 /* Act on the recursion */
2209 pjsip_inv_process_redirect(inv, op, e);
2210 return PJ_TRUE;
2211
2212 case PJSIP_REDIRECT_PENDING:
2213 /* Increment session so that the dialog/session is not destroyed
2214 * while we're waiting for user confirmation.
2215 */
2216 pjsip_dlg_inc_session(inv->dlg, &mod_inv.mod);
2217
2218 /* Also clear the invite_tsx variable, otherwise when this tsx is
2219 * terminated, it will also terminate the session.
2220 */
2221 inv->invite_tsx = NULL;
2222
2223 /* Done. The processing will continue once the application calls
2224 * pjsip_inv_process_redirect().
2225 */
2226 return PJ_TRUE;
2227
2228 case PJSIP_REDIRECT_REJECT:
2229 /* Recursively call this function again to fetch next target, if any.
2230 */
2231 return inv_uac_recurse(inv, PJSIP_SC_REQUEST_TERMINATED, NULL, e);
2232
2233 }
2234
2235 pj_assert(!"Should not reach here");
2236 return PJ_FALSE;
2237}
2238
2239
2240/* Process redirection/recursion */
2241PJ_DEF(pj_status_t) pjsip_inv_process_redirect( pjsip_inv_session *inv,
2242 pjsip_redirect_op op,
2243 pjsip_event *e)
2244{
2245 const pjsip_status_code cancel_code = PJSIP_SC_REQUEST_TERMINATED;
2246 pjsip_event usr_event;
2247 pj_status_t status = PJ_SUCCESS;
2248
2249 PJ_ASSERT_RETURN(inv && op != PJSIP_REDIRECT_PENDING, PJ_EINVAL);
2250
2251 if (e == NULL) {
2252 PJSIP_EVENT_INIT_USER(usr_event, NULL, NULL, NULL, NULL);
2253 e = &usr_event;
2254 }
2255
2256 pjsip_dlg_inc_lock(inv->dlg);
2257
2258 /* Decrement session. That's the convention here to prevent the dialog
2259 * or session from being destroyed while we're waiting for user
2260 * confirmation.
2261 */
2262 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
2263
2264 /* See what the application wants to do now */
2265 switch (op) {
2266 case PJSIP_REDIRECT_ACCEPT:
2267 /* User accept the redirection. Reset the session and resend the
2268 * INVITE request.
2269 */
2270 {
2271 pjsip_tx_data *tdata;
2272 pjsip_via_hdr *via;
2273
2274 /* Get the original INVITE request. */
2275 tdata = inv->invite_req;
2276 pjsip_tx_data_add_ref(tdata);
2277
2278 /* Restore strict route set.
2279 * See http://trac.pjsip.org/repos/ticket/492
2280 */
2281 pjsip_restore_strict_route_set(tdata);
2282
2283 /* Set target */
Benny Prijono20da7992008-12-18 16:48:43 +00002284 tdata->msg->line.req.uri = (pjsip_uri*)
Benny Prijono5e51a4e2008-11-27 00:06:46 +00002285 pjsip_uri_clone(tdata->pool, inv->dlg->target_set.current->uri);
2286
2287 /* Remove branch param in Via header. */
2288 via = (pjsip_via_hdr*)
2289 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
2290 via->branch_param.slen = 0;
2291
2292 /* Must invalidate the message! */
2293 pjsip_tx_data_invalidate_msg(tdata);
2294
2295 /* Reset the session */
2296 pjsip_inv_uac_restart(inv, PJ_FALSE);
2297
2298 /* (re)Send the INVITE request */
2299 status = pjsip_inv_send_msg(inv, tdata);
2300 }
2301 break;
2302
2303 case PJSIP_REDIRECT_STOP:
2304 /* User doesn't want the redirection. Disconnect the session now. */
2305 inv_set_cause(inv, cancel_code, pjsip_get_status_text(cancel_code));
2306 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2307
2308 /* Caller should expect that the invite session is gone now, so
2309 * we don't need to set status to PJSIP_ESESSIONTERMINATED here.
2310 */
2311 break;
2312
2313 case PJSIP_REDIRECT_REJECT:
2314 /* Current target is rejected. Fetch next target if any. */
2315 if (inv_uac_recurse(inv, cancel_code, NULL, NULL) == PJ_FALSE) {
2316 inv_set_cause(inv, cancel_code,
2317 pjsip_get_status_text(cancel_code));
2318 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2319
2320 /* Tell caller that the invite session is gone now */
2321 status = PJSIP_ESESSIONTERMINATED;
2322 }
2323 break;
2324
2325
2326 case PJSIP_REDIRECT_PENDING:
2327 pj_assert(!"Should not happen");
2328 break;
2329 }
2330
2331
2332 pjsip_dlg_dec_lock(inv->dlg);
2333
2334 return status;
2335}
2336
Benny Prijono268ca612006-02-07 12:34:11 +00002337
2338/*
2339 * Create re-INVITE.
2340 */
2341PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
2342 const pj_str_t *new_contact,
2343 const pjmedia_sdp_session *new_offer,
2344 pjsip_tx_data **p_tdata )
2345{
Benny Prijono26ff9062006-02-21 23:47:00 +00002346 pj_status_t status;
2347 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00002348
Benny Prijono26ff9062006-02-21 23:47:00 +00002349 /* Check arguments. */
2350 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2351
2352 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00002353 if (inv->invite_tsx!=NULL)
2354 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00002355
2356
2357 pjsip_dlg_inc_lock(inv->dlg);
2358
2359 if (new_contact) {
2360 pj_str_t tmp;
2361 const pj_str_t STR_CONTACT = { "Contact", 7 };
2362
2363 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00002364 contact_hdr = (pjsip_contact_hdr*)
2365 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00002366 tmp.ptr, tmp.slen, NULL);
2367 if (!contact_hdr) {
2368 status = PJSIP_EINVALIDURI;
2369 goto on_return;
2370 }
2371 }
2372
2373
2374 if (new_offer) {
2375 if (!inv->neg) {
Benny Prijono40d62b62009-08-12 17:53:47 +00002376 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool,
2377 new_offer,
Benny Prijono26ff9062006-02-21 23:47:00 +00002378 &inv->neg);
2379 if (status != PJ_SUCCESS)
2380 goto on_return;
2381
2382 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
2383
2384 case PJMEDIA_SDP_NEG_STATE_NULL:
2385 pj_assert(!"Unexpected SDP neg state NULL");
2386 status = PJ_EBUG;
2387 goto on_return;
2388
2389 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
2390 PJ_LOG(4,(inv->obj_name,
2391 "pjsip_inv_reinvite: already have an offer, new "
2392 "offer is ignored"));
2393 break;
2394
2395 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
Benny Prijono40d62b62009-08-12 17:53:47 +00002396 status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov,
2397 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002398 new_offer);
2399 if (status != PJ_SUCCESS)
2400 goto on_return;
2401 break;
2402
2403 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
2404 PJ_LOG(4,(inv->obj_name,
2405 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
2406 "offer is ignored"));
2407 break;
2408
2409 case PJMEDIA_SDP_NEG_STATE_DONE:
Benny Prijono40d62b62009-08-12 17:53:47 +00002410 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
2411 inv->neg,
Benny Prijono26ff9062006-02-21 23:47:00 +00002412 new_offer);
2413 if (status != PJ_SUCCESS)
2414 goto on_return;
2415 break;
2416 }
2417 }
2418
2419 if (contact_hdr)
2420 inv->dlg->local.contact = contact_hdr;
2421
2422 status = pjsip_inv_invite(inv, p_tdata);
2423
2424on_return:
2425 pjsip_dlg_dec_lock(inv->dlg);
2426 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002427}
2428
2429/*
2430 * Create UPDATE.
2431 */
2432PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
2433 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00002434 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00002435 pjsip_tx_data **p_tdata )
2436{
Benny Prijono1f7767b2007-10-03 18:28:49 +00002437 pjsip_contact_hdr *contact_hdr = NULL;
2438 pjsip_tx_data *tdata = NULL;
2439 pjmedia_sdp_session *sdp_copy;
2440 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00002441
Benny Prijono1f7767b2007-10-03 18:28:49 +00002442 /* Verify arguments. */
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002443 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002444
2445 /* Dialog must have been established */
2446 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
2447 PJ_EINVALIDOP);
2448
2449 /* Invite session must not have been disconnected */
2450 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
2451 PJ_EINVALIDOP);
2452
2453 /* Lock dialog. */
2454 pjsip_dlg_inc_lock(inv->dlg);
2455
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002456 /* Process offer, if any */
2457 if (offer) {
2458 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
2459 PJ_LOG(4,(inv->dlg->obj_name,
2460 "Invalid SDP offer/answer state for UPDATE"));
2461 status = PJ_EINVALIDOP;
2462 goto on_error;
2463 }
2464
2465 /* Notify negotiator about the new offer. This will fix the offer
2466 * with correct SDP origin.
2467 */
2468 status = pjmedia_sdp_neg_modify_local_offer(inv->pool_prov, inv->neg,
2469 offer);
2470 if (status != PJ_SUCCESS)
2471 goto on_error;
2472
2473 /* Retrieve the "fixed" offer from negotiator */
2474 pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002475 }
2476
Benny Prijono1f7767b2007-10-03 18:28:49 +00002477 /* Update Contact if required */
2478 if (new_contact) {
2479 pj_str_t tmp;
2480 const pj_str_t STR_CONTACT = { "Contact", 7 };
2481
2482 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
2483 contact_hdr = (pjsip_contact_hdr*)
2484 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
2485 tmp.ptr, tmp.slen, NULL);
2486 if (!contact_hdr) {
2487 status = PJSIP_EINVALIDURI;
2488 goto on_error;
2489 }
2490
2491 inv->dlg->local.contact = contact_hdr;
2492 }
2493
2494 /* Create request */
2495 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
2496 -1, &tdata);
2497 if (status != PJ_SUCCESS)
2498 goto on_error;
2499
2500 /* Attach SDP body */
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002501 if (offer) {
2502 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
2503 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
2504 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00002505
2506 /* Unlock dialog. */
2507 pjsip_dlg_dec_lock(inv->dlg);
2508
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002509 status = pjsip_timer_update_req(inv, tdata);
2510 if (status != PJ_SUCCESS)
2511 goto on_error;
2512
Benny Prijono1f7767b2007-10-03 18:28:49 +00002513 *p_tdata = tdata;
2514
2515 return PJ_SUCCESS;
2516
2517on_error:
2518 if (tdata)
2519 pjsip_tx_data_dec_ref(tdata);
2520
2521 /* Unlock dialog. */
2522 pjsip_dlg_dec_lock(inv->dlg);
2523
2524 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002525}
2526
2527/*
Benny Prijonod5f9f422007-11-25 04:40:07 +00002528 * Create an ACK request.
2529 */
2530PJ_DEF(pj_status_t) pjsip_inv_create_ack(pjsip_inv_session *inv,
2531 int cseq,
2532 pjsip_tx_data **p_tdata)
2533{
2534 const pjmedia_sdp_session *sdp = NULL;
2535 pj_status_t status;
2536
2537 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
2538
2539 /* Lock dialog. */
2540 pjsip_dlg_inc_lock(inv->dlg);
2541
2542 /* Destroy last_ack */
2543 if (inv->last_ack) {
2544 pjsip_tx_data_dec_ref(inv->last_ack);
2545 inv->last_ack = NULL;
2546 }
2547
2548 /* Create new ACK request */
2549 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
2550 cseq, &inv->last_ack);
2551 if (status != PJ_SUCCESS) {
2552 pjsip_dlg_dec_lock(inv->dlg);
2553 return status;
2554 }
2555
2556 /* See if we have pending SDP answer to send */
2557 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
2558 if (sdp) {
2559 inv->last_ack->msg->body = create_sdp_body(inv->last_ack->pool, sdp);
2560 }
2561
2562 /* Keep this for subsequent response retransmission */
2563 inv->last_ack_cseq = cseq;
2564 pjsip_tx_data_add_ref(inv->last_ack);
2565
2566 /* Done */
2567 *p_tdata = inv->last_ack;
2568
2569 /* Unlock dialog. */
2570 pjsip_dlg_dec_lock(inv->dlg);
2571
2572 return PJ_SUCCESS;
2573}
2574
2575/*
Benny Prijono268ca612006-02-07 12:34:11 +00002576 * Send a request or response message.
2577 */
2578PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002579 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00002580{
2581 pj_status_t status;
2582
2583 /* Verify arguments. */
2584 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
2585
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002586 PJ_LOG(5,(inv->obj_name, "Sending %s",
2587 pjsip_tx_data_get_info(tdata)));
2588
Benny Prijono268ca612006-02-07 12:34:11 +00002589 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002590 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00002591
Benny Prijono64158af2006-04-04 11:06:34 +00002592 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00002593
Benny Prijono22e48c92008-03-20 14:40:50 +00002594 /* Check again that we didn't receive incoming re-INVITE */
Benny Prijono9ae5dfc2008-03-27 17:30:51 +00002595 if (tdata->msg->line.req.method.id==PJSIP_INVITE_METHOD &&
2596 inv->invite_tsx)
2597 {
Benny Prijono22e48c92008-03-20 14:40:50 +00002598 pjsip_tx_data_dec_ref(tdata);
2599 pjsip_dlg_dec_lock(inv->dlg);
2600 return PJ_EINVALIDOP;
2601 }
2602
2603 /* Associate our data in outgoing invite transaction */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002604 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002605 tsx_inv_data->inv = inv;
2606
Benny Prijono64158af2006-04-04 11:06:34 +00002607 pjsip_dlg_dec_lock(inv->dlg);
2608
2609 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
2610 tsx_inv_data);
2611 if (status != PJ_SUCCESS)
2612 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00002613
2614 } else {
2615 pjsip_cseq_hdr *cseq;
2616
2617 /* Can only do this to send response to original INVITE
2618 * request.
2619 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00002620 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 +00002621 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00002622 PJ_EINVALIDOP);
2623
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002624 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002625 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002626 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002627 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002628 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002629 }
2630
Benny Prijono268ca612006-02-07 12:34:11 +00002631 if (status != PJ_SUCCESS)
2632 return status;
2633 }
2634
2635 /* Done (?) */
2636 return PJ_SUCCESS;
2637}
2638
2639
Benny Prijono8ad55352006-02-08 11:16:05 +00002640/*
2641 * Respond to incoming CANCEL request.
2642 */
2643static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2644 pjsip_transaction *cancel_tsx,
2645 pjsip_rx_data *rdata)
2646{
2647 pjsip_tx_data *tdata;
2648 pjsip_transaction *invite_tsx;
2649 pj_str_t key;
2650 pj_status_t status;
2651
2652 /* See if we have matching INVITE server transaction: */
2653
2654 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002655 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002656 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2657
2658 if (invite_tsx == NULL) {
2659
2660 /* Invite transaction not found!
Benny Prijonoc5145762007-11-23 12:04:40 +00002661 * Respond CANCEL with 481 (RFC 3261 Section 9.2 page 55)
Benny Prijono8ad55352006-02-08 11:16:05 +00002662 */
Benny Prijonoc5145762007-11-23 12:04:40 +00002663 status = pjsip_dlg_create_response( inv->dlg, rdata, 481, NULL,
Benny Prijono8ad55352006-02-08 11:16:05 +00002664 &tdata);
2665
2666 } else {
2667 /* Always answer CANCEL will 200 (OK) regardless of
2668 * the state of the INVITE transaction.
2669 */
2670 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2671 &tdata);
2672 }
2673
2674 /* See if we have created the response successfully. */
2675 if (status != PJ_SUCCESS) return;
2676
2677 /* Send the CANCEL response */
2678 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2679 if (status != PJ_SUCCESS) return;
2680
2681
2682 /* See if we need to terminate the UAS INVITE transaction
2683 * with 487 (Request Terminated) response.
2684 */
2685 if (invite_tsx && invite_tsx->status_code < 200) {
2686
2687 pj_assert(invite_tsx->last_tx != NULL);
2688
2689 tdata = invite_tsx->last_tx;
2690
2691 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
Benny Prijonofc8bb142007-11-08 09:56:50 +00002692 if (status == PJ_SUCCESS) {
2693 /* Remove the message body */
2694 tdata->msg->body = NULL;
Benny Prijono1e08e4f2009-05-13 08:57:38 +00002695 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
2696 status = pjsip_100rel_tx_response(inv, tdata);
2697 } else {
2698 status = pjsip_dlg_send_response(inv->dlg, invite_tsx,
2699 tdata);
2700 }
Benny Prijonofc8bb142007-11-08 09:56:50 +00002701 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002702 }
2703
2704 if (invite_tsx)
2705 pj_mutex_unlock(invite_tsx->mutex);
2706}
2707
2708
2709/*
2710 * Respond to incoming BYE request.
2711 */
2712static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2713 pjsip_transaction *bye_tsx,
2714 pjsip_rx_data *rdata,
2715 pjsip_event *e )
2716{
2717 pj_status_t status;
2718 pjsip_tx_data *tdata;
2719
2720 /* Respond BYE with 200: */
2721
2722 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2723 if (status != PJ_SUCCESS) return;
2724
2725 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2726 if (status != PJ_SUCCESS) return;
2727
2728 /* Terminate session: */
2729
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002730 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002731 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002732 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002733 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002734}
2735
2736/*
Benny Prijono38998232006-02-08 22:44:25 +00002737 * Respond to BYE request.
2738 */
2739static void inv_handle_bye_response( pjsip_inv_session *inv,
2740 pjsip_transaction *tsx,
2741 pjsip_rx_data *rdata,
2742 pjsip_event *e )
2743{
2744 pj_status_t status;
2745
2746 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002747 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002748 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2749 return;
2750 }
2751
2752 /* Handle 401/407 challenge. */
2753 if (tsx->status_code == 401 || tsx->status_code == 407) {
2754
2755 pjsip_tx_data *tdata;
2756
2757 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2758 rdata,
2759 tsx->last_tx,
2760 &tdata);
2761
2762 if (status != PJ_SUCCESS) {
2763
2764 /* Does not have proper credentials.
2765 * End the session anyway.
2766 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002767 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002768 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2769
2770 } else {
2771 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002772 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002773 }
2774
2775 } else {
2776
2777 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002778 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002779 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2780 }
2781
2782}
2783
2784/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002785 * Respond to incoming UPDATE request.
2786 */
2787static void inv_respond_incoming_update(pjsip_inv_session *inv,
2788 pjsip_rx_data *rdata)
2789{
2790 pjmedia_sdp_neg_state neg_state;
2791 pj_status_t status;
2792 pjsip_tx_data *tdata = NULL;
Nanang Izzuddin65add622009-08-11 16:26:20 +00002793 pjsip_status_code st_code;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002794
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002795 /* Invoke Session Timers module */
Nanang Izzuddin65add622009-08-11 16:26:20 +00002796 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002797 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00002798 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002799 NULL, &tdata);
2800 goto on_return;
2801 }
2802
Benny Prijono1f7767b2007-10-03 18:28:49 +00002803 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2804
2805 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2806 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2807 status = pjsip_dlg_create_response(inv->dlg, rdata,
2808 PJSIP_SC_REQUEST_PENDING, NULL,
2809 &tdata);
2810 }
2811 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2812 * receive UPDATE while we haven't sent answer.
2813 */
2814 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2815 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2816 status = pjsip_dlg_create_response(inv->dlg, rdata,
2817 PJSIP_SC_INTERNAL_SERVER_ERROR,
2818 NULL, &tdata);
2819
Benny Prijonoc5cbc052007-11-08 09:44:08 +00002820 /* If UPDATE doesn't contain SDP, just respond with 200/OK.
2821 * This is a valid scenario according to session-timer draft.
2822 */
2823 } else if (rdata->msg_info.msg->body == NULL) {
2824
2825 status = pjsip_dlg_create_response(inv->dlg, rdata,
2826 200, NULL, &tdata);
2827
Benny Prijono1f7767b2007-10-03 18:28:49 +00002828 } else {
2829 /* We receive new offer from remote */
2830 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2831
2832 /* Application MUST have supplied the answer by now.
2833 * If so, negotiate the SDP.
2834 */
2835 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2836 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2837 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2838 {
Benny Prijonoab74c902010-06-23 12:21:20 +00002839 /* Negotiation has failed. If negotiator is still
2840 * stuck at non-DONE state, cancel any ongoing offer.
2841 */
2842 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2843 if (neg_state != PJMEDIA_SDP_NEG_STATE_DONE) {
2844 pjmedia_sdp_neg_cancel_offer(inv->neg);
2845 }
2846
Benny Prijono1f7767b2007-10-03 18:28:49 +00002847 status = pjsip_dlg_create_response(inv->dlg, rdata,
2848 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2849 NULL, &tdata);
2850 } else {
2851 /* New media has been negotiated successfully, send 200/OK */
2852 status = pjsip_dlg_create_response(inv->dlg, rdata,
2853 PJSIP_SC_OK, NULL, &tdata);
2854 if (status == PJ_SUCCESS) {
Benny Prijono9569a0b2007-10-04 15:35:26 +00002855 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002856 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2857 if (status == PJ_SUCCESS)
2858 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2859 }
2860 }
2861 }
2862
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00002863on_return:
2864 /* Invoke Session Timers */
2865 if (status == PJ_SUCCESS)
2866 status = pjsip_timer_update_resp(inv, tdata);
2867
Benny Prijono1f7767b2007-10-03 18:28:49 +00002868 if (status != PJ_SUCCESS) {
2869 if (tdata != NULL) {
2870 pjsip_tx_data_dec_ref(tdata);
2871 tdata = NULL;
2872 }
2873 return;
2874 }
2875
2876 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2877}
2878
2879
2880/*
2881 * Handle incoming response to UAC UPDATE request.
2882 */
2883static void inv_handle_update_response( pjsip_inv_session *inv,
2884 pjsip_event *e)
2885{
2886 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2887 struct tsx_inv_data *tsx_inv_data = NULL;
2888 pj_status_t status = -1;
2889
Benny Prijono48ab2b72007-11-08 09:24:30 +00002890 /* Handle 401/407 challenge. */
Benny Prijono1f7767b2007-10-03 18:28:49 +00002891 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002892 (tsx->status_code == 401 || tsx->status_code == 407))
2893 {
Benny Prijono48ab2b72007-11-08 09:24:30 +00002894 pjsip_tx_data *tdata;
2895
2896 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2897 e->body.tsx_state.src.rdata,
2898 tsx->last_tx,
2899 &tdata);
2900
2901 if (status != PJ_SUCCESS) {
2902
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002903 /* Somehow failed. Probably it's not a good idea to terminate
2904 * the session since this is just a request within dialog. And
2905 * even if we terminate we should send BYE.
Benny Prijono48ab2b72007-11-08 09:24:30 +00002906 */
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002907 /*
Benny Prijono48ab2b72007-11-08 09:24:30 +00002908 inv_set_cause(inv, PJSIP_SC_OK, NULL);
2909 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00002910 */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002911
2912 } else {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00002913 /* Re-send request. */
Benny Prijono48ab2b72007-11-08 09:24:30 +00002914 status = pjsip_inv_send_msg(inv, tdata);
2915 }
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002916 }
2917
2918 /* Process 422 response */
2919 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2920 tsx->status_code == 422)
2921 {
2922 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2923 PJ_FALSE);
2924 }
Benny Prijono48ab2b72007-11-08 09:24:30 +00002925
2926 /* Process 2xx response */
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002927 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002928 tsx->status_code/100 == 2 &&
2929 e->body.tsx_state.src.rdata->msg_info.msg->body)
2930 {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002931 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2932 PJ_FALSE);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002933 status = inv_check_sdp_in_incoming_msg(inv, tsx,
Nanang Izzuddincf69c282009-10-16 06:28:56 +00002934 e->body.tsx_state.src.rdata);
2935 }
2936
2937 /* Get/attach invite session's transaction data */
2938 else
2939 {
Benny Prijonoa8f9e622010-06-21 13:28:55 +00002940 /* Session-Timer needs to see any error responses, to determine
2941 * whether peer supports UPDATE with empty body.
2942 */
2943 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2944 tsx->role == PJSIP_ROLE_UAC)
2945 {
2946 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
2947 PJ_FALSE);
2948 }
2949
Benny Prijono1f7767b2007-10-03 18:28:49 +00002950 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2951 if (tsx_inv_data == NULL) {
2952 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2953 tsx_inv_data->inv = inv;
2954 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2955 }
2956 }
2957
Benny Prijonoab74c902010-06-23 12:21:20 +00002958 /* Cancel the negotiation if we don't get successful negotiation by now */
2959 if (pjmedia_sdp_neg_get_state(inv->neg) ==
2960 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
Benny Prijono1f7767b2007-10-03 18:28:49 +00002961 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2962 {
2963 pjmedia_sdp_neg_cancel_offer(inv->neg);
2964
2965 /* Prevent from us cancelling different offer! */
2966 tsx_inv_data->sdp_done = PJ_TRUE;
2967 }
2968}
2969
2970
2971/*
2972 * Handle incoming reliable response.
2973 */
2974static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2975 pjsip_rx_data *rdata)
2976{
2977 pjsip_tx_data *tdata;
Benny Prijono9569a0b2007-10-04 15:35:26 +00002978 const pjmedia_sdp_session *sdp;
Benny Prijono1f7767b2007-10-03 18:28:49 +00002979 pj_status_t status;
2980
2981 /* Create PRACK */
2982 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2983 if (status != PJ_SUCCESS)
2984 return;
2985
2986 /* See if we need to attach SDP answer on the PRACK request */
2987 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2988 if (sdp) {
2989 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2990 }
2991
2992 /* Send PRACK (must be using 100rel module!) */
2993 pjsip_100rel_send_prack(inv, tdata);
2994}
2995
2996
2997/*
2998 * Handle incoming PRACK.
2999 */
3000static void inv_respond_incoming_prack(pjsip_inv_session *inv,
3001 pjsip_rx_data *rdata)
3002{
3003 pj_status_t status;
3004
3005 /* Run through 100rel module to see if we can accept this
3006 * PRACK request. The 100rel will send 200/OK to PRACK request.
3007 */
3008 status = pjsip_100rel_on_rx_prack(inv, rdata);
3009 if (status != PJ_SUCCESS)
3010 return;
3011
3012 /* Now check for SDP answer in the PRACK request */
3013 if (rdata->msg_info.msg->body) {
3014 status = inv_check_sdp_in_incoming_msg(inv,
3015 pjsip_rdata_get_tsx(rdata), rdata);
3016 } else {
3017 /* No SDP body */
3018 status = -1;
3019 }
3020
3021 /* If SDP negotiation has been successful, also mark the
3022 * SDP negotiation flag in the invite transaction to be
3023 * done too.
3024 */
3025 if (status == PJ_SUCCESS && inv->invite_tsx) {
3026 struct tsx_inv_data *tsx_inv_data;
3027
3028 /* Get/attach invite session's transaction data */
3029 tsx_inv_data = (struct tsx_inv_data*)
3030 inv->invite_tsx->mod_data[mod_inv.mod.id];
3031 if (tsx_inv_data == NULL) {
3032 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
3033 struct tsx_inv_data);
3034 tsx_inv_data->inv = inv;
3035 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
3036 }
3037
3038 tsx_inv_data->sdp_done = PJ_TRUE;
3039 }
3040}
3041
3042
3043/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003044 * State NULL is before anything is sent/received.
3045 */
3046static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003047{
3048 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3049 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3050
3051 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3052
3053 if (tsx->method.id == PJSIP_INVITE_METHOD) {
3054
Benny Prijono64f851e2006-02-23 13:49:28 +00003055 /* Keep the initial INVITE transaction. */
3056 if (inv->invite_tsx == NULL)
3057 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00003058
Benny Prijono64f851e2006-02-23 13:49:28 +00003059 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00003060
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003061 /* Save the original INVITE request, if on_redirected() callback
3062 * is implemented. We may need to resend the INVITE if we receive
3063 * redirection response.
3064 */
3065 if (mod_inv.cb.on_redirected) {
3066 if (inv->invite_req) {
3067 pjsip_tx_data_dec_ref(inv->invite_req);
3068 inv->invite_req = NULL;
3069 }
3070 inv->invite_req = tsx->last_tx;
3071 pjsip_tx_data_add_ref(inv->invite_req);
3072 }
3073
Benny Prijono268ca612006-02-07 12:34:11 +00003074 switch (tsx->state) {
3075 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003076 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003077 break;
3078 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00003079 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003080 break;
3081 }
3082
3083 } else {
3084 switch (tsx->state) {
3085 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003086 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003087 break;
Benny Prijono38998232006-02-08 22:44:25 +00003088 case PJSIP_TSX_STATE_PROCEEDING:
3089 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3090 if (tsx->status_code > 100)
3091 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
3092 break;
Benny Prijono2285e7e2008-12-17 14:28:18 +00003093 case PJSIP_TSX_STATE_TERMINATED:
3094 /* there is a failure in sending response. */
3095 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3096 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3097 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003098 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00003099 inv_on_state_incoming(inv, e);
3100 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003101 }
3102 }
3103
3104 } else {
3105 pj_assert(!"Unexpected transaction type");
3106 }
3107}
3108
Benny Prijono8ad55352006-02-08 11:16:05 +00003109/*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003110 * Generic UAC transaction handler:
3111 * - resend request on 401 or 407 response.
3112 * - terminate dialog on 408 and 481 response.
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003113 * - resend request on 422 response.
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003114 */
3115static pj_bool_t handle_uac_tsx_response(pjsip_inv_session *inv,
3116 pjsip_event *e)
3117{
3118 /* RFC 3261 Section 12.2.1.2:
3119 * If the response for a request within a dialog is a 481
3120 * (Call/Transaction Does Not Exist) or a 408 (Request Timeout), the UAC
3121 * SHOULD terminate the dialog. A UAC SHOULD also terminate a dialog if
3122 * no response at all is received for the request (the client
3123 * transaction would inform the TU about the timeout.)
3124 *
3125 * For INVITE initiated dialogs, terminating the dialog consists of
3126 * sending a BYE.
3127 *
3128 * Note:
3129 * according to X, this should terminate dialog usage only, not the
3130 * dialog.
3131 */
3132 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3133
3134 pj_assert(tsx->role == PJSIP_UAC_ROLE);
3135
3136 /* Note that 481 response to CANCEL does not terminate dialog usage,
3137 * but only the transaction.
3138 */
Benny Prijono61fc5e62008-06-25 18:35:31 +00003139 if (inv->state != PJSIP_INV_STATE_DISCONNECTED &&
3140 ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003141 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijono61fc5e62008-06-25 18:35:31 +00003142 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3143 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
3144 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR))
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003145 {
3146 pjsip_tx_data *bye;
3147 pj_status_t status;
3148
3149 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3150 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3151
3152 /* Send BYE */
3153 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
3154 -1, &bye);
3155 if (status == PJ_SUCCESS) {
3156 pjsip_inv_send_msg(inv, bye);
3157 }
3158
3159 return PJ_TRUE; /* Handled */
3160
3161 }
3162 /* Handle 401/407 challenge. */
3163 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3164 (tsx->status_code == PJSIP_SC_UNAUTHORIZED ||
3165 tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED))
3166 {
3167
3168 pjsip_tx_data *tdata;
3169 pj_status_t status;
3170
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003171 if (tsx->method.id == PJSIP_INVITE_METHOD)
3172 inv->invite_tsx = NULL;
3173
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003174 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
3175 e->body.tsx_state.src.rdata,
3176 tsx->last_tx, &tdata);
3177
3178 if (status != PJ_SUCCESS) {
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003179 /* Somehow failed. Probably it's not a good idea to terminate
3180 * the session since this is just a request within dialog. And
3181 * even if we terminate we should send BYE.
3182 */
3183 /*
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003184 inv_set_cause(inv, PJSIP_SC_OK, NULL);
3185 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonob2ad04a2008-06-26 13:24:10 +00003186 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003187
3188 } else {
3189 /* Re-send request. */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003190 status = pjsip_inv_send_msg(inv, tdata);
3191 }
3192
3193 return PJ_TRUE; /* Handled */
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003194 }
3195
3196 /* Handle session timer 422 response. */
3197 else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3198 tsx->status_code == PJSIP_SC_SESSION_TIMER_TOO_SMALL)
3199 {
3200 handle_timer_response(inv, e->body.tsx_state.src.rdata,
3201 PJ_FALSE);
3202
3203 return PJ_TRUE; /* Handled */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003204
3205 } else {
3206 return PJ_FALSE; /* Unhandled */
3207 }
3208}
3209
3210
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003211/* Handle call rejection, especially with regard to processing call
3212 * redirection. We need to handle the following scenarios:
3213 * - 3xx response is received -- see if on_redirected() callback is
3214 * implemented. If so, add the Contact URIs in the response to the
3215 * target set and notify user.
3216 * - 4xx - 6xx resposne is received -- see if we're currently recursing,
3217 * if so fetch the next target if any and notify the on_redirected()
3218 * callback.
3219 * - for other cases -- disconnect the session.
3220 */
3221static void handle_uac_call_rejection(pjsip_inv_session *inv, pjsip_event *e)
3222{
3223 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3224 pj_status_t status;
3225
3226 if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 300)) {
3227
3228 if (mod_inv.cb.on_redirected == NULL) {
3229
3230 /* Redirection callback is not implemented, disconnect the
3231 * call.
3232 */
3233 goto terminate_session;
3234
3235 } else {
3236 const pjsip_msg *res_msg;
3237
3238 res_msg = e->body.tsx_state.src.rdata->msg_info.msg;
3239
3240 /* Gather all Contact URI's in the response and add them
3241 * to target set. The function will take care of removing
3242 * duplicate URI's.
3243 */
3244 pjsip_target_set_add_from_msg(&inv->dlg->target_set,
3245 inv->dlg->pool, res_msg);
3246
3247 /* Recurse to alternate targets if application allows us */
3248 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3249 {
3250 /* Recursion fails, terminate session now */
3251 goto terminate_session;
3252 }
3253
3254 /* Done */
3255 }
3256
3257 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
3258 !inv->cancelling)
3259 {
3260
3261 /* Handle authentication failure:
3262 * Resend the request with Authorization header.
3263 */
3264 pjsip_tx_data *tdata;
3265
3266 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
3267 e->body.tsx_state.src.rdata,
3268 tsx->last_tx,
3269 &tdata);
3270
3271 if (status != PJ_SUCCESS) {
3272
3273 /* Does not have proper credentials. If we are currently
3274 * recursing, try the next target. Otherwise end the session.
3275 */
3276 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e))
3277 {
3278 /* Recursion fails, terminate session now */
3279 goto terminate_session;
3280 }
3281
3282 } else {
3283
3284 /* Restart session. */
3285 pjsip_inv_uac_restart(inv, PJ_FALSE);
3286
3287 /* Send the request. */
3288 status = pjsip_inv_send_msg(inv, tdata);
3289 }
3290
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003291 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3292 tsx->status_code == PJSIP_SC_SESSION_TIMER_TOO_SMALL)
3293 {
3294 /* Handle session timer 422 response:
3295 * Resend the request with requested session timer setting.
3296 */
3297 status = handle_timer_response(inv, e->body.tsx_state.src.rdata,
3298 PJ_TRUE);
3299
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003300 } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 600)) {
3301 /* Global error */
3302 goto terminate_session;
3303
3304 } else {
3305 /* See if we have alternate target to try */
3306 if (!inv_uac_recurse(inv, tsx->status_code, &tsx->status_text, e)) {
3307 /* Recursion fails, terminate session now */
3308 goto terminate_session;
3309 }
3310 }
3311 return;
3312
3313terminate_session:
3314 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3315 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3316}
3317
3318
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003319/*
Benny Prijono8ad55352006-02-08 11:16:05 +00003320 * State CALLING is after sending initial INVITE request but before
3321 * any response (with tag) is received.
3322 */
3323static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003324{
3325 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3326 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00003327 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00003328
3329 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3330
Benny Prijono8ad55352006-02-08 11:16:05 +00003331 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003332
3333 switch (tsx->state) {
3334
Benny Prijono64f851e2006-02-23 13:49:28 +00003335 case PJSIP_TSX_STATE_CALLING:
3336 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
3337 break;
3338
Benny Prijono268ca612006-02-07 12:34:11 +00003339 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00003340 if (inv->pending_cancel) {
3341 pjsip_tx_data *cancel;
3342
3343 inv->pending_cancel = PJ_FALSE;
3344
3345 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
3346 if (status == PJ_SUCCESS && cancel)
3347 status = pjsip_inv_send_msg(inv, cancel);
3348 }
3349
Benny Prijono268ca612006-02-07 12:34:11 +00003350 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00003351
Benny Prijono8ad55352006-02-08 11:16:05 +00003352 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003353
3354 inv_check_sdp_in_incoming_msg(inv, tsx,
3355 e->body.tsx_state.src.rdata);
3356
Benny Prijono1f7767b2007-10-03 18:28:49 +00003357 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3358 inv_handle_incoming_reliable_response(
3359 inv, e->body.tsx_state.src.rdata);
3360 }
3361
Benny Prijono268ca612006-02-07 12:34:11 +00003362 } else {
3363 /* Ignore 100 (Trying) response, as it doesn't change
3364 * session state. It only ceases retransmissions.
3365 */
3366 }
3367 break;
3368
3369 case PJSIP_TSX_STATE_COMPLETED:
3370 if (tsx->status_code/100 == 2) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003371
Benny Prijono268ca612006-02-07 12:34:11 +00003372 /* This should not happen.
3373 * When transaction receives 2xx, it should be terminated
3374 */
3375 pj_assert(0);
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003376
3377 /* Process session timer response. */
3378 status = handle_timer_response(inv,
3379 e->body.tsx_state.src.rdata,
3380 PJ_TRUE);
3381 if (status != PJ_SUCCESS)
3382 break;
3383
Benny Prijono8ad55352006-02-08 11:16:05 +00003384 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003385
3386 inv_check_sdp_in_incoming_msg(inv, tsx,
3387 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00003388
3389 } else {
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003390 handle_uac_call_rejection(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003391 }
3392 break;
3393
3394 case PJSIP_TSX_STATE_TERMINATED:
3395 /* INVITE transaction can be terminated either because UAC
3396 * transaction received 2xx response or because of transport
3397 * error.
3398 */
3399 if (tsx->status_code/100 == 2) {
3400 /* This must be receipt of 2xx response */
3401
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003402 /* Process session timer response. */
3403 status = handle_timer_response(inv,
3404 e->body.tsx_state.src.rdata,
3405 PJ_TRUE);
3406 if (status != PJ_SUCCESS)
3407 break;
3408
Benny Prijono268ca612006-02-07 12:34:11 +00003409 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003410 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003411
Benny Prijonoa66c7152006-02-09 01:26:14 +00003412 inv_check_sdp_in_incoming_msg(inv, tsx,
3413 e->body.tsx_state.src.rdata);
3414
Benny Prijono268ca612006-02-07 12:34:11 +00003415 /* Send ACK */
3416 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3417
Benny Prijonod5f9f422007-11-25 04:40:07 +00003418 inv_send_ack(inv, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003419
Benny Prijono268ca612006-02-07 12:34:11 +00003420 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003421 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003422 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003423 }
3424 break;
3425
Benny Prijono34a404e2006-02-09 14:38:30 +00003426 default:
3427 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003428 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003429
Benny Prijono1f7767b2007-10-03 18:28:49 +00003430 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003431 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003432 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003433 * Transaction Does Not Exist), 408, or when it's timed out. In these
3434 * cases, disconnect session (i.e. dialog usage only).
Benny Prijonoc5145762007-11-23 12:04:40 +00003435 * Note that 481 response to CANCEL does not terminate dialog usage,
3436 * but only the transaction.
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003437 */
Benny Prijonoc5145762007-11-23 12:04:40 +00003438 if ((tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST &&
3439 tsx->method.id != PJSIP_CANCEL_METHOD) ||
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003440 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3441 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00003442 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003443 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003444 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003445 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3446 }
Benny Prijono268ca612006-02-07 12:34:11 +00003447 }
3448}
3449
Benny Prijono8ad55352006-02-08 11:16:05 +00003450/*
3451 * State INCOMING is after we received the request, but before
3452 * responses with tag are sent.
3453 */
3454static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003455{
3456 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3457 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3458
3459 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3460
Benny Prijono8ad55352006-02-08 11:16:05 +00003461 if (tsx == inv->invite_tsx) {
3462
3463 /*
3464 * Handle the INVITE state transition.
3465 */
3466
Benny Prijono268ca612006-02-07 12:34:11 +00003467 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003468
Benny Prijono64f851e2006-02-23 13:49:28 +00003469 case PJSIP_TSX_STATE_TRYING:
3470 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
3471 break;
3472
Benny Prijono268ca612006-02-07 12:34:11 +00003473 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00003474 /*
3475 * Transaction sent provisional response.
3476 */
Benny Prijono268ca612006-02-07 12:34:11 +00003477 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00003478 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003479 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003480
Benny Prijono268ca612006-02-07 12:34:11 +00003481 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003482 /*
3483 * Transaction sent final response.
3484 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003485 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003486 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003487 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003488 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003489 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003490 }
Benny Prijono268ca612006-02-07 12:34:11 +00003491 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003492
Benny Prijono268ca612006-02-07 12:34:11 +00003493 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00003494 /*
3495 * This happens on transport error (e.g. failed to send
3496 * response)
3497 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003498 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003499 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003500 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00003501
Benny Prijono268ca612006-02-07 12:34:11 +00003502 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003503 pj_assert(!"Unexpected INVITE state");
3504 break;
Benny Prijono268ca612006-02-07 12:34:11 +00003505 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003506
3507 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3508 tsx->role == PJSIP_ROLE_UAS &&
3509 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3510 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3511 {
3512
3513 /*
3514 * Handle incoming CANCEL request.
3515 */
3516
3517 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3518
Benny Prijono268ca612006-02-07 12:34:11 +00003519 }
3520}
3521
Benny Prijono8ad55352006-02-08 11:16:05 +00003522/*
3523 * State EARLY is for both UAS and UAC, after response with To tag
3524 * is sent/received.
3525 */
3526static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003527{
3528 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3529 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3530
3531 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3532
Benny Prijono8ad55352006-02-08 11:16:05 +00003533 if (tsx == inv->invite_tsx) {
3534
3535 /*
3536 * Handle the INVITE state progress.
3537 */
Benny Prijono268ca612006-02-07 12:34:11 +00003538
3539 switch (tsx->state) {
3540
3541 case PJSIP_TSX_STATE_PROCEEDING:
3542 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00003543 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003544
3545 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3546 inv_check_sdp_in_incoming_msg(inv, tsx,
3547 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003548
3549 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
3550 inv_handle_incoming_reliable_response(
3551 inv, e->body.tsx_state.src.rdata);
3552 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00003553 }
Benny Prijono268ca612006-02-07 12:34:11 +00003554 break;
3555
3556 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00003557 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00003558 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00003559 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003560 pj_status_t status;
3561
3562 /* Process session timer response. */
3563 status = handle_timer_response(inv,
3564 e->body.tsx_state.src.rdata,
3565 PJ_TRUE);
3566 if (status != PJ_SUCCESS)
3567 break;
3568
Benny Prijonoa66c7152006-02-09 01:26:14 +00003569 inv_check_sdp_in_incoming_msg(inv, tsx,
3570 e->body.tsx_state.src.rdata);
3571 }
3572
Benny Prijono5e51a4e2008-11-27 00:06:46 +00003573 } else if (tsx->role == PJSIP_ROLE_UAC) {
3574
3575 handle_uac_call_rejection(inv, e);
3576
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003577 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003578 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003579 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00003580 }
Benny Prijono268ca612006-02-07 12:34:11 +00003581 break;
3582
Benny Prijonof3195072006-02-14 21:15:30 +00003583 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003584 /* For some reason can go here (maybe when ACK for 2xx has
3585 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00003586
Benny Prijono268ca612006-02-07 12:34:11 +00003587 case PJSIP_TSX_STATE_TERMINATED:
3588 /* INVITE transaction can be terminated either because UAC
3589 * transaction received 2xx response or because of transport
3590 * error.
3591 */
3592 if (tsx->status_code/100 == 2) {
3593
3594 /* This must be receipt of 2xx response */
3595
3596 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00003597 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003598
Benny Prijonoa66c7152006-02-09 01:26:14 +00003599 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00003600 pj_status_t status;
3601
3602 /* Process session timer response. */
3603 status = handle_timer_response(inv,
3604 e->body.tsx_state.src.rdata,
3605 PJ_TRUE);
3606 if (status != PJ_SUCCESS)
3607 break;
3608
Benny Prijonoa66c7152006-02-09 01:26:14 +00003609 inv_check_sdp_in_incoming_msg(inv, tsx,
3610 e->body.tsx_state.src.rdata);
3611 }
3612
Benny Prijono268ca612006-02-07 12:34:11 +00003613 /* if UAC, send ACK and move state to confirmed. */
3614 if (tsx->role == PJSIP_ROLE_UAC) {
3615 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3616
Benny Prijonod5f9f422007-11-25 04:40:07 +00003617 inv_send_ack(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003618 }
3619
3620 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00003621 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00003622 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003623 }
3624 break;
3625
3626 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00003627 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00003628 }
3629
Benny Prijono8ad55352006-02-08 11:16:05 +00003630 } else if (inv->role == PJSIP_ROLE_UAS &&
3631 tsx->role == PJSIP_ROLE_UAS &&
3632 tsx->method.id == PJSIP_CANCEL_METHOD &&
3633 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
3634 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
3635 {
Benny Prijono268ca612006-02-07 12:34:11 +00003636
Benny Prijono8ad55352006-02-08 11:16:05 +00003637 /*
3638 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00003639 */
3640
Benny Prijono8ad55352006-02-08 11:16:05 +00003641 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
3642
Benny Prijono1f7767b2007-10-03 18:28:49 +00003643 } else if (tsx->role == PJSIP_ROLE_UAS &&
3644 tsx->state == PJSIP_TSX_STATE_TRYING &&
3645 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00003646 {
3647 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00003648 * Handle incoming UPDATE
3649 */
3650 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3651
3652
3653 } else if (tsx->role == PJSIP_ROLE_UAC &&
3654 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3655 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3656 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3657 {
3658 /*
3659 * Handle response to outgoing UPDATE request.
3660 */
3661 inv_handle_update_response(inv, e);
3662
3663 } else if (tsx->role == PJSIP_ROLE_UAS &&
3664 tsx->state == PJSIP_TSX_STATE_TRYING &&
3665 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3666 {
3667 /*
3668 * Handle incoming PRACK
3669 */
3670 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3671
3672 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003673
3674 /* Generic handling for UAC tsx completion */
3675 handle_uac_tsx_response(inv, e);
Benny Prijono7efa2d62009-04-27 12:50:16 +00003676
3677 } else if (tsx->role == PJSIP_ROLE_UAS &&
3678 tsx->method.id == PJSIP_BYE_METHOD &&
3679 tsx->status_code < 200 &&
3680 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3681 {
3682 /* Received BYE before the 2xx/OK response to INVITE.
3683 * Assume that the 2xx/OK response is lost and the BYE
3684 * arrives earlier.
3685 */
3686 inv_respond_incoming_bye(inv, tsx, e->body.tsx_state.src.rdata, e);
3687
3688 /* Set timer just in case we will never get the final response
3689 * for INVITE.
3690 */
3691 pjsip_tsx_set_timeout(inv->invite_tsx, 64*pjsip_cfg()->tsx.t1);
Benny Prijono268ca612006-02-07 12:34:11 +00003692 }
3693}
3694
Benny Prijono8ad55352006-02-08 11:16:05 +00003695/*
3696 * State CONNECTING is after 2xx response to INVITE is sent/received.
3697 */
3698static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003699{
3700 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3701 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3702
3703 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3704
Benny Prijono8ad55352006-02-08 11:16:05 +00003705 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00003706
Benny Prijono8ad55352006-02-08 11:16:05 +00003707 /*
3708 * Handle INVITE state progression.
3709 */
Benny Prijono268ca612006-02-07 12:34:11 +00003710 switch (tsx->state) {
3711
3712 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00003713 /* It can only go here if incoming ACK request has the same Via
3714 * branch parameter as the INVITE transaction.
3715 */
3716 if (tsx->status_code/100 == 2) {
3717 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
3718 inv_check_sdp_in_incoming_msg(inv, tsx,
3719 e->body.tsx_state.src.rdata);
3720 }
3721
Benny Prijono38998232006-02-08 22:44:25 +00003722 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00003723 }
Benny Prijono268ca612006-02-07 12:34:11 +00003724 break;
3725
3726 case PJSIP_TSX_STATE_TERMINATED:
3727 /* INVITE transaction can be terminated either because UAC
3728 * transaction received 2xx response or because of transport
3729 * error.
3730 */
3731 if (tsx->status_code/100 != 2) {
Benny Prijono0ef4e192010-09-28 08:03:23 +00003732 if (tsx->role == PJSIP_ROLE_UAC) {
3733 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3734 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3735 } else {
3736 pjsip_tx_data *bye;
3737 pj_status_t status;
3738
3739 /* Send BYE */
3740 status = pjsip_dlg_create_request(inv->dlg,
3741 pjsip_get_bye_method(),
3742 -1, &bye);
3743 if (status == PJ_SUCCESS) {
3744 pjsip_inv_send_msg(inv, bye);
3745 }
3746 }
Benny Prijono268ca612006-02-07 12:34:11 +00003747 }
3748 break;
3749
3750 case PJSIP_TSX_STATE_DESTROYED:
3751 /* Do nothing. */
3752 break;
3753
3754 default:
3755 pj_assert(!"Unexpected state");
3756 }
3757
Benny Prijono8ad55352006-02-08 11:16:05 +00003758 } else if (tsx->role == PJSIP_ROLE_UAS &&
3759 tsx->method.id == PJSIP_BYE_METHOD &&
3760 tsx->status_code < 200 &&
3761 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3762 {
3763
3764 /*
3765 * Handle incoming BYE.
3766 */
3767
3768 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3769
Benny Prijono38998232006-02-08 22:44:25 +00003770 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
3771 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003772 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3773 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00003774 {
3775
3776 /*
3777 * Outgoing BYE
3778 */
3779 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
3780
Benny Prijono268ca612006-02-07 12:34:11 +00003781 }
Benny Prijono70127222006-07-02 14:53:05 +00003782 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3783 tsx->role == PJSIP_ROLE_UAS &&
3784 tsx->status_code < 200 &&
3785 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3786 {
Benny Prijono38998232006-02-08 22:44:25 +00003787
Benny Prijono70127222006-07-02 14:53:05 +00003788 /*
3789 * Handle strandled incoming CANCEL.
3790 */
3791 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3792 pjsip_tx_data *tdata;
3793 pj_status_t status;
3794
3795 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3796 if (status != PJ_SUCCESS) return;
3797
3798 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3799 if (status != PJ_SUCCESS) return;
3800
Benny Prijono1f7767b2007-10-03 18:28:49 +00003801 } else if (tsx->role == PJSIP_ROLE_UAS &&
3802 tsx->state == PJSIP_TSX_STATE_TRYING &&
3803 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3804 {
3805 /*
3806 * Handle incoming UPDATE
3807 */
3808 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3809
3810
3811 } else if (tsx->role == PJSIP_ROLE_UAC &&
3812 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3813 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3814 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3815 {
3816 /*
3817 * Handle response to outgoing UPDATE request.
3818 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003819 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00003820 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00003821
3822 } else if (tsx->role == PJSIP_ROLE_UAS &&
3823 tsx->state == PJSIP_TSX_STATE_TRYING &&
3824 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3825 {
3826 /*
3827 * Handle incoming PRACK
3828 */
3829 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3830
3831 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijono87402382008-02-21 19:28:21 +00003832
Benny Prijono0b4c57b2008-06-25 10:15:01 +00003833 /* Generic handling for UAC tsx completion */
3834 handle_uac_tsx_response(inv, e);
Benny Prijono70127222006-07-02 14:53:05 +00003835 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003836
Benny Prijono268ca612006-02-07 12:34:11 +00003837}
3838
Benny Prijono8ad55352006-02-08 11:16:05 +00003839/*
3840 * State CONFIRMED is after ACK is sent/received.
3841 */
3842static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003843{
3844 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3845 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
3846
3847 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3848
Benny Prijono268ca612006-02-07 12:34:11 +00003849
Benny Prijono8ad55352006-02-08 11:16:05 +00003850 if (tsx->method.id == PJSIP_BYE_METHOD &&
3851 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00003852 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3853 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00003854 {
Benny Prijono38998232006-02-08 22:44:25 +00003855
Benny Prijono8ad55352006-02-08 11:16:05 +00003856 /*
Benny Prijono38998232006-02-08 22:44:25 +00003857 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00003858 */
Benny Prijono8ad55352006-02-08 11:16:05 +00003859
Benny Prijonoa66c7152006-02-09 01:26:14 +00003860 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00003861
Benny Prijono8ad55352006-02-08 11:16:05 +00003862 }
3863 else if (tsx->method.id == PJSIP_BYE_METHOD &&
3864 tsx->role == PJSIP_ROLE_UAS &&
3865 tsx->status_code < 200 &&
3866 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3867 {
Benny Prijonoccf95622006-02-07 18:48:01 +00003868
Benny Prijono8ad55352006-02-08 11:16:05 +00003869 /*
3870 * Handle incoming BYE.
3871 */
Benny Prijono268ca612006-02-07 12:34:11 +00003872
Benny Prijono8ad55352006-02-08 11:16:05 +00003873 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
3874
Benny Prijono268ca612006-02-07 12:34:11 +00003875 }
Benny Prijono70127222006-07-02 14:53:05 +00003876 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
3877 tsx->role == PJSIP_ROLE_UAS &&
3878 tsx->status_code < 200 &&
3879 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3880 {
3881
3882 /*
3883 * Handle strandled incoming CANCEL.
3884 */
3885 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3886 pjsip_tx_data *tdata;
3887 pj_status_t status;
3888
3889 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3890 if (status != PJ_SUCCESS) return;
3891
3892 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3893 if (status != PJ_SUCCESS) return;
3894
3895 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003896 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3897 tsx->role == PJSIP_ROLE_UAS)
3898 {
3899
3900 /*
3901 * Handle incoming re-INVITE
3902 */
3903 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
3904
3905 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
3906 pjsip_tx_data *tdata;
3907 pj_status_t status;
Benny Prijono1c1d7342010-08-01 09:48:51 +00003908 pjsip_rdata_sdp_info *sdp_info;
Nanang Izzuddin65add622009-08-11 16:26:20 +00003909 pjsip_status_code st_code;
Benny Prijono26ff9062006-02-21 23:47:00 +00003910
3911 /* Check if we have INVITE pending. */
3912 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00003913 pj_str_t reason;
3914
3915 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00003916
3917 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00003918 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
3919 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003920 if (status != PJ_SUCCESS)
3921 return;
3922
3923 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
3924
3925
3926 return;
3927 }
3928
3929 /* Save the invite transaction. */
3930 inv->invite_tsx = tsx;
3931
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003932 /* Process session timers headers in the re-INVITE */
Nanang Izzuddin65add622009-08-11 16:26:20 +00003933 status = pjsip_timer_process_req(inv, rdata, &st_code);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003934 if (status != PJ_SUCCESS) {
Nanang Izzuddin65add622009-08-11 16:26:20 +00003935 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code,
3936 NULL, &tdata);
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00003937 if (status != PJ_SUCCESS)
3938 return;
3939
3940 pjsip_timer_update_resp(inv, tdata);
3941 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3942 return;
3943 }
3944
Benny Prijono26ff9062006-02-21 23:47:00 +00003945 /* Process SDP in incoming message. */
3946 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
3947
3948 if (status != PJ_SUCCESS) {
3949
3950 /* Not Acceptable */
3951 const pjsip_hdr *accept;
3952
3953 status = pjsip_dlg_create_response(inv->dlg, rdata,
3954 488, NULL, &tdata);
3955 if (status != PJ_SUCCESS)
3956 return;
3957
3958
3959 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
3960 NULL);
3961 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00003962 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003963 pjsip_hdr_clone(tdata->pool, accept));
3964 }
3965
3966 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3967
3968 return;
3969 }
3970
3971 /* Create 2xx ANSWER */
3972 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3973 if (status != PJ_SUCCESS)
3974 return;
3975
Benny Prijono7d910092007-06-20 04:19:46 +00003976 /* If the INVITE request has SDP body, send answer.
3977 * Otherwise generate offer from local active SDP.
3978 */
Benny Prijono1c1d7342010-08-01 09:48:51 +00003979 sdp_info = pjsip_rdata_get_sdp_info(rdata);
3980 if (sdp_info->sdp != NULL) {
Benny Prijono7d910092007-06-20 04:19:46 +00003981 status = process_answer(inv, 200, tdata, NULL);
3982 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003983 /* INVITE does not have SDP.
3984 * If on_create_offer() callback is implemented, ask app.
3985 * to generate an offer, otherwise just send active local
3986 * SDP to signal that nothing gets modified.
3987 */
3988 pjmedia_sdp_session *sdp = NULL;
3989
3990 if (mod_inv.cb.on_create_offer) {
3991 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3992 if (sdp) {
Benny Prijono60e31fc2009-04-23 11:50:25 +00003993 /* Notify negotiator about the new offer. This will
3994 * fix the offer with correct SDP origin.
3995 */
Benny Prijono40d62b62009-08-12 17:53:47 +00003996 status =
3997 pjmedia_sdp_neg_modify_local_offer(inv->pool_prov,
3998 inv->neg,
3999 sdp);
Benny Prijono60e31fc2009-04-23 11:50:25 +00004000
4001 /* Retrieve the "fixed" offer from negotiator */
Benny Prijonoc8fe3df2009-04-29 20:56:57 +00004002 if (status==PJ_SUCCESS) {
4003 const pjmedia_sdp_session *lsdp = NULL;
4004 pjmedia_sdp_neg_get_neg_local(inv->neg, &lsdp);
4005 sdp = (pjmedia_sdp_session*)lsdp;
4006 }
Benny Prijono77998ce2007-06-20 10:03:46 +00004007 }
4008 }
4009
4010 if (sdp == NULL) {
4011 const pjmedia_sdp_session *active_sdp = NULL;
Benny Prijono40d62b62009-08-12 17:53:47 +00004012 status = pjmedia_sdp_neg_send_local_offer(inv->pool_prov,
Benny Prijono77998ce2007-06-20 10:03:46 +00004013 inv->neg,
4014 &active_sdp);
4015 if (status == PJ_SUCCESS)
4016 sdp = (pjmedia_sdp_session*) active_sdp;
4017 }
4018
4019 if (sdp) {
4020 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00004021 }
4022 }
Benny Prijono26ff9062006-02-21 23:47:00 +00004023
Benny Prijono1d9b9a42006-09-25 13:40:12 +00004024 if (status != PJ_SUCCESS) {
4025 /*
4026 * SDP negotiation has failed.
4027 */
4028 pj_status_t rc;
4029 pj_str_t reason;
4030
4031 /* Delete the 2xx answer */
4032 pjsip_tx_data_dec_ref(tdata);
4033
4034 /* Create 500 response */
4035 reason = pj_str("SDP negotiation failed");
4036 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
4037 &tdata);
4038 if (rc == PJ_SUCCESS) {
4039 pjsip_warning_hdr *w;
4040 const pj_str_t *endpt_name;
4041
4042 endpt_name = pjsip_endpt_name(dlg->endpt);
4043 w = pjsip_warning_hdr_create_from_status(tdata->pool,
4044 endpt_name,
4045 status);
4046 if (w)
4047 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
4048
4049 pjsip_inv_send_msg(inv, tdata);
4050 }
4051 return;
4052 }
4053
Nanang Izzuddin59dffb12009-08-11 12:42:38 +00004054 /* Invoke Session Timers */
4055 pjsip_timer_update_resp(inv, tdata);
4056
Benny Prijono1d9b9a42006-09-25 13:40:12 +00004057 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00004058 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00004059
Benny Prijono7d910092007-06-20 04:19:46 +00004060 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
4061 /* This is the case where ACK has the same branch as
4062 * the INVITE request.
4063 */
4064 if (tsx->status_code/100 == 2 &&
4065 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
4066 {
4067 inv_check_sdp_in_incoming_msg(inv, tsx,
4068 e->body.tsx_state.src.rdata);
Nanang Izzuddin0fd92672010-06-16 15:26:18 +00004069
4070 /* Check if local offer got no SDP answer */
4071 if (pjmedia_sdp_neg_get_state(inv->neg)==
4072 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
4073 {
4074 pjmedia_sdp_neg_cancel_offer(inv->neg);
4075 }
Benny Prijono7d910092007-06-20 04:19:46 +00004076 }
4077
Benny Prijono26ff9062006-02-21 23:47:00 +00004078 }
4079
4080 }
4081 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
4082 tsx->role == PJSIP_ROLE_UAC)
4083 {
Benny Prijono22e48c92008-03-20 14:40:50 +00004084
Benny Prijono26ff9062006-02-21 23:47:00 +00004085 /*
4086 * Handle outgoing re-INVITE
4087 */
Benny Prijono22e48c92008-03-20 14:40:50 +00004088 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
4089
Benny Prijono61fc5e62008-06-25 18:35:31 +00004090 /* Must not have other pending INVITE transaction */
4091 pj_assert(inv->invite_tsx==NULL || tsx==inv->invite_tsx);
4092
Benny Prijono22e48c92008-03-20 14:40:50 +00004093 /* Save pending invite transaction */
4094 inv->invite_tsx = tsx;
4095
4096 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
4097 tsx->status_code/100 == 2)
Benny Prijono26ff9062006-02-21 23:47:00 +00004098 {
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004099 pj_status_t status;
Benny Prijono26ff9062006-02-21 23:47:00 +00004100
4101 /* Re-INVITE was accepted. */
4102
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004103 /* Process session timer response. */
4104 status = handle_timer_response(inv,
4105 e->body.tsx_state.src.rdata,
4106 PJ_TRUE);
4107 if (status != PJ_SUCCESS)
4108 return;
4109
Benny Prijono26ff9062006-02-21 23:47:00 +00004110 /* Process SDP */
4111 inv_check_sdp_in_incoming_msg(inv, tsx,
4112 e->body.tsx_state.src.rdata);
4113
Nanang Izzuddin0fd92672010-06-16 15:26:18 +00004114 /* Check if local offer got no SDP answer */
4115 if (pjmedia_sdp_neg_get_state(inv->neg)==
4116 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
4117 {
4118 pjmedia_sdp_neg_cancel_offer(inv->neg);
4119 }
4120
Benny Prijono26ff9062006-02-21 23:47:00 +00004121 /* Send ACK */
Benny Prijonod5f9f422007-11-25 04:40:07 +00004122 inv_send_ack(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00004123
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004124 } else if (handle_uac_tsx_response(inv, e)) {
Benny Prijono87402382008-02-21 19:28:21 +00004125
4126 /* Handle response that terminates dialog */
4127 /* Nothing to do (already handled) */
4128
Benny Prijono77998ce2007-06-20 10:03:46 +00004129 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
4130
4131 pjmedia_sdp_neg_state neg_state;
4132
4133 /* Outgoing INVITE transaction has failed, cancel SDP nego */
4134 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
4135 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
4136 pjmedia_sdp_neg_cancel_offer(inv->neg);
4137 }
Benny Prijonoe641a742009-05-01 12:01:28 +00004138
4139 if (tsx == inv->invite_tsx)
4140 inv->invite_tsx = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00004141 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00004142
4143 } else if (tsx->role == PJSIP_ROLE_UAS &&
4144 tsx->state == PJSIP_TSX_STATE_TRYING &&
4145 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
4146 {
4147 /*
4148 * Handle incoming UPDATE
4149 */
4150 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
4151
4152 } else if (tsx->role == PJSIP_ROLE_UAC &&
4153 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
4154 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
4155 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
4156 {
4157 /*
4158 * Handle response to outgoing UPDATE request.
4159 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004160 if (handle_uac_tsx_response(inv, e) == PJ_FALSE)
Benny Prijono87402382008-02-21 19:28:21 +00004161 inv_handle_update_response(inv, e);
Benny Prijono1f7767b2007-10-03 18:28:49 +00004162
4163 } else if (tsx->role == PJSIP_ROLE_UAS &&
4164 tsx->state == PJSIP_TSX_STATE_TRYING &&
4165 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
4166 {
4167 /*
4168 * Handle strandled incoming PRACK
4169 */
4170 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
4171
4172 } else if (tsx->role == PJSIP_ROLE_UAC) {
4173 /*
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004174 * Handle 401/407/408/481/422 response
Benny Prijono1f7767b2007-10-03 18:28:49 +00004175 */
Benny Prijono0b4c57b2008-06-25 10:15:01 +00004176 handle_uac_tsx_response(inv, e);
Benny Prijono26ff9062006-02-21 23:47:00 +00004177 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00004178
Benny Prijono268ca612006-02-07 12:34:11 +00004179}
4180
Benny Prijono8ad55352006-02-08 11:16:05 +00004181/*
4182 * After session has been terminated, but before dialog is destroyed
4183 * (because dialog has other usages, or because dialog is waiting for
4184 * the last transaction to terminate).
4185 */
4186static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00004187{
Benny Prijono8ad55352006-02-08 11:16:05 +00004188 pjsip_transaction *tsx = e->body.tsx_state.tsx;
4189 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00004190
Benny Prijono8ad55352006-02-08 11:16:05 +00004191 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
4192
Benny Prijono70127222006-07-02 14:53:05 +00004193 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00004194 tsx->status_code < 200 &&
4195 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
4196 {
Benny Prijono70127222006-07-02 14:53:05 +00004197 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00004198
4199 /*
Benny Prijono70127222006-07-02 14:53:05 +00004200 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00004201 */
Benny Prijono70127222006-07-02 14:53:05 +00004202 if (tsx->method.id == PJSIP_BYE_METHOD) {
4203 inv_respond_incoming_bye( inv, tsx, rdata, e );
4204 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
4205 /*
4206 * Respond CANCEL with 200/OK too.
4207 */
4208 pjsip_tx_data *tdata;
4209 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00004210
Benny Prijono70127222006-07-02 14:53:05 +00004211 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
4212 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00004213
Benny Prijono70127222006-07-02 14:53:05 +00004214 status = pjsip_dlg_send_response(dlg, tsx, tdata);
4215 if (status != PJ_SUCCESS) return;
4216
4217 }
Benny Prijono61fc5e62008-06-25 18:35:31 +00004218
4219 } else if (tsx->role == PJSIP_ROLE_UAC) {
4220 /*
Nanang Izzuddincf69c282009-10-16 06:28:56 +00004221 * Handle 401/407/408/481/422 response
Benny Prijono61fc5e62008-06-25 18:35:31 +00004222 */
4223 handle_uac_tsx_response(inv, e);
Benny Prijono8ad55352006-02-08 11:16:05 +00004224 }
Benny Prijono268ca612006-02-07 12:34:11 +00004225}
4226