blob: 6c7fe222bd555951c421f6328cd44552d212e6ab [file] [log] [blame]
Benny Prijono268ca612006-02-07 12:34:11 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono268ca612006-02-07 12:34:11 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjsip-ua/sip_inv.h>
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000020#include <pjsip-ua/sip_100rel.h>
Benny Prijono268ca612006-02-07 12:34:11 +000021#include <pjsip/sip_module.h>
22#include <pjsip/sip_endpoint.h>
23#include <pjsip/sip_event.h>
24#include <pjsip/sip_transaction.h>
25#include <pjmedia/sdp.h>
26#include <pjmedia/sdp_neg.h>
Benny Prijono95196582006-02-09 00:13:40 +000027#include <pjmedia/errno.h>
Benny Prijono268ca612006-02-07 12:34:11 +000028#include <pj/string.h>
29#include <pj/pool.h>
30#include <pj/assert.h>
Benny Prijono8ad55352006-02-08 11:16:05 +000031#include <pj/os.h>
Benny Prijonoa66c7152006-02-09 01:26:14 +000032#include <pj/log.h>
33
Benny Prijono1f7767b2007-10-03 18:28:49 +000034/*
35 * Note on offer/answer:
36 *
37 * The offer/answer framework in this implementation assumes the occurence
38 * of SDP in a particular request/response according to this table:
39
40 offer answer Note:
41 ========================================================================
42 INVITE X INVITE may contain offer
43 18x/INVITE X X Response may contain offer or answer
44 2xx/INVITE X X Response may contain offer or answer
45 ACK X ACK may contain answer
46
47 PRACK X PRACK can only contain answer
48 2xx/PRACK Response may not have offer nor answer
49
50 UPDATE X UPDATE may only contain offer
51 2xx/UPDATE X Response may only contain answer
52 ========================================================================
53
54 *
55 */
Benny Prijono268ca612006-02-07 12:34:11 +000056
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000057#define THIS_FILE "sip_inv.c"
Benny Prijono268ca612006-02-07 12:34:11 +000058
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000059static const char *inv_state_names[] =
60{
Benny Prijono4be63b52006-11-25 14:50:25 +000061 "NULL",
62 "CALLING",
63 "INCOMING",
64 "EARLY",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000065 "CONNECTING",
Benny Prijonoc5055702007-01-13 23:20:18 +000066 "CONFIRMED",
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +000067 "DISCONNCTD",
68 "TERMINATED",
69};
70
Benny Prijono1f7767b2007-10-03 18:28:49 +000071/* UPDATE method */
72const pjsip_method pjsip_update_method =
73{
74 PJSIP_OTHER_METHOD,
75 { "UPDATE", 6 }
76};
77
Benny Prijono268ca612006-02-07 12:34:11 +000078/*
79 * Static prototypes.
80 */
81static pj_status_t mod_inv_load(pjsip_endpoint *endpt);
82static pj_status_t mod_inv_unload(void);
83static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata);
84static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata);
85static void mod_inv_on_tsx_state(pjsip_transaction*, pjsip_event*);
86
Benny Prijono8ad55352006-02-08 11:16:05 +000087static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e);
88static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e);
89static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e);
90static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e);
91static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e);
92static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e);
93static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e);
Benny Prijono268ca612006-02-07 12:34:11 +000094
Benny Prijono7d910092007-06-20 04:19:46 +000095static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
96 pjsip_transaction *tsx,
97 pjsip_rx_data *rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +000098static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv );
99static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
100 const pjmedia_sdp_session *c_sdp);
Benny Prijono7d910092007-06-20 04:19:46 +0000101static pj_status_t process_answer( pjsip_inv_session *inv,
102 int st_code,
103 pjsip_tx_data *tdata,
104 const pjmedia_sdp_session *local_sdp);
105
Benny Prijono8ad55352006-02-08 11:16:05 +0000106static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) =
Benny Prijono268ca612006-02-07 12:34:11 +0000107{
108 &inv_on_state_null,
109 &inv_on_state_calling,
110 &inv_on_state_incoming,
111 &inv_on_state_early,
112 &inv_on_state_connecting,
113 &inv_on_state_confirmed,
114 &inv_on_state_disconnected,
Benny Prijono268ca612006-02-07 12:34:11 +0000115};
116
117static struct mod_inv
118{
119 pjsip_module mod;
120 pjsip_endpoint *endpt;
121 pjsip_inv_callback cb;
Benny Prijono268ca612006-02-07 12:34:11 +0000122} mod_inv =
123{
124 {
Benny Prijono2f8992b2006-02-25 21:16:36 +0000125 NULL, NULL, /* prev, next. */
126 { "mod-invite", 10 }, /* Name. */
127 -1, /* Id */
128 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
129 &mod_inv_load, /* load() */
130 NULL, /* start() */
131 NULL, /* stop() */
132 &mod_inv_unload, /* unload() */
133 &mod_inv_on_rx_request, /* on_rx_request() */
134 &mod_inv_on_rx_response, /* on_rx_response() */
135 NULL, /* on_tx_request. */
136 NULL, /* on_tx_response() */
137 &mod_inv_on_tsx_state, /* on_tsx_state() */
Benny Prijono268ca612006-02-07 12:34:11 +0000138 }
139};
140
141
Benny Prijonoa66c7152006-02-09 01:26:14 +0000142/* Invite session data to be attached to transaction. */
143struct tsx_inv_data
144{
145 pjsip_inv_session *inv;
146 pj_bool_t sdp_done;
147};
148
Benny Prijono8ad55352006-02-08 11:16:05 +0000149/*
150 * Module load()
151 */
Benny Prijono268ca612006-02-07 12:34:11 +0000152static pj_status_t mod_inv_load(pjsip_endpoint *endpt)
153{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000154 pj_str_t allowed[] = {{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},
155 { "UPDATE", 6}};
Benny Prijono56315612006-07-18 14:39:40 +0000156 pj_str_t accepted = { "application/sdp", 15 };
Benny Prijono268ca612006-02-07 12:34:11 +0000157
Benny Prijono1f7767b2007-10-03 18:28:49 +0000158 /* Register supported methods: INVITE, ACK, BYE, CANCEL, UPDATE */
Benny Prijono268ca612006-02-07 12:34:11 +0000159 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ALLOW, NULL,
160 PJ_ARRAY_SIZE(allowed), allowed);
161
Benny Prijono56315612006-07-18 14:39:40 +0000162 /* Register "application/sdp" in Accept header */
163 pjsip_endpt_add_capability(endpt, &mod_inv.mod, PJSIP_H_ACCEPT, NULL,
164 1, &accepted);
165
Benny Prijono268ca612006-02-07 12:34:11 +0000166 return PJ_SUCCESS;
167}
168
Benny Prijono8ad55352006-02-08 11:16:05 +0000169/*
170 * Module unload()
171 */
Benny Prijono268ca612006-02-07 12:34:11 +0000172static pj_status_t mod_inv_unload(void)
173{
174 /* Should remove capability here */
175 return PJ_SUCCESS;
176}
177
Benny Prijono8ad55352006-02-08 11:16:05 +0000178/*
Benny Prijono38998232006-02-08 22:44:25 +0000179 * Set session state.
180 */
181void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
182 pjsip_event *e)
183{
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000184 pjsip_inv_state prev_state = inv->state;
Benny Prijono7d910092007-06-20 04:19:46 +0000185 pj_status_t status;
186
187
188 /* If state is confirmed, check that SDP negotiation is done,
189 * otherwise disconnect the session.
190 */
191 if (state == PJSIP_INV_STATE_CONFIRMED) {
192 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
193 pjsip_tx_data *bye;
194
195 PJ_LOG(4,(inv->obj_name, "SDP offer/answer incomplete, ending the "
196 "session"));
197
198 status = pjsip_inv_end_session(inv, PJSIP_SC_NOT_ACCEPTABLE,
199 NULL, &bye);
200 if (status == PJ_SUCCESS && bye)
201 status = pjsip_inv_send_msg(inv, bye);
202
203 return;
204 }
205 }
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000206
207 /* Set state. */
Benny Prijono38998232006-02-08 22:44:25 +0000208 inv->state = state;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000209
210 /* If state is DISCONNECTED, cause code MUST have been set. */
211 pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
212 inv->cause != 0);
213
214 /* Call on_state_changed() callback. */
215 if (mod_inv.cb.on_state_changed && inv->notify)
Benny Prijono38998232006-02-08 22:44:25 +0000216 (*mod_inv.cb.on_state_changed)(inv, e);
217
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000218 /* Only decrement when previous state is not already DISCONNECTED */
219 if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
220 prev_state != PJSIP_INV_STATE_DISCONNECTED)
221 {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000222 if (inv->last_ack) {
223 pjsip_tx_data_dec_ref(inv->last_ack);
224 inv->last_ack = NULL;
225 }
226 pjsip_100rel_end_session(inv);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000227 pjsip_dlg_dec_session(inv->dlg, &mod_inv.mod);
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000228 }
Benny Prijono38998232006-02-08 22:44:25 +0000229}
230
231
232/*
Benny Prijono0b6340c2006-06-13 22:21:23 +0000233 * Set cause code.
234 */
235void inv_set_cause(pjsip_inv_session *inv, int cause_code,
236 const pj_str_t *cause_text)
237{
238 if (cause_code > inv->cause) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000239 inv->cause = (pjsip_status_code) cause_code;
Benny Prijono0b6340c2006-06-13 22:21:23 +0000240 if (cause_text)
241 pj_strdup(inv->pool, &inv->cause_text, cause_text);
242 else if (cause_code/100 == 2)
243 inv->cause_text = pj_str("Normal call clearing");
244 else
245 inv->cause_text = *pjsip_get_status_text(cause_code);
246 }
247}
248
249
Benny Prijono1f7767b2007-10-03 18:28:49 +0000250/*
251 * Check if outgoing request needs to have SDP answer.
252 * This applies for both ACK and PRACK requests.
253 */
254static pjmedia_sdp_session *inv_has_pending_answer(pjsip_inv_session *inv,
255 pjsip_transaction *tsx)
256{
257 pjmedia_sdp_neg_state neg_state;
258 pjmedia_sdp_session *sdp = NULL;
259 pj_status_t status;
260
261 /* If SDP negotiator is ready, start negotiation. */
262
263 /* Start nego when appropriate. */
264 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
265 PJMEDIA_SDP_NEG_STATE_NULL;
266
267 if (neg_state == PJMEDIA_SDP_NEG_STATE_DONE) {
268
269 /* Nothing to do */
270
271 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
272 pjmedia_sdp_neg_has_local_answer(inv->neg) )
273 {
274 struct tsx_inv_data *tsx_inv_data;
275
276 /* Get invite session's transaction data */
277 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
278
279 status = inv_negotiate_sdp(inv);
280 if (status != PJ_SUCCESS)
281 return NULL;
282
283 /* Mark this transaction has having SDP offer/answer done. */
284 tsx_inv_data->sdp_done = 1;
285
286 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
287
288 } else {
289 /* This remark is only valid for ACK.
290 PJ_LOG(4,(inv->dlg->obj_name,
291 "FYI, the SDP negotiator state (%s) is in a mess "
292 "when sending this ACK/PRACK request",
293 pjmedia_sdp_neg_state_str(neg_state)));
294 */
295 }
296
297 return sdp;
298}
299
Benny Prijono0b6340c2006-06-13 22:21:23 +0000300
301/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000302 * Send ACK for 2xx response.
303 */
304static pj_status_t inv_send_ack(pjsip_inv_session *inv, pjsip_rx_data *rdata)
Benny Prijono268ca612006-02-07 12:34:11 +0000305{
Benny Prijono268ca612006-02-07 12:34:11 +0000306 pj_status_t status;
307
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000308 PJ_LOG(5,(inv->obj_name, "Received %s, sending ACK",
309 pjsip_rx_data_get_info(rdata)));
310
Benny Prijono1f7767b2007-10-03 18:28:49 +0000311 /* Check if we have cached ACK request */
312 if (inv->last_ack && rdata->msg_info.cseq->cseq == inv->last_ack_cseq) {
313 pjsip_tx_data_add_ref(inv->last_ack);
314 } else {
315 pjmedia_sdp_session *sdp = NULL;
316
317 /* Destroy last_ack */
318 if (inv->last_ack) {
319 pjsip_tx_data_dec_ref(inv->last_ack);
320 inv->last_ack = NULL;
321 }
322
323 /* Create new ACK request */
324 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_ack_method(),
325 rdata->msg_info.cseq->cseq,
326 &inv->last_ack);
327 if (status != PJ_SUCCESS) {
328 /* Better luck next time */
329 pj_assert(!"Unable to create ACK!");
330 return status;
331 }
332
333 /* See if we have pending SDP answer to send */
334 sdp = inv_has_pending_answer(inv, inv->invite_tsx);
335 if (sdp) {
336 inv->last_ack->msg->body=create_sdp_body(inv->last_ack->pool, sdp);
337 }
338
339
340 /* Keep this for subsequent response retransmission */
341 inv->last_ack_cseq = rdata->msg_info.cseq->cseq;
342 pjsip_tx_data_add_ref(inv->last_ack);
Benny Prijono268ca612006-02-07 12:34:11 +0000343 }
344
Benny Prijono1f7767b2007-10-03 18:28:49 +0000345 /* Send ACK */
346 status = pjsip_dlg_send_request(inv->dlg, inv->last_ack, -1, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000347 if (status != PJ_SUCCESS) {
348 /* Better luck next time */
349 pj_assert(!"Unable to send ACK!");
350 return status;
351 }
352
353 return PJ_SUCCESS;
354}
355
Benny Prijono8ad55352006-02-08 11:16:05 +0000356/*
357 * Module on_rx_request()
358 *
359 * This callback is called for these events:
360 * - endpoint receives request which was unhandled by higher priority
361 * modules (e.g. transaction layer, dialog layer).
362 * - dialog distributes incoming request to its usages.
363 */
364static pj_bool_t mod_inv_on_rx_request(pjsip_rx_data *rdata)
365{
366 pjsip_method *method;
Benny Prijono38998232006-02-08 22:44:25 +0000367 pjsip_dialog *dlg;
368 pjsip_inv_session *inv;
Benny Prijono8ad55352006-02-08 11:16:05 +0000369
370 /* Only wants to receive request from a dialog. */
Benny Prijono38998232006-02-08 22:44:25 +0000371 dlg = pjsip_rdata_get_dlg(rdata);
372 if (dlg == NULL)
Benny Prijono8ad55352006-02-08 11:16:05 +0000373 return PJ_FALSE;
374
Benny Prijonoa1e69682007-05-11 15:14:34 +0000375 inv = (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono38998232006-02-08 22:44:25 +0000376
Benny Prijono8ad55352006-02-08 11:16:05 +0000377 /* Report to dialog that we handle INVITE, CANCEL, BYE, ACK.
378 * If we need to send response, it will be sent in the state
379 * handlers.
380 */
381 method = &rdata->msg_info.msg->line.req.method;
382
Benny Prijono70127222006-07-02 14:53:05 +0000383 if (method->id == PJSIP_INVITE_METHOD) {
384 return PJ_TRUE;
385 }
386
387 /* BYE and CANCEL must have existing invite session */
388 if (method->id == PJSIP_BYE_METHOD ||
389 method->id == PJSIP_CANCEL_METHOD)
Benny Prijono8ad55352006-02-08 11:16:05 +0000390 {
Benny Prijono70127222006-07-02 14:53:05 +0000391 if (inv == NULL)
392 return PJ_FALSE;
393
Benny Prijono8ad55352006-02-08 11:16:05 +0000394 return PJ_TRUE;
395 }
396
Benny Prijono38998232006-02-08 22:44:25 +0000397 /* On receipt ACK request, when state is CONNECTING,
398 * move state to CONFIRMED.
399 */
Benny Prijono26ff9062006-02-21 23:47:00 +0000400 if (method->id == PJSIP_ACK_METHOD && inv) {
Benny Prijono38998232006-02-08 22:44:25 +0000401
Benny Prijonof521eb02006-08-06 23:07:25 +0000402 /* Ignore ACK if pending INVITE transaction has not finished. */
403 if (inv->invite_tsx &&
404 inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
405 {
406 return PJ_TRUE;
407 }
408
Benny Prijono5eff0432006-02-09 14:14:21 +0000409 /* Terminate INVITE transaction, if it's still present. */
410 if (inv->invite_tsx &&
411 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
412 {
Benny Prijono7d910092007-06-20 04:19:46 +0000413 /* Before we terminate INVITE transaction, process the SDP
414 * in the ACK request, if any.
415 */
416 inv_check_sdp_in_incoming_msg(inv, inv->invite_tsx, rdata);
417
418 /* Now we can terminate the INVITE transaction */
Benny Prijonof521eb02006-08-06 23:07:25 +0000419 pj_assert(inv->invite_tsx->status_code >= 200);
Benny Prijono5eff0432006-02-09 14:14:21 +0000420 pjsip_tsx_terminate(inv->invite_tsx,
421 inv->invite_tsx->status_code);
422 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000423 if (inv->last_answer) {
424 pjsip_tx_data_dec_ref(inv->last_answer);
425 inv->last_answer = NULL;
426 }
Benny Prijono5eff0432006-02-09 14:14:21 +0000427 }
428
Benny Prijono32ac8fe2006-03-02 21:16:55 +0000429 /* On receipt of ACK, only set state to confirmed when state
430 * is CONNECTING (e.g. we don't want to set the state to confirmed
431 * when we receive ACK retransmission after sending non-2xx!)
432 */
433 if (inv->state == PJSIP_INV_STATE_CONNECTING) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000434 pjsip_event event;
435
436 PJSIP_EVENT_INIT_RX_MSG(event, rdata);
437 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, &event);
438 }
Benny Prijono38998232006-02-08 22:44:25 +0000439 }
440
Benny Prijono8ad55352006-02-08 11:16:05 +0000441 return PJ_FALSE;
442}
443
444/*
445 * Module on_rx_response().
446 *
447 * This callback is called for these events:
448 * - dialog distributes incoming 2xx response to INVITE (outside
449 * transaction) to its usages.
450 * - endpoint distributes strayed responses.
451 */
Benny Prijono268ca612006-02-07 12:34:11 +0000452static pj_bool_t mod_inv_on_rx_response(pjsip_rx_data *rdata)
453{
454 pjsip_dialog *dlg;
455 pjsip_inv_session *inv;
456 pjsip_msg *msg = rdata->msg_info.msg;
457
458 dlg = pjsip_rdata_get_dlg(rdata);
459
460 /* Ignore responses outside dialog */
461 if (dlg == NULL)
462 return PJ_FALSE;
463
464 /* Ignore responses not belonging to invite session */
465 inv = pjsip_dlg_get_inv_session(dlg);
466 if (inv == NULL)
467 return PJ_FALSE;
468
469 /* This MAY be retransmission of 2xx response to INVITE.
470 * If it is, we need to send ACK.
471 */
472 if (msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/100==2 &&
Benny Prijono26ff9062006-02-21 23:47:00 +0000473 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD &&
474 inv->invite_tsx == NULL)
475 {
Benny Prijono268ca612006-02-07 12:34:11 +0000476
Benny Prijono853ab812007-06-12 15:40:38 +0000477 inv_send_ack(inv, rdata);
Benny Prijono268ca612006-02-07 12:34:11 +0000478 return PJ_TRUE;
479
480 }
481
482 /* No other processing needs to be done here. */
483 return PJ_FALSE;
484}
485
Benny Prijono8ad55352006-02-08 11:16:05 +0000486/*
487 * Module on_tsx_state()
488 *
489 * This callback is called by dialog framework for all transactions
490 * inside the dialog for all its dialog usages.
491 */
Benny Prijono268ca612006-02-07 12:34:11 +0000492static void mod_inv_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
493{
494 pjsip_dialog *dlg;
495 pjsip_inv_session *inv;
496
497 dlg = pjsip_tsx_get_dlg(tsx);
498 if (dlg == NULL)
499 return;
500
501 inv = pjsip_dlg_get_inv_session(dlg);
502 if (inv == NULL)
503 return;
504
505 /* Call state handler for the invite session. */
506 (*inv_state_handler[inv->state])(inv, e);
507
508 /* Call on_tsx_state */
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000509 if (mod_inv.cb.on_tsx_state_changed && inv->notify)
Benny Prijono268ca612006-02-07 12:34:11 +0000510 (*mod_inv.cb.on_tsx_state_changed)(inv, tsx, e);
511
Benny Prijono46249942007-02-19 22:23:14 +0000512 /* Clear invite transaction when tsx is confirmed.
513 * Previously we set invite_tsx to NULL only when transaction has
514 * terminated, but this didn't work when ACK has the same Via branch
515 * value as the INVITE (see http://www.pjsip.org/trac/ticket/113)
516 */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000517 if (tsx->state>=PJSIP_TSX_STATE_CONFIRMED && tsx == inv->invite_tsx) {
Benny Prijono46249942007-02-19 22:23:14 +0000518 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000519 if (inv->last_answer) {
520 pjsip_tx_data_dec_ref(inv->last_answer);
521 inv->last_answer = NULL;
522 }
523 }
Benny Prijono268ca612006-02-07 12:34:11 +0000524}
525
Benny Prijono8ad55352006-02-08 11:16:05 +0000526
527/*
528 * Initialize the invite module.
529 */
Benny Prijono268ca612006-02-07 12:34:11 +0000530PJ_DEF(pj_status_t) pjsip_inv_usage_init( pjsip_endpoint *endpt,
Benny Prijono268ca612006-02-07 12:34:11 +0000531 const pjsip_inv_callback *cb)
532{
533 pj_status_t status;
534
535 /* Check arguments. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000536 PJ_ASSERT_RETURN(endpt && cb, PJ_EINVAL);
Benny Prijono268ca612006-02-07 12:34:11 +0000537
538 /* Some callbacks are mandatory */
539 PJ_ASSERT_RETURN(cb->on_state_changed && cb->on_new_session, PJ_EINVAL);
540
541 /* Check if module already registered. */
542 PJ_ASSERT_RETURN(mod_inv.mod.id == -1, PJ_EINVALIDOP);
543
544 /* Copy param. */
545 pj_memcpy(&mod_inv.cb, cb, sizeof(pjsip_inv_callback));
546
547 mod_inv.endpt = endpt;
Benny Prijono268ca612006-02-07 12:34:11 +0000548
549 /* Register the module. */
550 status = pjsip_endpt_register_module(endpt, &mod_inv.mod);
Benny Prijono053f5222006-11-11 16:16:04 +0000551 if (status != PJ_SUCCESS)
552 return status;
Benny Prijono268ca612006-02-07 12:34:11 +0000553
Benny Prijono053f5222006-11-11 16:16:04 +0000554 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +0000555}
556
Benny Prijono8ad55352006-02-08 11:16:05 +0000557/*
558 * Get the instance of invite module.
559 */
Benny Prijono268ca612006-02-07 12:34:11 +0000560PJ_DEF(pjsip_module*) pjsip_inv_usage_instance(void)
561{
562 return &mod_inv.mod;
563}
564
565
Benny Prijono632ce712006-02-09 14:01:40 +0000566
Benny Prijono8ad55352006-02-08 11:16:05 +0000567/*
568 * Return the invite session for the specified dialog.
569 */
Benny Prijono268ca612006-02-07 12:34:11 +0000570PJ_DEF(pjsip_inv_session*) pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
571{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000572 return (pjsip_inv_session*) dlg->mod_data[mod_inv.mod.id];
Benny Prijono268ca612006-02-07 12:34:11 +0000573}
574
Benny Prijono8ad55352006-02-08 11:16:05 +0000575
Benny Prijono268ca612006-02-07 12:34:11 +0000576/*
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +0000577 * Get INVITE state name.
578 */
579PJ_DEF(const char *) pjsip_inv_state_name(pjsip_inv_state state)
580{
581 PJ_ASSERT_RETURN(state >= PJSIP_INV_STATE_NULL &&
582 state <= PJSIP_INV_STATE_DISCONNECTED,
583 "??");
584
585 return inv_state_names[state];
586}
587
588/*
Benny Prijono8ad55352006-02-08 11:16:05 +0000589 * Create UAC invite session.
Benny Prijono268ca612006-02-07 12:34:11 +0000590 */
591PJ_DEF(pj_status_t) pjsip_inv_create_uac( pjsip_dialog *dlg,
592 const pjmedia_sdp_session *local_sdp,
593 unsigned options,
594 pjsip_inv_session **p_inv)
595{
596 pjsip_inv_session *inv;
597 pj_status_t status;
598
599 /* Verify arguments. */
600 PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
601
Benny Prijono8eae8382006-08-10 21:44:26 +0000602 /* Must lock dialog first */
603 pjsip_dlg_inc_lock(dlg);
604
Benny Prijono268ca612006-02-07 12:34:11 +0000605 /* Normalize options */
606 if (options & PJSIP_INV_REQUIRE_100REL)
607 options |= PJSIP_INV_SUPPORT_100REL;
608
609 if (options & PJSIP_INV_REQUIRE_TIMER)
610 options |= PJSIP_INV_SUPPORT_TIMER;
611
612 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000613 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +0000614 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000615
616 inv->pool = dlg->pool;
617 inv->role = PJSIP_ROLE_UAC;
618 inv->state = PJSIP_INV_STATE_NULL;
619 inv->dlg = dlg;
620 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +0000621 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000622 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +0000623
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000624 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +0000625 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000626
Benny Prijono268ca612006-02-07 12:34:11 +0000627 /* Create negotiator if local_sdp is specified. */
628 if (local_sdp) {
629 status = pjmedia_sdp_neg_create_w_local_offer(dlg->pool, local_sdp,
630 &inv->neg);
Benny Prijono8eae8382006-08-10 21:44:26 +0000631 if (status != PJ_SUCCESS) {
632 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000633 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000634 }
Benny Prijono268ca612006-02-07 12:34:11 +0000635 }
636
637 /* Register invite as dialog usage. */
638 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +0000639 if (status != PJ_SUCCESS) {
640 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +0000641 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +0000642 }
Benny Prijono268ca612006-02-07 12:34:11 +0000643
644 /* Increment dialog session */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000645 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +0000646
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000647 /* Create 100rel handler */
648 pjsip_100rel_attach(inv);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000649
Benny Prijono268ca612006-02-07 12:34:11 +0000650 /* Done */
651 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000652
Benny Prijono8eae8382006-08-10 21:44:26 +0000653 pjsip_dlg_dec_lock(dlg);
654
Benny Prijonoe4f2abb2006-02-10 14:04:05 +0000655 PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
656 dlg->obj_name));
657
Benny Prijono268ca612006-02-07 12:34:11 +0000658 return PJ_SUCCESS;
659}
660
661/*
662 * Verify incoming INVITE request.
663 */
664PJ_DEF(pj_status_t) pjsip_inv_verify_request(pjsip_rx_data *rdata,
665 unsigned *options,
666 const pjmedia_sdp_session *l_sdp,
667 pjsip_dialog *dlg,
668 pjsip_endpoint *endpt,
669 pjsip_tx_data **p_tdata)
670{
671 pjsip_msg *msg;
672 pjsip_allow_hdr *allow;
673 pjsip_supported_hdr *sup_hdr;
674 pjsip_require_hdr *req_hdr;
675 int code = 200;
676 unsigned rem_option = 0;
677 pj_status_t status = PJ_SUCCESS;
678 pjsip_hdr res_hdr_list;
679
680 /* Init return arguments. */
681 if (p_tdata) *p_tdata = NULL;
682
683 /* Verify arguments. */
684 PJ_ASSERT_RETURN(rdata != NULL && options != NULL, PJ_EINVAL);
685
686 /* Normalize options */
687 if (*options & PJSIP_INV_REQUIRE_100REL)
688 *options |= PJSIP_INV_SUPPORT_100REL;
689
690 if (*options & PJSIP_INV_REQUIRE_TIMER)
691 *options |= PJSIP_INV_SUPPORT_TIMER;
692
693 /* Get the message in rdata */
694 msg = rdata->msg_info.msg;
695
696 /* Must be INVITE request. */
697 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
698 msg->line.req.method.id == PJSIP_INVITE_METHOD,
699 PJ_EINVAL);
700
701 /* If tdata is specified, then either dlg or endpt must be specified */
702 PJ_ASSERT_RETURN((!p_tdata) || (endpt || dlg), PJ_EINVAL);
703
704 /* Get the endpoint */
705 endpt = endpt ? endpt : dlg->endpt;
706
707 /* Init response header list */
708 pj_list_init(&res_hdr_list);
709
Benny Prijono8ad55352006-02-08 11:16:05 +0000710 /* Check the request body, see if it'inv something that we support
Benny Prijono268ca612006-02-07 12:34:11 +0000711 * (i.e. SDP).
712 */
713 if (msg->body) {
714 pjsip_msg_body *body = msg->body;
715 pj_str_t str_application = {"application", 11};
716 pj_str_t str_sdp = { "sdp", 3 };
717 pjmedia_sdp_session *sdp;
718
719 /* Check content type. */
720 if (pj_stricmp(&body->content_type.type, &str_application) != 0 ||
721 pj_stricmp(&body->content_type.subtype, &str_sdp) != 0)
722 {
723 /* Not "application/sdp" */
724 code = PJSIP_SC_UNSUPPORTED_MEDIA_TYPE;
725 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
726
727 if (p_tdata) {
728 /* Add Accept header to response */
729 pjsip_accept_hdr *acc;
730
731 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
732 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
733 acc->values[acc->count++] = pj_str("application/sdp");
734 pj_list_push_back(&res_hdr_list, acc);
735 }
736
737 goto on_return;
738 }
739
740 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000741 status = pjmedia_sdp_parse(rdata->tp_info.pool,
742 (char*)body->data, body->len, &sdp);
Benny Prijono268ca612006-02-07 12:34:11 +0000743 if (status == PJ_SUCCESS)
744 status = pjmedia_sdp_validate(sdp);
745
746 if (status != PJ_SUCCESS) {
747 /* Unparseable or invalid SDP */
748 code = PJSIP_SC_BAD_REQUEST;
749
750 if (p_tdata) {
751 /* Add Warning header. */
752 pjsip_warning_hdr *w;
753
754 w = pjsip_warning_hdr_create_from_status(rdata->tp_info.pool,
755 pjsip_endpt_name(endpt),
756 status);
757 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
758
759 pj_list_push_back(&res_hdr_list, w);
760 }
761
762 goto on_return;
763 }
764
765 /* Negotiate with local SDP */
766 if (l_sdp) {
767 pjmedia_sdp_neg *neg;
768
769 /* Local SDP must be valid! */
770 PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(l_sdp))==PJ_SUCCESS,
771 status);
772
773 /* Create SDP negotiator */
774 status = pjmedia_sdp_neg_create_w_remote_offer(
775 rdata->tp_info.pool, l_sdp, sdp, &neg);
776 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
777
778 /* Negotiate SDP */
779 status = pjmedia_sdp_neg_negotiate(rdata->tp_info.pool, neg, 0);
780 if (status != PJ_SUCCESS) {
781
782 /* Incompatible media */
783 code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
Benny Prijono268ca612006-02-07 12:34:11 +0000784
785 if (p_tdata) {
786 pjsip_accept_hdr *acc;
787 pjsip_warning_hdr *w;
788
789 /* Add Warning header. */
790 w = pjsip_warning_hdr_create_from_status(
791 rdata->tp_info.pool,
792 pjsip_endpt_name(endpt), status);
793 PJ_ASSERT_RETURN(w, PJ_ENOMEM);
794
795 pj_list_push_back(&res_hdr_list, w);
796
797 /* Add Accept header to response */
798 acc = pjsip_accept_hdr_create(rdata->tp_info.pool);
799 PJ_ASSERT_RETURN(acc, PJ_ENOMEM);
800 acc->values[acc->count++] = pj_str("application/sdp");
801 pj_list_push_back(&res_hdr_list, acc);
802
803 }
804
805 goto on_return;
806 }
807 }
808 }
809
810 /* Check supported methods, see if peer supports UPDATE.
811 * We just assume that peer supports standard INVITE, ACK, CANCEL, and BYE
812 * implicitly by sending this INVITE.
813 */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000814 allow = (pjsip_allow_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_ALLOW, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000815 if (allow) {
816 unsigned i;
817 const pj_str_t STR_UPDATE = { "UPDATE", 6 };
818
819 for (i=0; i<allow->count; ++i) {
820 if (pj_stricmp(&allow->values[i], &STR_UPDATE)==0)
821 break;
822 }
823
824 if (i != allow->count) {
825 /* UPDATE is present in Allow */
826 rem_option |= PJSIP_INV_SUPPORT_UPDATE;
827 }
828
829 }
830
831 /* Check Supported header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000832 sup_hdr = (pjsip_supported_hdr*)
833 pjsip_msg_find_hdr(msg, PJSIP_H_SUPPORTED, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000834 if (sup_hdr) {
835 unsigned i;
836 pj_str_t STR_100REL = { "100rel", 6};
837 pj_str_t STR_TIMER = { "timer", 5 };
838
839 for (i=0; i<sup_hdr->count; ++i) {
840 if (pj_stricmp(&sup_hdr->values[i], &STR_100REL)==0)
841 rem_option |= PJSIP_INV_SUPPORT_100REL;
842 else if (pj_stricmp(&sup_hdr->values[i], &STR_TIMER)==0)
843 rem_option |= PJSIP_INV_SUPPORT_TIMER;
844 }
845 }
846
847 /* Check Require header */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000848 req_hdr = (pjsip_require_hdr*)
849 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
Benny Prijono268ca612006-02-07 12:34:11 +0000850 if (req_hdr) {
851 unsigned i;
Benny Prijono053f5222006-11-11 16:16:04 +0000852 const pj_str_t STR_100REL = { "100rel", 6};
853 const pj_str_t STR_TIMER = { "timer", 5 };
854 const pj_str_t STR_REPLACES = { "replaces", 8 };
Benny Prijono268ca612006-02-07 12:34:11 +0000855 unsigned unsupp_cnt = 0;
856 pj_str_t unsupp_tags[PJSIP_GENERIC_ARRAY_MAX_COUNT];
857
858 for (i=0; i<req_hdr->count; ++i) {
859 if ((*options & PJSIP_INV_SUPPORT_100REL) &&
860 pj_stricmp(&req_hdr->values[i], &STR_100REL)==0)
861 {
862 rem_option |= PJSIP_INV_REQUIRE_100REL;
863
864 } else if ((*options && PJSIP_INV_SUPPORT_TIMER) &&
865 pj_stricmp(&req_hdr->values[i], &STR_TIMER)==0)
866 {
867 rem_option |= PJSIP_INV_REQUIRE_TIMER;
868
Benny Prijono053f5222006-11-11 16:16:04 +0000869 } else if (pj_stricmp(&req_hdr->values[i], &STR_REPLACES)==0) {
870 pj_bool_t supp;
871
872 supp = pjsip_endpt_has_capability(endpt, PJSIP_H_SUPPORTED,
873 NULL, &STR_REPLACES);
874 if (!supp)
875 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
876
Benny Prijono268ca612006-02-07 12:34:11 +0000877 } else {
878 /* Unknown/unsupported extension tag! */
879 unsupp_tags[unsupp_cnt++] = req_hdr->values[i];
880 }
881 }
882
883 /* Check if there are required tags that we don't support */
884 if (unsupp_cnt) {
885
886 code = PJSIP_SC_BAD_EXTENSION;
887 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
888
889 if (p_tdata) {
890 pjsip_unsupported_hdr *unsupp_hdr;
891 const pjsip_hdr *h;
892
893 /* Add Unsupported header. */
894 unsupp_hdr = pjsip_unsupported_hdr_create(rdata->tp_info.pool);
895 PJ_ASSERT_RETURN(unsupp_hdr != NULL, PJ_ENOMEM);
896
897 unsupp_hdr->count = unsupp_cnt;
898 for (i=0; i<unsupp_cnt; ++i)
899 unsupp_hdr->values[i] = unsupp_tags[i];
900
901 pj_list_push_back(&res_hdr_list, unsupp_hdr);
902
903 /* Add Supported header. */
904 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
905 NULL);
906 pj_assert(h);
907 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000908 sup_hdr = (pjsip_supported_hdr*)
909 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000910 pj_list_push_back(&res_hdr_list, sup_hdr);
911 }
912 }
913
914 goto on_return;
915 }
916 }
917
918 /* Check if there are local requirements that are not supported
919 * by peer.
920 */
921 if ( ((*options & PJSIP_INV_REQUIRE_100REL)!=0 &&
922 (rem_option & PJSIP_INV_SUPPORT_100REL)==0) ||
923 ((*options & PJSIP_INV_REQUIRE_TIMER)!=0 &&
924 (rem_option & PJSIP_INV_SUPPORT_TIMER)==0))
925 {
926 code = PJSIP_SC_EXTENSION_REQUIRED;
927 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
928
929 if (p_tdata) {
930 const pjsip_hdr *h;
931
932 /* Add Require header. */
933 req_hdr = pjsip_require_hdr_create(rdata->tp_info.pool);
934 PJ_ASSERT_RETURN(req_hdr != NULL, PJ_ENOMEM);
935
936 if (*options & PJSIP_INV_REQUIRE_100REL)
937 req_hdr->values[req_hdr->count++] = pj_str("100rel");
938
939 if (*options & PJSIP_INV_REQUIRE_TIMER)
940 req_hdr->values[req_hdr->count++] = pj_str("timer");
941
942 pj_list_push_back(&res_hdr_list, req_hdr);
943
944 /* Add Supported header. */
945 h = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED,
946 NULL);
947 pj_assert(h);
948 if (h) {
Benny Prijonoa1e69682007-05-11 15:14:34 +0000949 sup_hdr = (pjsip_supported_hdr*)
950 pjsip_hdr_clone(rdata->tp_info.pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000951 pj_list_push_back(&res_hdr_list, sup_hdr);
952 }
953
954 }
955
956 goto on_return;
957 }
958
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000959 /* If remote Require something that we support, make us Require
960 * that feature too.
961 */
962 if (rem_option & PJSIP_INV_REQUIRE_100REL) {
963 pj_assert(*options & PJSIP_INV_SUPPORT_100REL);
964 *options |= PJSIP_INV_REQUIRE_100REL;
965 }
966 if (rem_option & PJSIP_INV_REQUIRE_TIMER) {
967 pj_assert(*options & PJSIP_INV_SUPPORT_TIMER);
968 *options |= PJSIP_INV_REQUIRE_TIMER;
969 }
970
Benny Prijono268ca612006-02-07 12:34:11 +0000971on_return:
972
973 /* Create response if necessary */
974 if (code != 200 && p_tdata) {
975 pjsip_tx_data *tdata;
976 const pjsip_hdr *h;
977
978 if (dlg) {
979 status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
980 &tdata);
981 } else {
982 status = pjsip_endpt_create_response(endpt, rdata, code, NULL,
983 &tdata);
984 }
985
986 if (status != PJ_SUCCESS)
987 return status;
988
989 /* Add response headers. */
990 h = res_hdr_list.next;
991 while (h != &res_hdr_list) {
992 pjsip_hdr *cloned;
993
Benny Prijonoa1e69682007-05-11 15:14:34 +0000994 cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h);
Benny Prijono268ca612006-02-07 12:34:11 +0000995 PJ_ASSERT_RETURN(cloned, PJ_ENOMEM);
996
997 pjsip_msg_add_hdr(tdata->msg, cloned);
998
999 h = h->next;
1000 }
1001
1002 *p_tdata = tdata;
Benny Prijono70127222006-07-02 14:53:05 +00001003
1004 /* Can not return PJ_SUCCESS when response message is produced.
1005 * Ref: PROTOS test ~#2490
1006 */
1007 if (status == PJ_SUCCESS)
1008 status = PJSIP_ERRNO_FROM_SIP_STATUS(code);
1009
Benny Prijono268ca612006-02-07 12:34:11 +00001010 }
1011
1012 return status;
1013}
1014
1015/*
Benny Prijono8ad55352006-02-08 11:16:05 +00001016 * Create UAS invite session.
Benny Prijono268ca612006-02-07 12:34:11 +00001017 */
1018PJ_DEF(pj_status_t) pjsip_inv_create_uas( pjsip_dialog *dlg,
1019 pjsip_rx_data *rdata,
1020 const pjmedia_sdp_session *local_sdp,
1021 unsigned options,
1022 pjsip_inv_session **p_inv)
1023{
1024 pjsip_inv_session *inv;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001025 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001026 pjsip_msg *msg;
1027 pjmedia_sdp_session *rem_sdp = NULL;
1028 pj_status_t status;
1029
1030 /* Verify arguments. */
1031 PJ_ASSERT_RETURN(dlg && rdata && p_inv, PJ_EINVAL);
1032
1033 /* Dialog MUST have been initialised. */
1034 PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata) != NULL, PJ_EINVALIDOP);
1035
1036 msg = rdata->msg_info.msg;
1037
1038 /* rdata MUST contain INVITE request */
1039 PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG &&
1040 msg->line.req.method.id == PJSIP_INVITE_METHOD,
1041 PJ_EINVALIDOP);
1042
Benny Prijono8eae8382006-08-10 21:44:26 +00001043 /* Lock dialog */
1044 pjsip_dlg_inc_lock(dlg);
1045
Benny Prijono268ca612006-02-07 12:34:11 +00001046 /* Normalize options */
1047 if (options & PJSIP_INV_REQUIRE_100REL)
1048 options |= PJSIP_INV_SUPPORT_100REL;
1049
1050 if (options & PJSIP_INV_REQUIRE_TIMER)
1051 options |= PJSIP_INV_SUPPORT_TIMER;
1052
1053 /* Create the session */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001054 inv = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_inv_session);
Benny Prijono8eae8382006-08-10 21:44:26 +00001055 pj_assert(inv != NULL);
Benny Prijono268ca612006-02-07 12:34:11 +00001056
1057 inv->pool = dlg->pool;
1058 inv->role = PJSIP_ROLE_UAS;
Benny Prijono38998232006-02-08 22:44:25 +00001059 inv->state = PJSIP_INV_STATE_NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001060 inv->dlg = dlg;
1061 inv->options = options;
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001062 inv->notify = PJ_TRUE;
Benny Prijonoba5926a2007-05-02 11:29:37 +00001063 inv->cause = (pjsip_status_code) 0;
Benny Prijono268ca612006-02-07 12:34:11 +00001064
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001065 /* Object name will use the same dialog pointer. */
Benny Prijonoed811d72006-03-10 12:57:12 +00001066 pj_ansi_snprintf(inv->obj_name, PJ_MAX_OBJ_NAME, "inv%p", dlg);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001067
Benny Prijono268ca612006-02-07 12:34:11 +00001068 /* Parse SDP in message body, if present. */
1069 if (msg->body) {
1070 pjsip_msg_body *body = msg->body;
1071
1072 /* Parse and validate SDP */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001073 status = pjmedia_sdp_parse(inv->pool, (char*)body->data, body->len,
Benny Prijono268ca612006-02-07 12:34:11 +00001074 &rem_sdp);
1075 if (status == PJ_SUCCESS)
1076 status = pjmedia_sdp_validate(rem_sdp);
1077
Benny Prijono8eae8382006-08-10 21:44:26 +00001078 if (status != PJ_SUCCESS) {
1079 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001080 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001081 }
Benny Prijono268ca612006-02-07 12:34:11 +00001082 }
1083
1084 /* Create negotiator. */
1085 if (rem_sdp) {
1086 status = pjmedia_sdp_neg_create_w_remote_offer(inv->pool, local_sdp,
1087 rem_sdp, &inv->neg);
1088
1089 } else if (local_sdp) {
1090 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1091 &inv->neg);
1092 } else {
Benny Prijono95196582006-02-09 00:13:40 +00001093 status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001094 }
1095
Benny Prijono8eae8382006-08-10 21:44:26 +00001096 if (status != PJ_SUCCESS) {
1097 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001098 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001099 }
Benny Prijono268ca612006-02-07 12:34:11 +00001100
1101 /* Register invite as dialog usage. */
1102 status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
Benny Prijono8eae8382006-08-10 21:44:26 +00001103 if (status != PJ_SUCCESS) {
1104 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001105 return status;
Benny Prijono8eae8382006-08-10 21:44:26 +00001106 }
Benny Prijono268ca612006-02-07 12:34:11 +00001107
1108 /* Increment session in the dialog. */
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001109 pjsip_dlg_inc_session(dlg, &mod_inv.mod);
Benny Prijono268ca612006-02-07 12:34:11 +00001110
1111 /* Save the invite transaction. */
1112 inv->invite_tsx = pjsip_rdata_get_tsx(rdata);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001113
1114 /* Attach our data to the transaction. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001115 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001116 tsx_inv_data->inv = inv;
1117 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001118
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001119 /* Create 100rel handler */
1120 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1121 pjsip_100rel_attach(inv);
1122 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001123
Benny Prijono268ca612006-02-07 12:34:11 +00001124 /* Done */
Benny Prijono8eae8382006-08-10 21:44:26 +00001125 pjsip_dlg_dec_lock(dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001126 *p_inv = inv;
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001127
1128 PJ_LOG(5,(inv->obj_name, "UAS invite session created for dialog %s",
1129 dlg->obj_name));
1130
Benny Prijono268ca612006-02-07 12:34:11 +00001131 return PJ_SUCCESS;
1132}
1133
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001134/*
1135 * Forcefully terminate the session.
1136 */
1137PJ_DEF(pj_status_t) pjsip_inv_terminate( pjsip_inv_session *inv,
1138 int st_code,
1139 pj_bool_t notify)
1140{
1141 PJ_ASSERT_RETURN(inv, PJ_EINVAL);
1142
1143 /* Lock dialog. */
1144 pjsip_dlg_inc_lock(inv->dlg);
1145
1146 /* Set callback notify flag. */
1147 inv->notify = notify;
1148
1149 /* If there's pending transaction, terminate the transaction.
1150 * This may subsequently set the INVITE session state to
1151 * disconnected.
1152 */
1153 if (inv->invite_tsx &&
1154 inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
1155 {
1156 pjsip_tsx_terminate(inv->invite_tsx, st_code);
1157
1158 }
1159
1160 /* Set cause. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001161 inv_set_cause(inv, st_code, NULL);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001162
1163 /* Forcefully terminate the session if state is not DISCONNECTED */
1164 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
1165 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, NULL);
1166 }
1167
1168 /* Done.
1169 * The dec_lock() below will actually destroys the dialog if it
1170 * has no other session.
1171 */
1172 pjsip_dlg_dec_lock(inv->dlg);
1173
1174 return PJ_SUCCESS;
1175}
1176
1177
Benny Prijono268ca612006-02-07 12:34:11 +00001178static void *clone_sdp(pj_pool_t *pool, const void *data, unsigned len)
1179{
1180 PJ_UNUSED_ARG(len);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001181 return pjmedia_sdp_session_clone(pool, (const pjmedia_sdp_session*)data);
Benny Prijono268ca612006-02-07 12:34:11 +00001182}
1183
1184static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len)
1185{
Benny Prijonoa1e69682007-05-11 15:14:34 +00001186 return pjmedia_sdp_print((const pjmedia_sdp_session*)body->data, buf, len);
Benny Prijono268ca612006-02-07 12:34:11 +00001187}
1188
Benny Prijono56315612006-07-18 14:39:40 +00001189
1190PJ_DEF(pj_status_t) pjsip_create_sdp_body( pj_pool_t *pool,
1191 pjmedia_sdp_session *sdp,
1192 pjsip_msg_body **p_body)
1193{
1194 const pj_str_t STR_APPLICATION = { "application", 11};
1195 const pj_str_t STR_SDP = { "sdp", 3 };
1196 pjsip_msg_body *body;
1197
Benny Prijonoa1e69682007-05-11 15:14:34 +00001198 body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
Benny Prijono56315612006-07-18 14:39:40 +00001199 PJ_ASSERT_RETURN(body != NULL, PJ_ENOMEM);
1200
1201 body->content_type.type = STR_APPLICATION;
1202 body->content_type.subtype = STR_SDP;
1203 body->data = sdp;
1204 body->len = 0;
1205 body->clone_data = &clone_sdp;
1206 body->print_body = &print_sdp;
1207
1208 *p_body = body;
1209
1210 return PJ_SUCCESS;
1211}
1212
Benny Prijono268ca612006-02-07 12:34:11 +00001213static pjsip_msg_body *create_sdp_body(pj_pool_t *pool,
1214 const pjmedia_sdp_session *c_sdp)
1215{
1216 pjsip_msg_body *body;
Benny Prijono56315612006-07-18 14:39:40 +00001217 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00001218
Benny Prijono56315612006-07-18 14:39:40 +00001219 status = pjsip_create_sdp_body(pool,
1220 pjmedia_sdp_session_clone(pool, c_sdp),
1221 &body);
Benny Prijono268ca612006-02-07 12:34:11 +00001222
Benny Prijono56315612006-07-18 14:39:40 +00001223 if (status != PJ_SUCCESS)
1224 return NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001225
1226 return body;
1227}
1228
1229/*
1230 * Create initial INVITE request.
1231 */
1232PJ_DEF(pj_status_t) pjsip_inv_invite( pjsip_inv_session *inv,
1233 pjsip_tx_data **p_tdata )
1234{
1235 pjsip_tx_data *tdata;
1236 const pjsip_hdr *hdr;
Benny Prijono26ff9062006-02-21 23:47:00 +00001237 pj_bool_t has_sdp;
Benny Prijono268ca612006-02-07 12:34:11 +00001238 pj_status_t status;
1239
1240 /* Verify arguments. */
1241 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1242
Benny Prijono26ff9062006-02-21 23:47:00 +00001243 /* State MUST be NULL or CONFIRMED. */
1244 PJ_ASSERT_RETURN(inv->state == PJSIP_INV_STATE_NULL ||
1245 inv->state == PJSIP_INV_STATE_CONFIRMED,
1246 PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001247
Benny Prijono64f851e2006-02-23 13:49:28 +00001248 /* Lock dialog. */
1249 pjsip_dlg_inc_lock(inv->dlg);
1250
Benny Prijono268ca612006-02-07 12:34:11 +00001251 /* Create the INVITE request. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001252 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_invite_method(), -1,
Benny Prijono268ca612006-02-07 12:34:11 +00001253 &tdata);
1254 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001255 goto on_return;
1256
Benny Prijono268ca612006-02-07 12:34:11 +00001257
Benny Prijono26ff9062006-02-21 23:47:00 +00001258 /* If this is the first INVITE, then copy the headers from inv_hdr.
1259 * These are the headers parsed from the request URI when the
1260 * dialog was created.
1261 */
1262 if (inv->state == PJSIP_INV_STATE_NULL) {
1263 hdr = inv->dlg->inv_hdr.next;
1264
1265 while (hdr != &inv->dlg->inv_hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001266 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00001267 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1268 hdr = hdr->next;
1269 }
1270 }
1271
1272 /* See if we have SDP to send. */
1273 if (inv->neg) {
1274 pjmedia_sdp_neg_state neg_state;
1275
1276 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
1277
1278 has_sdp = (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER ||
1279 (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1280 pjmedia_sdp_neg_has_local_answer(inv->neg)));
1281
1282
1283 } else {
1284 has_sdp = PJ_FALSE;
1285 }
1286
Benny Prijono268ca612006-02-07 12:34:11 +00001287 /* Add SDP, if any. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001288 if (has_sdp) {
Benny Prijono268ca612006-02-07 12:34:11 +00001289 const pjmedia_sdp_session *offer;
1290
1291 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &offer);
1292 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001293 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001294
1295 tdata->msg->body = create_sdp_body(tdata->pool, offer);
1296 }
1297
1298 /* Add Allow header. */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001299 if (inv->dlg->add_allow) {
Benny Prijono95673f32007-06-26 08:23:18 +00001300 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_ALLOW, NULL);
1301 if (hdr) {
1302 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
1303 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1304 }
Benny Prijono268ca612006-02-07 12:34:11 +00001305 }
1306
1307 /* Add Supported header */
1308 hdr = pjsip_endpt_get_capability(inv->dlg->endpt, PJSIP_H_SUPPORTED, NULL);
1309 if (hdr) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001310 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono268ca612006-02-07 12:34:11 +00001311 pjsip_hdr_shallow_clone(tdata->pool, hdr));
1312 }
1313
1314 /* Add Require header. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001315 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
1316 const pj_str_t HREQ = { "Require", 7 };
1317 const pj_str_t tag_100rel = { "100rel", 6 };
1318 pjsip_generic_string_hdr *hreq;
1319
1320 hreq = pjsip_generic_string_hdr_create(tdata->pool, &HREQ,
1321 &tag_100rel);
1322 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) hreq);
1323 }
Benny Prijono268ca612006-02-07 12:34:11 +00001324
1325 /* Done. */
1326 *p_tdata = tdata;
1327
Benny Prijono64f851e2006-02-23 13:49:28 +00001328
1329on_return:
1330 pjsip_dlg_dec_lock(inv->dlg);
1331 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001332}
1333
1334
1335/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00001336 * Initiate SDP negotiation in the SDP negotiator.
Benny Prijono95196582006-02-09 00:13:40 +00001337 */
1338static pj_status_t inv_negotiate_sdp( pjsip_inv_session *inv )
1339{
1340 pj_status_t status;
1341
1342 PJ_ASSERT_RETURN(pjmedia_sdp_neg_get_state(inv->neg) ==
1343 PJMEDIA_SDP_NEG_STATE_WAIT_NEGO,
1344 PJMEDIA_SDPNEG_EINSTATE);
1345
1346 status = pjmedia_sdp_neg_negotiate(inv->pool, inv->neg, 0);
1347
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001348 PJ_LOG(5,(inv->obj_name, "SDP negotiation done, status=%d", status));
1349
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001350 if (mod_inv.cb.on_media_update && inv->notify)
Benny Prijono95196582006-02-09 00:13:40 +00001351 (*mod_inv.cb.on_media_update)(inv, status);
1352
1353 return status;
1354}
1355
1356/*
Benny Prijonoa66c7152006-02-09 01:26:14 +00001357 * Check in incoming message for SDP offer/answer.
1358 */
Benny Prijono26ff9062006-02-21 23:47:00 +00001359static pj_status_t inv_check_sdp_in_incoming_msg( pjsip_inv_session *inv,
1360 pjsip_transaction *tsx,
1361 pjsip_rx_data *rdata)
Benny Prijonoa66c7152006-02-09 01:26:14 +00001362{
1363 struct tsx_inv_data *tsx_inv_data;
1364 static const pj_str_t str_application = { "application", 11 };
1365 static const pj_str_t str_sdp = { "sdp", 3 };
1366 pj_status_t status;
1367 pjsip_msg *msg;
1368 pjmedia_sdp_session *sdp;
1369
1370 /* Get/attach invite session's transaction data */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001371 tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
Benny Prijonoa66c7152006-02-09 01:26:14 +00001372 if (tsx_inv_data == NULL) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00001373 tsx_inv_data = PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001374 tsx_inv_data->inv = inv;
1375 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
1376 }
1377
1378 /* MUST NOT do multiple SDP offer/answer in a single transaction.
1379 */
1380
Benny Prijono77998ce2007-06-20 10:03:46 +00001381 if (tsx_inv_data->sdp_done) {
1382 if (rdata->msg_info.msg->body) {
1383 PJ_LOG(4,(inv->obj_name, "SDP negotiation done, message "
1384 "body is ignored"));
1385 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001386 return PJ_SUCCESS;
Benny Prijono77998ce2007-06-20 10:03:46 +00001387 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001388
1389 /* Check if SDP is present in the message. */
1390
1391 msg = rdata->msg_info.msg;
1392 if (msg->body == NULL) {
1393 /* Message doesn't have body. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001394 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001395 }
1396
1397 if (pj_stricmp(&msg->body->content_type.type, &str_application) ||
1398 pj_stricmp(&msg->body->content_type.subtype, &str_sdp))
1399 {
1400 /* Message body is not "application/sdp" */
Benny Prijono26ff9062006-02-21 23:47:00 +00001401 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001402 }
1403
1404 /* Parse the SDP body. */
1405
Benny Prijonoa1e69682007-05-11 15:14:34 +00001406 status = pjmedia_sdp_parse(rdata->tp_info.pool,
1407 (char*)msg->body->data,
Benny Prijonoa66c7152006-02-09 01:26:14 +00001408 msg->body->len, &sdp);
1409 if (status != PJ_SUCCESS) {
1410 char errmsg[PJ_ERR_MSG_SIZE];
1411 pj_strerror(status, errmsg, sizeof(errmsg));
1412 PJ_LOG(4,(THIS_FILE, "Error parsing SDP in %s: %s",
1413 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001414 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001415 }
1416
1417 /* The SDP can be an offer or answer, depending on negotiator's state */
1418
1419 if (inv->neg == NULL ||
1420 pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_DONE)
1421 {
1422
1423 /* This is an offer. */
1424
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001425 PJ_LOG(5,(inv->obj_name, "Got SDP offer in %s",
1426 pjsip_rx_data_get_info(rdata)));
1427
Benny Prijonoa66c7152006-02-09 01:26:14 +00001428 if (inv->neg == NULL) {
1429 status=pjmedia_sdp_neg_create_w_remote_offer(inv->pool, NULL,
1430 sdp, &inv->neg);
1431 } else {
1432 status=pjmedia_sdp_neg_set_remote_offer(inv->pool, inv->neg, sdp);
1433 }
1434
1435 if (status != PJ_SUCCESS) {
1436 char errmsg[PJ_ERR_MSG_SIZE];
1437 pj_strerror(status, errmsg, sizeof(errmsg));
1438 PJ_LOG(4,(THIS_FILE, "Error processing SDP offer in %s: %s",
1439 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001440 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001441 }
1442
1443 /* Inform application about remote offer. */
1444
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001445 if (mod_inv.cb.on_rx_offer && inv->notify) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001446
1447 (*mod_inv.cb.on_rx_offer)(inv, sdp);
1448
1449 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00001450
1451 } else if (pjmedia_sdp_neg_get_state(inv->neg) ==
1452 PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
1453 {
1454
1455 /* This is an answer.
1456 * Process and negotiate remote answer.
1457 */
1458
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001459 PJ_LOG(5,(inv->obj_name, "Got SDP answer in %s",
1460 pjsip_rx_data_get_info(rdata)));
1461
Benny Prijonoa66c7152006-02-09 01:26:14 +00001462 status = pjmedia_sdp_neg_set_remote_answer(inv->pool, inv->neg, sdp);
1463
1464 if (status != PJ_SUCCESS) {
1465 char errmsg[PJ_ERR_MSG_SIZE];
1466 pj_strerror(status, errmsg, sizeof(errmsg));
1467 PJ_LOG(4,(THIS_FILE, "Error processing SDP answer in %s: %s",
1468 pjsip_rx_data_get_info(rdata), errmsg));
Benny Prijono26ff9062006-02-21 23:47:00 +00001469 return PJMEDIA_SDP_EINSDP;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001470 }
1471
1472 /* Negotiate SDP */
1473
1474 inv_negotiate_sdp(inv);
1475
1476 /* Mark this transaction has having SDP offer/answer done. */
1477
1478 tsx_inv_data->sdp_done = 1;
1479
1480 } else {
1481
1482 PJ_LOG(5,(THIS_FILE, "Ignored SDP in %s: negotiator state is %s",
1483 pjsip_rx_data_get_info(rdata),
1484 pjmedia_sdp_neg_state_str(pjmedia_sdp_neg_get_state(inv->neg))));
1485 }
1486
Benny Prijono26ff9062006-02-21 23:47:00 +00001487 return PJ_SUCCESS;
Benny Prijonoa66c7152006-02-09 01:26:14 +00001488}
1489
1490
Benny Prijono26ff9062006-02-21 23:47:00 +00001491/*
1492 * Process INVITE answer, for both initial and subsequent re-INVITE
1493 */
1494static pj_status_t process_answer( pjsip_inv_session *inv,
1495 int st_code,
Benny Prijono64f851e2006-02-23 13:49:28 +00001496 pjsip_tx_data *tdata,
1497 const pjmedia_sdp_session *local_sdp)
Benny Prijono26ff9062006-02-21 23:47:00 +00001498{
1499 pj_status_t status;
Benny Prijonoab7399b2006-02-27 00:40:31 +00001500 const pjmedia_sdp_session *sdp = NULL;
Benny Prijono26ff9062006-02-21 23:47:00 +00001501
Benny Prijono64f851e2006-02-23 13:49:28 +00001502 /* If local_sdp is specified, then we MUST NOT have answered the
1503 * offer before.
Benny Prijono26ff9062006-02-21 23:47:00 +00001504 */
Benny Prijono64f851e2006-02-23 13:49:28 +00001505 if (local_sdp && (st_code/100==1 || st_code/100==2)) {
1506
1507 if (inv->neg == NULL) {
1508 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, local_sdp,
1509 &inv->neg);
1510 } else if (pjmedia_sdp_neg_get_state(inv->neg)==
1511 PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
1512 {
1513 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
1514 local_sdp);
1515 } else {
1516
1517 /* Can not specify local SDP at this state. */
1518 pj_assert(0);
1519 status = PJMEDIA_SDPNEG_EINSTATE;
1520 }
1521
1522 if (status != PJ_SUCCESS)
1523 return status;
1524
1525 }
1526
1527
1528 /* If SDP negotiator is ready, start negotiation. */
1529 if (st_code/100==2 || (st_code/10==18 && st_code!=180)) {
Benny Prijono26ff9062006-02-21 23:47:00 +00001530
1531 pjmedia_sdp_neg_state neg_state;
1532
Benny Prijono64f851e2006-02-23 13:49:28 +00001533 /* Start nego when appropriate. */
Benny Prijono26ff9062006-02-21 23:47:00 +00001534 neg_state = inv->neg ? pjmedia_sdp_neg_get_state(inv->neg) :
1535 PJMEDIA_SDP_NEG_STATE_NULL;
1536
1537 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
1538
1539 status = pjmedia_sdp_neg_get_neg_local(inv->neg, &sdp);
1540
1541 } else if (neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO &&
1542 pjmedia_sdp_neg_has_local_answer(inv->neg) )
1543 {
Benny Prijono77998ce2007-06-20 10:03:46 +00001544 struct tsx_inv_data *tsx_inv_data;
1545
1546 /* Get invite session's transaction data */
1547 tsx_inv_data = (struct tsx_inv_data*)
1548 inv->invite_tsx->mod_data[mod_inv.mod.id];
Benny Prijono26ff9062006-02-21 23:47:00 +00001549
1550 status = inv_negotiate_sdp(inv);
1551 if (status != PJ_SUCCESS)
1552 return status;
1553
Benny Prijono77998ce2007-06-20 10:03:46 +00001554 /* Mark this transaction has having SDP offer/answer done. */
1555 tsx_inv_data->sdp_done = 1;
1556
Benny Prijono26ff9062006-02-21 23:47:00 +00001557 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
1558 }
Benny Prijono26ff9062006-02-21 23:47:00 +00001559 }
1560
Benny Prijono64f851e2006-02-23 13:49:28 +00001561 /* Include SDP when it's available for 2xx and 18x (but not 180) response.
Benny Prijono26ff9062006-02-21 23:47:00 +00001562 * Subsequent response will include this SDP.
1563 */
1564 if (sdp) {
1565 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
1566 }
1567
Benny Prijono26ff9062006-02-21 23:47:00 +00001568
1569 return PJ_SUCCESS;
1570}
1571
Benny Prijonoa66c7152006-02-09 01:26:14 +00001572
1573/*
Benny Prijono64f851e2006-02-23 13:49:28 +00001574 * Create first response to INVITE
1575 */
1576PJ_DEF(pj_status_t) pjsip_inv_initial_answer( pjsip_inv_session *inv,
1577 pjsip_rx_data *rdata,
1578 int st_code,
1579 const pj_str_t *st_text,
1580 const pjmedia_sdp_session *sdp,
1581 pjsip_tx_data **p_tdata)
1582{
1583 pjsip_tx_data *tdata;
1584 pj_status_t status;
1585
1586 /* Verify arguments. */
1587 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1588
1589 /* Must have INVITE transaction. */
1590 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1591
1592 pjsip_dlg_inc_lock(inv->dlg);
1593
1594 /* Create response */
1595 status = pjsip_dlg_create_response(inv->dlg, rdata, st_code, st_text,
1596 &tdata);
1597 if (status != PJ_SUCCESS)
1598 goto on_return;
1599
1600 /* Process SDP in answer */
1601 status = process_answer(inv, st_code, tdata, sdp);
1602 if (status != PJ_SUCCESS) {
1603 pjsip_tx_data_dec_ref(tdata);
1604 goto on_return;
1605 }
1606
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001607 /* Save this answer */
1608 inv->last_answer = tdata;
1609 pjsip_tx_data_add_ref(inv->last_answer);
1610 PJ_LOG(5,(inv->dlg->obj_name, "Initial answer %s",
1611 pjsip_tx_data_get_info(inv->last_answer)));
1612
Benny Prijono64f851e2006-02-23 13:49:28 +00001613 *p_tdata = tdata;
1614
1615on_return:
1616 pjsip_dlg_dec_lock(inv->dlg);
1617 return status;
1618}
1619
1620
1621/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001622 * Answer initial INVITE
1623 * Re-INVITE will be answered automatically, and will not use this function.
Benny Prijono268ca612006-02-07 12:34:11 +00001624 */
1625PJ_DEF(pj_status_t) pjsip_inv_answer( pjsip_inv_session *inv,
1626 int st_code,
1627 const pj_str_t *st_text,
1628 const pjmedia_sdp_session *local_sdp,
1629 pjsip_tx_data **p_tdata )
1630{
1631 pjsip_tx_data *last_res;
1632 pj_status_t status;
1633
1634 /* Verify arguments. */
1635 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1636
1637 /* Must have INVITE transaction. */
1638 PJ_ASSERT_RETURN(inv->invite_tsx, PJ_EBUG);
1639
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001640 /* Must have created an answer before */
1641 PJ_ASSERT_RETURN(inv->last_answer, PJ_EINVALIDOP);
Benny Prijono268ca612006-02-07 12:34:11 +00001642
Benny Prijono64f851e2006-02-23 13:49:28 +00001643 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001644
1645 /* Modify last response. */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001646 last_res = inv->last_answer;
Benny Prijono268ca612006-02-07 12:34:11 +00001647 status = pjsip_dlg_modify_response(inv->dlg, last_res, st_code, st_text);
1648 if (status != PJ_SUCCESS)
Benny Prijono64f851e2006-02-23 13:49:28 +00001649 goto on_return;
Benny Prijono268ca612006-02-07 12:34:11 +00001650
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001651 /* For non-2xx final response, strip message body */
1652 if (st_code >= 300) {
1653 last_res->msg->body = NULL;
1654 }
Benny Prijono268ca612006-02-07 12:34:11 +00001655
Benny Prijono26ff9062006-02-21 23:47:00 +00001656 /* Process SDP in answer */
Benny Prijono64f851e2006-02-23 13:49:28 +00001657 status = process_answer(inv, st_code, last_res, local_sdp);
1658 if (status != PJ_SUCCESS) {
1659 pjsip_tx_data_dec_ref(last_res);
1660 goto on_return;
1661 }
Benny Prijono268ca612006-02-07 12:34:11 +00001662
Benny Prijono268ca612006-02-07 12:34:11 +00001663
1664 *p_tdata = last_res;
1665
Benny Prijono64f851e2006-02-23 13:49:28 +00001666on_return:
1667 pjsip_dlg_dec_lock(inv->dlg);
1668 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001669}
1670
1671
1672/*
Benny Prijono26ff9062006-02-21 23:47:00 +00001673 * Set SDP answer.
1674 */
1675PJ_DEF(pj_status_t) pjsip_inv_set_sdp_answer( pjsip_inv_session *inv,
1676 const pjmedia_sdp_session *sdp )
1677{
1678 pj_status_t status;
1679
1680 PJ_ASSERT_RETURN(inv && sdp, PJ_EINVAL);
1681
1682 pjsip_dlg_inc_lock(inv->dlg);
1683 status = pjmedia_sdp_neg_set_local_answer( inv->pool, inv->neg, sdp);
1684 pjsip_dlg_dec_lock(inv->dlg);
1685
1686 return status;
1687}
1688
1689
1690/*
Benny Prijono268ca612006-02-07 12:34:11 +00001691 * End session.
1692 */
1693PJ_DEF(pj_status_t) pjsip_inv_end_session( pjsip_inv_session *inv,
1694 int st_code,
1695 const pj_str_t *st_text,
1696 pjsip_tx_data **p_tdata )
1697{
1698 pjsip_tx_data *tdata;
1699 pj_status_t status;
1700
1701 /* Verify arguments. */
1702 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1703
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001704 /* Set cause code. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00001705 inv_set_cause(inv, st_code, st_text);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001706
Benny Prijono268ca612006-02-07 12:34:11 +00001707 /* Create appropriate message. */
1708 switch (inv->state) {
1709 case PJSIP_INV_STATE_CALLING:
1710 case PJSIP_INV_STATE_EARLY:
1711 case PJSIP_INV_STATE_INCOMING:
1712
1713 if (inv->role == PJSIP_ROLE_UAC) {
1714
1715 /* For UAC when session has not been confirmed, create CANCEL. */
1716
1717 /* MUST have the original UAC INVITE transaction. */
1718 PJ_ASSERT_RETURN(inv->invite_tsx != NULL, PJ_EBUG);
1719
1720 /* But CANCEL should only be called when we have received a
1721 * provisional response. If we haven't received any responses,
1722 * just destroy the transaction.
1723 */
1724 if (inv->invite_tsx->status_code < 100) {
1725
Benny Prijono1dc8be02007-05-30 04:26:40 +00001726 pjsip_tsx_stop_retransmit(inv->invite_tsx);
1727 inv->cancelling = PJ_TRUE;
1728 inv->pending_cancel = PJ_TRUE;
Benny Prijonofccab712006-02-22 22:23:22 +00001729 *p_tdata = NULL;
Benny Prijono1dc8be02007-05-30 04:26:40 +00001730 PJ_LOG(4, (inv->obj_name, "Stopping retransmission, "
1731 "delaying CANCEL"));
Benny Prijonofccab712006-02-22 22:23:22 +00001732 return PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001733 }
1734
1735 /* The CSeq here assumes that the dialog is started with an
1736 * INVITE session. This may not be correct; dialog can be
1737 * started as SUBSCRIBE session.
1738 * So fix this!
1739 */
1740 status = pjsip_endpt_create_cancel(inv->dlg->endpt,
1741 inv->invite_tsx->last_tx,
1742 &tdata);
1743
1744 } else {
1745
1746 /* For UAS, send a final response. */
1747 tdata = inv->invite_tsx->last_tx;
1748 PJ_ASSERT_RETURN(tdata != NULL, PJ_EINVALIDOP);
1749
Benny Prijono26ff9062006-02-21 23:47:00 +00001750 //status = pjsip_dlg_modify_response(inv->dlg, tdata, st_code,
1751 // st_text);
1752 status = pjsip_inv_answer(inv, st_code, st_text, NULL, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001753 }
1754 break;
1755
1756 case PJSIP_INV_STATE_CONNECTING:
1757 case PJSIP_INV_STATE_CONFIRMED:
1758 /* For established dialog, send BYE */
Benny Prijono1f61a8f2007-08-16 10:11:44 +00001759 status = pjsip_dlg_create_request(inv->dlg, pjsip_get_bye_method(),
1760 -1, &tdata);
Benny Prijono268ca612006-02-07 12:34:11 +00001761 break;
1762
1763 case PJSIP_INV_STATE_DISCONNECTED:
Benny Prijono268ca612006-02-07 12:34:11 +00001764 /* No need to do anything. */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00001765 return PJSIP_ESESSIONTERMINATED;
Benny Prijono268ca612006-02-07 12:34:11 +00001766
1767 default:
1768 pj_assert("!Invalid operation!");
1769 return PJ_EINVALIDOP;
1770 }
1771
1772 if (status != PJ_SUCCESS)
1773 return status;
1774
1775
1776 /* Done */
1777
Benny Prijono0606e702007-05-22 12:21:40 +00001778 inv->cancelling = PJ_TRUE;
Benny Prijono268ca612006-02-07 12:34:11 +00001779 *p_tdata = tdata;
1780
1781 return PJ_SUCCESS;
1782}
1783
1784
1785/*
1786 * Create re-INVITE.
1787 */
1788PJ_DEF(pj_status_t) pjsip_inv_reinvite( pjsip_inv_session *inv,
1789 const pj_str_t *new_contact,
1790 const pjmedia_sdp_session *new_offer,
1791 pjsip_tx_data **p_tdata )
1792{
Benny Prijono26ff9062006-02-21 23:47:00 +00001793 pj_status_t status;
1794 pjsip_contact_hdr *contact_hdr = NULL;
Benny Prijono268ca612006-02-07 12:34:11 +00001795
Benny Prijono26ff9062006-02-21 23:47:00 +00001796 /* Check arguments. */
1797 PJ_ASSERT_RETURN(inv && p_tdata, PJ_EINVAL);
1798
1799 /* Must NOT have a pending INVITE transaction */
Benny Prijono2b787822007-06-12 15:29:52 +00001800 if (inv->invite_tsx!=NULL)
1801 return PJ_EINVALIDOP;
Benny Prijono26ff9062006-02-21 23:47:00 +00001802
1803
1804 pjsip_dlg_inc_lock(inv->dlg);
1805
1806 if (new_contact) {
1807 pj_str_t tmp;
1808 const pj_str_t STR_CONTACT = { "Contact", 7 };
1809
1810 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
Benny Prijonoa1e69682007-05-11 15:14:34 +00001811 contact_hdr = (pjsip_contact_hdr*)
1812 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
Benny Prijono26ff9062006-02-21 23:47:00 +00001813 tmp.ptr, tmp.slen, NULL);
1814 if (!contact_hdr) {
1815 status = PJSIP_EINVALIDURI;
1816 goto on_return;
1817 }
1818 }
1819
1820
1821 if (new_offer) {
1822 if (!inv->neg) {
1823 status = pjmedia_sdp_neg_create_w_local_offer(inv->pool, new_offer,
1824 &inv->neg);
1825 if (status != PJ_SUCCESS)
1826 goto on_return;
1827
1828 } else switch (pjmedia_sdp_neg_get_state(inv->neg)) {
1829
1830 case PJMEDIA_SDP_NEG_STATE_NULL:
1831 pj_assert(!"Unexpected SDP neg state NULL");
1832 status = PJ_EBUG;
1833 goto on_return;
1834
1835 case PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER:
1836 PJ_LOG(4,(inv->obj_name,
1837 "pjsip_inv_reinvite: already have an offer, new "
1838 "offer is ignored"));
1839 break;
1840
1841 case PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER:
1842 status = pjmedia_sdp_neg_set_local_answer(inv->pool, inv->neg,
1843 new_offer);
1844 if (status != PJ_SUCCESS)
1845 goto on_return;
1846 break;
1847
1848 case PJMEDIA_SDP_NEG_STATE_WAIT_NEGO:
1849 PJ_LOG(4,(inv->obj_name,
1850 "pjsip_inv_reinvite: SDP in WAIT_NEGO state, new "
1851 "offer is ignored"));
1852 break;
1853
1854 case PJMEDIA_SDP_NEG_STATE_DONE:
1855 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
1856 new_offer);
1857 if (status != PJ_SUCCESS)
1858 goto on_return;
1859 break;
1860 }
1861 }
1862
1863 if (contact_hdr)
1864 inv->dlg->local.contact = contact_hdr;
1865
1866 status = pjsip_inv_invite(inv, p_tdata);
1867
1868on_return:
1869 pjsip_dlg_dec_lock(inv->dlg);
1870 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001871}
1872
1873/*
1874 * Create UPDATE.
1875 */
1876PJ_DEF(pj_status_t) pjsip_inv_update ( pjsip_inv_session *inv,
1877 const pj_str_t *new_contact,
Benny Prijono1f7767b2007-10-03 18:28:49 +00001878 const pjmedia_sdp_session *offer,
Benny Prijono268ca612006-02-07 12:34:11 +00001879 pjsip_tx_data **p_tdata )
1880{
Benny Prijono1f7767b2007-10-03 18:28:49 +00001881 pjsip_contact_hdr *contact_hdr = NULL;
1882 pjsip_tx_data *tdata = NULL;
1883 pjmedia_sdp_session *sdp_copy;
1884 pj_status_t status = PJ_SUCCESS;
Benny Prijono268ca612006-02-07 12:34:11 +00001885
Benny Prijono1f7767b2007-10-03 18:28:49 +00001886 /* Verify arguments. */
1887 PJ_ASSERT_RETURN(inv && p_tdata && offer, PJ_EINVAL);
1888
1889 /* Dialog must have been established */
1890 PJ_ASSERT_RETURN(inv->dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED,
1891 PJ_EINVALIDOP);
1892
1893 /* Invite session must not have been disconnected */
1894 PJ_ASSERT_RETURN(inv->state < PJSIP_INV_STATE_DISCONNECTED,
1895 PJ_EINVALIDOP);
1896
1897 /* Lock dialog. */
1898 pjsip_dlg_inc_lock(inv->dlg);
1899
1900 /* Process offer */
1901 if (pjmedia_sdp_neg_get_state(inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) {
1902 PJ_LOG(4,(inv->dlg->obj_name,
1903 "Invalid SDP offer/answer state for UPDATE"));
1904 status = PJ_EINVALIDOP;
1905 goto on_error;
1906 }
1907
1908 status = pjmedia_sdp_neg_modify_local_offer(inv->pool,inv->neg,
1909 offer);
1910 if (status != PJ_SUCCESS)
1911 goto on_error;
1912
1913
1914 /* Update Contact if required */
1915 if (new_contact) {
1916 pj_str_t tmp;
1917 const pj_str_t STR_CONTACT = { "Contact", 7 };
1918
1919 pj_strdup_with_null(inv->dlg->pool, &tmp, new_contact);
1920 contact_hdr = (pjsip_contact_hdr*)
1921 pjsip_parse_hdr(inv->dlg->pool, &STR_CONTACT,
1922 tmp.ptr, tmp.slen, NULL);
1923 if (!contact_hdr) {
1924 status = PJSIP_EINVALIDURI;
1925 goto on_error;
1926 }
1927
1928 inv->dlg->local.contact = contact_hdr;
1929 }
1930
1931 /* Create request */
1932 status = pjsip_dlg_create_request(inv->dlg, &pjsip_update_method,
1933 -1, &tdata);
1934 if (status != PJ_SUCCESS)
1935 goto on_error;
1936
1937 /* Attach SDP body */
1938 sdp_copy = pjmedia_sdp_session_clone(tdata->pool, offer);
1939 pjsip_create_sdp_body(tdata->pool, sdp_copy, &tdata->msg->body);
1940
1941 /* Unlock dialog. */
1942 pjsip_dlg_dec_lock(inv->dlg);
1943
1944 *p_tdata = tdata;
1945
1946 return PJ_SUCCESS;
1947
1948on_error:
1949 if (tdata)
1950 pjsip_tx_data_dec_ref(tdata);
1951
1952 /* Unlock dialog. */
1953 pjsip_dlg_dec_lock(inv->dlg);
1954
1955 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001956}
1957
1958/*
1959 * Send a request or response message.
1960 */
1961PJ_DEF(pj_status_t) pjsip_inv_send_msg( pjsip_inv_session *inv,
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00001962 pjsip_tx_data *tdata)
Benny Prijono268ca612006-02-07 12:34:11 +00001963{
1964 pj_status_t status;
1965
1966 /* Verify arguments. */
1967 PJ_ASSERT_RETURN(inv && tdata, PJ_EINVAL);
1968
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00001969 PJ_LOG(5,(inv->obj_name, "Sending %s",
1970 pjsip_tx_data_get_info(tdata)));
1971
Benny Prijono268ca612006-02-07 12:34:11 +00001972 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00001973 struct tsx_inv_data *tsx_inv_data;
Benny Prijono268ca612006-02-07 12:34:11 +00001974
Benny Prijono64158af2006-04-04 11:06:34 +00001975 pjsip_dlg_inc_lock(inv->dlg);
Benny Prijono268ca612006-02-07 12:34:11 +00001976
Benny Prijonoa1e69682007-05-11 15:14:34 +00001977 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->pool, struct tsx_inv_data);
Benny Prijonoa66c7152006-02-09 01:26:14 +00001978 tsx_inv_data->inv = inv;
1979
Benny Prijono64158af2006-04-04 11:06:34 +00001980 pjsip_dlg_dec_lock(inv->dlg);
1981
1982 status = pjsip_dlg_send_request(inv->dlg, tdata, mod_inv.mod.id,
1983 tsx_inv_data);
1984 if (status != PJ_SUCCESS)
1985 return status;
Benny Prijono268ca612006-02-07 12:34:11 +00001986
1987 } else {
1988 pjsip_cseq_hdr *cseq;
1989
1990 /* Can only do this to send response to original INVITE
1991 * request.
1992 */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001993 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 +00001994 && (cseq->cseq == inv->invite_tsx->cseq),
Benny Prijono268ca612006-02-07 12:34:11 +00001995 PJ_EINVALIDOP);
1996
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001997 if (inv->options & PJSIP_INV_REQUIRE_100REL) {
Benny Prijono1f7767b2007-10-03 18:28:49 +00001998 status = pjsip_100rel_tx_response(inv, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001999 } else
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002000 {
Benny Prijono1f7767b2007-10-03 18:28:49 +00002001 status = pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002002 }
2003
Benny Prijono268ca612006-02-07 12:34:11 +00002004 if (status != PJ_SUCCESS)
2005 return status;
2006 }
2007
2008 /* Done (?) */
2009 return PJ_SUCCESS;
2010}
2011
2012
Benny Prijono8ad55352006-02-08 11:16:05 +00002013/*
2014 * Respond to incoming CANCEL request.
2015 */
2016static void inv_respond_incoming_cancel(pjsip_inv_session *inv,
2017 pjsip_transaction *cancel_tsx,
2018 pjsip_rx_data *rdata)
2019{
2020 pjsip_tx_data *tdata;
2021 pjsip_transaction *invite_tsx;
2022 pj_str_t key;
2023 pj_status_t status;
2024
2025 /* See if we have matching INVITE server transaction: */
2026
2027 pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS,
Benny Prijono1f61a8f2007-08-16 10:11:44 +00002028 pjsip_get_invite_method(), rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002029 invite_tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
2030
2031 if (invite_tsx == NULL) {
2032
2033 /* Invite transaction not found!
2034 * Respond CANCEL with 491 (RFC 3261 Section 9.2 page 42)
2035 */
2036 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2037 &tdata);
2038
2039 } else {
2040 /* Always answer CANCEL will 200 (OK) regardless of
2041 * the state of the INVITE transaction.
2042 */
2043 status = pjsip_dlg_create_response( inv->dlg, rdata, 200, NULL,
2044 &tdata);
2045 }
2046
2047 /* See if we have created the response successfully. */
2048 if (status != PJ_SUCCESS) return;
2049
2050 /* Send the CANCEL response */
2051 status = pjsip_dlg_send_response(inv->dlg, cancel_tsx, tdata);
2052 if (status != PJ_SUCCESS) return;
2053
2054
2055 /* See if we need to terminate the UAS INVITE transaction
2056 * with 487 (Request Terminated) response.
2057 */
2058 if (invite_tsx && invite_tsx->status_code < 200) {
2059
2060 pj_assert(invite_tsx->last_tx != NULL);
2061
2062 tdata = invite_tsx->last_tx;
2063
2064 status = pjsip_dlg_modify_response(inv->dlg, tdata, 487, NULL);
2065 if (status == PJ_SUCCESS)
2066 pjsip_dlg_send_response(inv->dlg, invite_tsx, tdata);
2067 }
2068
2069 if (invite_tsx)
2070 pj_mutex_unlock(invite_tsx->mutex);
2071}
2072
2073
2074/*
2075 * Respond to incoming BYE request.
2076 */
2077static void inv_respond_incoming_bye( pjsip_inv_session *inv,
2078 pjsip_transaction *bye_tsx,
2079 pjsip_rx_data *rdata,
2080 pjsip_event *e )
2081{
2082 pj_status_t status;
2083 pjsip_tx_data *tdata;
2084
2085 /* Respond BYE with 200: */
2086
2087 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
2088 if (status != PJ_SUCCESS) return;
2089
2090 status = pjsip_dlg_send_response(inv->dlg, bye_tsx, tdata);
2091 if (status != PJ_SUCCESS) return;
2092
2093 /* Terminate session: */
2094
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002095 if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002096 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono8ad55352006-02-08 11:16:05 +00002097 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002098 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002099}
2100
2101/*
Benny Prijono38998232006-02-08 22:44:25 +00002102 * Respond to BYE request.
2103 */
2104static void inv_handle_bye_response( pjsip_inv_session *inv,
2105 pjsip_transaction *tsx,
2106 pjsip_rx_data *rdata,
2107 pjsip_event *e )
2108{
2109 pj_status_t status;
2110
2111 if (e->body.tsx_state.type != PJSIP_EVENT_RX_MSG) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002112 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002113 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2114 return;
2115 }
2116
2117 /* Handle 401/407 challenge. */
2118 if (tsx->status_code == 401 || tsx->status_code == 407) {
2119
2120 pjsip_tx_data *tdata;
2121
2122 status = pjsip_auth_clt_reinit_req( &inv->dlg->auth_sess,
2123 rdata,
2124 tsx->last_tx,
2125 &tdata);
2126
2127 if (status != PJ_SUCCESS) {
2128
2129 /* Does not have proper credentials.
2130 * End the session anyway.
2131 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002132 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002133 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2134
2135 } else {
2136 /* Re-send BYE. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002137 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono38998232006-02-08 22:44:25 +00002138 }
2139
2140 } else {
2141
2142 /* End the session. */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002143 inv_set_cause(inv, PJSIP_SC_OK, NULL);
Benny Prijono38998232006-02-08 22:44:25 +00002144 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2145 }
2146
2147}
2148
2149/*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002150 * Respond to incoming UPDATE request.
2151 */
2152static void inv_respond_incoming_update(pjsip_inv_session *inv,
2153 pjsip_rx_data *rdata)
2154{
2155 pjmedia_sdp_neg_state neg_state;
2156 pj_status_t status;
2157 pjsip_tx_data *tdata = NULL;
2158
2159 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2160
2161 /* Send 491 if we receive UPDATE while we're waiting for an answer */
2162 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
2163 status = pjsip_dlg_create_response(inv->dlg, rdata,
2164 PJSIP_SC_REQUEST_PENDING, NULL,
2165 &tdata);
2166 }
2167 /* Send 500 with Retry-After header set randomly between 0 and 10 if we
2168 * receive UPDATE while we haven't sent answer.
2169 */
2170 else if (neg_state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER ||
2171 neg_state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO) {
2172 status = pjsip_dlg_create_response(inv->dlg, rdata,
2173 PJSIP_SC_INTERNAL_SERVER_ERROR,
2174 NULL, &tdata);
2175
2176 } else {
2177 /* We receive new offer from remote */
2178 inv_check_sdp_in_incoming_msg(inv, pjsip_rdata_get_tsx(rdata), rdata);
2179
2180 /* Application MUST have supplied the answer by now.
2181 * If so, negotiate the SDP.
2182 */
2183 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
2184 if (neg_state != PJMEDIA_SDP_NEG_STATE_WAIT_NEGO ||
2185 (status=inv_negotiate_sdp(inv)) != PJ_SUCCESS)
2186 {
2187 /* Negotiation has failed */
2188 status = pjsip_dlg_create_response(inv->dlg, rdata,
2189 PJSIP_SC_NOT_ACCEPTABLE_HERE,
2190 NULL, &tdata);
2191 } else {
2192 /* New media has been negotiated successfully, send 200/OK */
2193 status = pjsip_dlg_create_response(inv->dlg, rdata,
2194 PJSIP_SC_OK, NULL, &tdata);
2195 if (status == PJ_SUCCESS) {
2196 pjmedia_sdp_session *sdp;
2197 status = pjmedia_sdp_neg_get_active_local(inv->neg, &sdp);
2198 if (status == PJ_SUCCESS)
2199 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2200 }
2201 }
2202 }
2203
2204 if (status != PJ_SUCCESS) {
2205 if (tdata != NULL) {
2206 pjsip_tx_data_dec_ref(tdata);
2207 tdata = NULL;
2208 }
2209 return;
2210 }
2211
2212 pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata), tdata);
2213}
2214
2215
2216/*
2217 * Handle incoming response to UAC UPDATE request.
2218 */
2219static void inv_handle_update_response( pjsip_inv_session *inv,
2220 pjsip_event *e)
2221{
2222 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2223 struct tsx_inv_data *tsx_inv_data = NULL;
2224 pj_status_t status = -1;
2225
2226 /* Process 2xx response */
2227 if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
2228 tsx->status_code/100 == 2 &&
2229 e->body.tsx_state.src.rdata->msg_info.msg->body)
2230 {
2231 status = inv_check_sdp_in_incoming_msg(inv, tsx,
2232 e->body.tsx_state.src.rdata);
2233
2234 } else {
2235 /* Get/attach invite session's transaction data */
2236 tsx_inv_data = (struct tsx_inv_data*)tsx->mod_data[mod_inv.mod.id];
2237 if (tsx_inv_data == NULL) {
2238 tsx_inv_data=PJ_POOL_ZALLOC_T(tsx->pool, struct tsx_inv_data);
2239 tsx_inv_data->inv = inv;
2240 tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2241 }
2242 }
2243
2244 /* Otherwise if we don't get successful response, cancel
2245 * our negotiator.
2246 */
2247 if (status != PJ_SUCCESS &&
2248 pjmedia_sdp_neg_get_state(inv->neg)==PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER &&
2249 tsx_inv_data && tsx_inv_data->sdp_done == PJ_FALSE)
2250 {
2251 pjmedia_sdp_neg_cancel_offer(inv->neg);
2252
2253 /* Prevent from us cancelling different offer! */
2254 tsx_inv_data->sdp_done = PJ_TRUE;
2255 }
2256}
2257
2258
2259/*
2260 * Handle incoming reliable response.
2261 */
2262static void inv_handle_incoming_reliable_response(pjsip_inv_session *inv,
2263 pjsip_rx_data *rdata)
2264{
2265 pjsip_tx_data *tdata;
2266 pjmedia_sdp_session *sdp;
2267 pj_status_t status;
2268
2269 /* Create PRACK */
2270 status = pjsip_100rel_create_prack(inv, rdata, &tdata);
2271 if (status != PJ_SUCCESS)
2272 return;
2273
2274 /* See if we need to attach SDP answer on the PRACK request */
2275 sdp = inv_has_pending_answer(inv, pjsip_rdata_get_tsx(rdata));
2276 if (sdp) {
2277 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
2278 }
2279
2280 /* Send PRACK (must be using 100rel module!) */
2281 pjsip_100rel_send_prack(inv, tdata);
2282}
2283
2284
2285/*
2286 * Handle incoming PRACK.
2287 */
2288static void inv_respond_incoming_prack(pjsip_inv_session *inv,
2289 pjsip_rx_data *rdata)
2290{
2291 pj_status_t status;
2292
2293 /* Run through 100rel module to see if we can accept this
2294 * PRACK request. The 100rel will send 200/OK to PRACK request.
2295 */
2296 status = pjsip_100rel_on_rx_prack(inv, rdata);
2297 if (status != PJ_SUCCESS)
2298 return;
2299
2300 /* Now check for SDP answer in the PRACK request */
2301 if (rdata->msg_info.msg->body) {
2302 status = inv_check_sdp_in_incoming_msg(inv,
2303 pjsip_rdata_get_tsx(rdata), rdata);
2304 } else {
2305 /* No SDP body */
2306 status = -1;
2307 }
2308
2309 /* If SDP negotiation has been successful, also mark the
2310 * SDP negotiation flag in the invite transaction to be
2311 * done too.
2312 */
2313 if (status == PJ_SUCCESS && inv->invite_tsx) {
2314 struct tsx_inv_data *tsx_inv_data;
2315
2316 /* Get/attach invite session's transaction data */
2317 tsx_inv_data = (struct tsx_inv_data*)
2318 inv->invite_tsx->mod_data[mod_inv.mod.id];
2319 if (tsx_inv_data == NULL) {
2320 tsx_inv_data = PJ_POOL_ZALLOC_T(inv->invite_tsx->pool,
2321 struct tsx_inv_data);
2322 tsx_inv_data->inv = inv;
2323 inv->invite_tsx->mod_data[mod_inv.mod.id] = tsx_inv_data;
2324 }
2325
2326 tsx_inv_data->sdp_done = PJ_TRUE;
2327 }
2328}
2329
2330
2331/*
Benny Prijono8ad55352006-02-08 11:16:05 +00002332 * State NULL is before anything is sent/received.
2333 */
2334static void inv_on_state_null( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002335{
2336 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2337 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2338
2339 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2340
2341 if (tsx->method.id == PJSIP_INVITE_METHOD) {
2342
Benny Prijono64f851e2006-02-23 13:49:28 +00002343 /* Keep the initial INVITE transaction. */
2344 if (inv->invite_tsx == NULL)
2345 inv->invite_tsx = tsx;
Benny Prijono268ca612006-02-07 12:34:11 +00002346
Benny Prijono64f851e2006-02-23 13:49:28 +00002347 if (dlg->role == PJSIP_ROLE_UAC) {
Benny Prijono268ca612006-02-07 12:34:11 +00002348
2349 switch (tsx->state) {
2350 case PJSIP_TSX_STATE_CALLING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002351 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002352 break;
2353 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002354 inv_on_state_calling(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002355 break;
2356 }
2357
2358 } else {
2359 switch (tsx->state) {
2360 case PJSIP_TSX_STATE_TRYING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002361 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002362 break;
Benny Prijono38998232006-02-08 22:44:25 +00002363 case PJSIP_TSX_STATE_PROCEEDING:
2364 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
2365 if (tsx->status_code > 100)
2366 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
2367 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002368 default:
Benny Prijono64f851e2006-02-23 13:49:28 +00002369 inv_on_state_incoming(inv, e);
2370 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002371 }
2372 }
2373
2374 } else {
2375 pj_assert(!"Unexpected transaction type");
2376 }
2377}
2378
Benny Prijono8ad55352006-02-08 11:16:05 +00002379/*
2380 * State CALLING is after sending initial INVITE request but before
2381 * any response (with tag) is received.
2382 */
2383static void inv_on_state_calling( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002384{
2385 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2386 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijonoccf95622006-02-07 18:48:01 +00002387 pj_status_t status;
Benny Prijono268ca612006-02-07 12:34:11 +00002388
2389 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2390
Benny Prijono8ad55352006-02-08 11:16:05 +00002391 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00002392
2393 switch (tsx->state) {
2394
Benny Prijono64f851e2006-02-23 13:49:28 +00002395 case PJSIP_TSX_STATE_CALLING:
2396 inv_set_state(inv, PJSIP_INV_STATE_CALLING, e);
2397 break;
2398
Benny Prijono268ca612006-02-07 12:34:11 +00002399 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono1dc8be02007-05-30 04:26:40 +00002400 if (inv->pending_cancel) {
2401 pjsip_tx_data *cancel;
2402
2403 inv->pending_cancel = PJ_FALSE;
2404
2405 status = pjsip_inv_end_session(inv, 487, NULL, &cancel);
2406 if (status == PJ_SUCCESS && cancel)
2407 status = pjsip_inv_send_msg(inv, cancel);
2408 }
2409
Benny Prijono268ca612006-02-07 12:34:11 +00002410 if (dlg->remote.info->tag.slen) {
Benny Prijonoa66c7152006-02-09 01:26:14 +00002411
Benny Prijono8ad55352006-02-08 11:16:05 +00002412 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002413
2414 inv_check_sdp_in_incoming_msg(inv, tsx,
2415 e->body.tsx_state.src.rdata);
2416
Benny Prijono1f7767b2007-10-03 18:28:49 +00002417 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
2418 inv_handle_incoming_reliable_response(
2419 inv, e->body.tsx_state.src.rdata);
2420 }
2421
Benny Prijono268ca612006-02-07 12:34:11 +00002422 } else {
2423 /* Ignore 100 (Trying) response, as it doesn't change
2424 * session state. It only ceases retransmissions.
2425 */
2426 }
2427 break;
2428
2429 case PJSIP_TSX_STATE_COMPLETED:
2430 if (tsx->status_code/100 == 2) {
2431
2432 /* This should not happen.
2433 * When transaction receives 2xx, it should be terminated
2434 */
2435 pj_assert(0);
Benny Prijono8ad55352006-02-08 11:16:05 +00002436 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002437
2438 inv_check_sdp_in_incoming_msg(inv, tsx,
2439 e->body.tsx_state.src.rdata);
Benny Prijono268ca612006-02-07 12:34:11 +00002440
Benny Prijono0606e702007-05-22 12:21:40 +00002441 } else if ((tsx->status_code==401 || tsx->status_code==407) &&
2442 !inv->cancelling)
2443 {
Benny Prijonoccf95622006-02-07 18:48:01 +00002444
2445 /* Handle authentication failure:
2446 * Resend the request with Authorization header.
2447 */
2448 pjsip_tx_data *tdata;
2449
Benny Prijono8ad55352006-02-08 11:16:05 +00002450 status = pjsip_auth_clt_reinit_req(&inv->dlg->auth_sess,
Benny Prijonoccf95622006-02-07 18:48:01 +00002451 e->body.tsx_state.src.rdata,
2452 tsx->last_tx,
2453 &tdata);
2454
2455 if (status != PJ_SUCCESS) {
2456
2457 /* Does not have proper credentials.
2458 * End the session.
2459 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002460 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002461 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonoccf95622006-02-07 18:48:01 +00002462
2463 } else {
2464
2465 /* Restart session. */
Benny Prijono8ad55352006-02-08 11:16:05 +00002466 inv->state = PJSIP_INV_STATE_NULL;
2467 inv->invite_tsx = NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00002468 if (inv->last_answer) {
2469 pjsip_tx_data_dec_ref(inv->last_answer);
2470 inv->last_answer = NULL;
2471 }
Benny Prijonoccf95622006-02-07 18:48:01 +00002472
2473 /* Send the request. */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00002474 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijonoccf95622006-02-07 18:48:01 +00002475 }
2476
Benny Prijono268ca612006-02-07 12:34:11 +00002477 } else {
Benny Prijonoccf95622006-02-07 18:48:01 +00002478
Benny Prijono0b6340c2006-06-13 22:21:23 +00002479 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002480 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonoccf95622006-02-07 18:48:01 +00002481
Benny Prijono268ca612006-02-07 12:34:11 +00002482 }
2483 break;
2484
2485 case PJSIP_TSX_STATE_TERMINATED:
2486 /* INVITE transaction can be terminated either because UAC
2487 * transaction received 2xx response or because of transport
2488 * error.
2489 */
2490 if (tsx->status_code/100 == 2) {
2491 /* This must be receipt of 2xx response */
2492
2493 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00002494 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002495
Benny Prijonoa66c7152006-02-09 01:26:14 +00002496 inv_check_sdp_in_incoming_msg(inv, tsx,
2497 e->body.tsx_state.src.rdata);
2498
Benny Prijono268ca612006-02-07 12:34:11 +00002499 /* Send ACK */
2500 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
2501
Benny Prijono8ad55352006-02-08 11:16:05 +00002502 inv_send_ack(inv, e->body.tsx_state.src.rdata);
Benny Prijono5eff0432006-02-09 14:14:21 +00002503 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002504
Benny Prijonoa66c7152006-02-09 01:26:14 +00002505
Benny Prijono268ca612006-02-07 12:34:11 +00002506 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002507 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002508 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002509 }
2510 break;
2511
Benny Prijono34a404e2006-02-09 14:38:30 +00002512 default:
2513 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002514 }
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002515
Benny Prijono1f7767b2007-10-03 18:28:49 +00002516 } else if (tsx->role == PJSIP_ROLE_UAC) {
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002517 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002518 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002519 * Transaction Does Not Exist), 408, or when it's timed out. In these
2520 * cases, disconnect session (i.e. dialog usage only).
2521 */
2522 if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||
2523 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
2524 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00002525 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002526 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002527 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002528 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2529 }
Benny Prijono268ca612006-02-07 12:34:11 +00002530 }
2531}
2532
Benny Prijono8ad55352006-02-08 11:16:05 +00002533/*
2534 * State INCOMING is after we received the request, but before
2535 * responses with tag are sent.
2536 */
2537static void inv_on_state_incoming( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002538{
2539 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2540 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2541
2542 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2543
Benny Prijono8ad55352006-02-08 11:16:05 +00002544 if (tsx == inv->invite_tsx) {
2545
2546 /*
2547 * Handle the INVITE state transition.
2548 */
2549
Benny Prijono268ca612006-02-07 12:34:11 +00002550 switch (tsx->state) {
Benny Prijono8ad55352006-02-08 11:16:05 +00002551
Benny Prijono64f851e2006-02-23 13:49:28 +00002552 case PJSIP_TSX_STATE_TRYING:
2553 inv_set_state(inv, PJSIP_INV_STATE_INCOMING, e);
2554 break;
2555
Benny Prijono268ca612006-02-07 12:34:11 +00002556 case PJSIP_TSX_STATE_PROCEEDING:
Benny Prijono8ad55352006-02-08 11:16:05 +00002557 /*
2558 * Transaction sent provisional response.
2559 */
Benny Prijono268ca612006-02-07 12:34:11 +00002560 if (tsx->status_code > 100)
Benny Prijono8ad55352006-02-08 11:16:05 +00002561 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002562 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00002563
Benny Prijono268ca612006-02-07 12:34:11 +00002564 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijono8ad55352006-02-08 11:16:05 +00002565 /*
2566 * Transaction sent final response.
2567 */
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002568 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00002569 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002570 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002571 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002572 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002573 }
Benny Prijono268ca612006-02-07 12:34:11 +00002574 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00002575
Benny Prijono268ca612006-02-07 12:34:11 +00002576 case PJSIP_TSX_STATE_TERMINATED:
Benny Prijono8ad55352006-02-08 11:16:05 +00002577 /*
2578 * This happens on transport error (e.g. failed to send
2579 * response)
2580 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00002581 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002582 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002583 break;
Benny Prijono8ad55352006-02-08 11:16:05 +00002584
Benny Prijono268ca612006-02-07 12:34:11 +00002585 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00002586 pj_assert(!"Unexpected INVITE state");
2587 break;
Benny Prijono268ca612006-02-07 12:34:11 +00002588 }
Benny Prijono8ad55352006-02-08 11:16:05 +00002589
2590 } else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
2591 tsx->role == PJSIP_ROLE_UAS &&
2592 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
2593 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
2594 {
2595
2596 /*
2597 * Handle incoming CANCEL request.
2598 */
2599
2600 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
2601
Benny Prijono268ca612006-02-07 12:34:11 +00002602 }
2603}
2604
Benny Prijono8ad55352006-02-08 11:16:05 +00002605/*
2606 * State EARLY is for both UAS and UAC, after response with To tag
2607 * is sent/received.
2608 */
2609static void inv_on_state_early( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002610{
2611 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2612 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2613
2614 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2615
Benny Prijono8ad55352006-02-08 11:16:05 +00002616 if (tsx == inv->invite_tsx) {
2617
2618 /*
2619 * Handle the INVITE state progress.
2620 */
Benny Prijono268ca612006-02-07 12:34:11 +00002621
2622 switch (tsx->state) {
2623
2624 case PJSIP_TSX_STATE_PROCEEDING:
2625 /* Send/received another provisional response. */
Benny Prijono8ad55352006-02-08 11:16:05 +00002626 inv_set_state(inv, PJSIP_INV_STATE_EARLY, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002627
2628 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
2629 inv_check_sdp_in_incoming_msg(inv, tsx,
2630 e->body.tsx_state.src.rdata);
Benny Prijono1f7767b2007-10-03 18:28:49 +00002631
2632 if (pjsip_100rel_is_reliable(e->body.tsx_state.src.rdata)) {
2633 inv_handle_incoming_reliable_response(
2634 inv, e->body.tsx_state.src.rdata);
2635 }
Benny Prijonoa66c7152006-02-09 01:26:14 +00002636 }
Benny Prijono268ca612006-02-07 12:34:11 +00002637 break;
2638
2639 case PJSIP_TSX_STATE_COMPLETED:
Benny Prijonoa66c7152006-02-09 01:26:14 +00002640 if (tsx->status_code/100 == 2) {
Benny Prijono8ad55352006-02-08 11:16:05 +00002641 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijonoa66c7152006-02-09 01:26:14 +00002642 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
2643 inv_check_sdp_in_incoming_msg(inv, tsx,
2644 e->body.tsx_state.src.rdata);
2645 }
2646
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002647 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002648 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002649 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijonod4e0abd2006-03-05 11:53:36 +00002650 }
Benny Prijono268ca612006-02-07 12:34:11 +00002651 break;
2652
Benny Prijonof3195072006-02-14 21:15:30 +00002653 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00002654 /* For some reason can go here (maybe when ACK for 2xx has
2655 * the same branch value as the INVITE transaction) */
Benny Prijonof3195072006-02-14 21:15:30 +00002656
Benny Prijono268ca612006-02-07 12:34:11 +00002657 case PJSIP_TSX_STATE_TERMINATED:
2658 /* INVITE transaction can be terminated either because UAC
2659 * transaction received 2xx response or because of transport
2660 * error.
2661 */
2662 if (tsx->status_code/100 == 2) {
2663
2664 /* This must be receipt of 2xx response */
2665
2666 /* Set state to CONNECTING */
Benny Prijono8ad55352006-02-08 11:16:05 +00002667 inv_set_state(inv, PJSIP_INV_STATE_CONNECTING, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002668
Benny Prijonoa66c7152006-02-09 01:26:14 +00002669 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
2670 inv_check_sdp_in_incoming_msg(inv, tsx,
2671 e->body.tsx_state.src.rdata);
2672 }
2673
Benny Prijono268ca612006-02-07 12:34:11 +00002674 /* if UAC, send ACK and move state to confirmed. */
2675 if (tsx->role == PJSIP_ROLE_UAC) {
2676 pj_assert(e->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
2677
Benny Prijono8ad55352006-02-08 11:16:05 +00002678 inv_send_ack(inv, e->body.tsx_state.src.rdata);
Benny Prijono8ad55352006-02-08 11:16:05 +00002679 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002680 }
2681
2682 } else {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002683 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002684 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002685 }
2686 break;
2687
2688 default:
Benny Prijono8ad55352006-02-08 11:16:05 +00002689 pj_assert(!"Unexpected INVITE tsx state");
Benny Prijono268ca612006-02-07 12:34:11 +00002690 }
2691
Benny Prijono8ad55352006-02-08 11:16:05 +00002692 } else if (inv->role == PJSIP_ROLE_UAS &&
2693 tsx->role == PJSIP_ROLE_UAS &&
2694 tsx->method.id == PJSIP_CANCEL_METHOD &&
2695 tsx->state < PJSIP_TSX_STATE_COMPLETED &&
2696 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG )
2697 {
Benny Prijono268ca612006-02-07 12:34:11 +00002698
Benny Prijono8ad55352006-02-08 11:16:05 +00002699 /*
2700 * Handle incoming CANCEL request.
Benny Prijonoccf95622006-02-07 18:48:01 +00002701 */
2702
Benny Prijono8ad55352006-02-08 11:16:05 +00002703 inv_respond_incoming_cancel(inv, tsx, e->body.tsx_state.src.rdata);
2704
Benny Prijono1f7767b2007-10-03 18:28:49 +00002705 } else if (tsx->role == PJSIP_ROLE_UAS &&
2706 tsx->state == PJSIP_TSX_STATE_TRYING &&
2707 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002708 {
2709 /*
Benny Prijono1f7767b2007-10-03 18:28:49 +00002710 * Handle incoming UPDATE
2711 */
2712 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
2713
2714
2715 } else if (tsx->role == PJSIP_ROLE_UAC &&
2716 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
2717 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
2718 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
2719 {
2720 /*
2721 * Handle response to outgoing UPDATE request.
2722 */
2723 inv_handle_update_response(inv, e);
2724
2725 } else if (tsx->role == PJSIP_ROLE_UAS &&
2726 tsx->state == PJSIP_TSX_STATE_TRYING &&
2727 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
2728 {
2729 /*
2730 * Handle incoming PRACK
2731 */
2732 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
2733
2734 } else if (tsx->role == PJSIP_ROLE_UAC) {
2735 /*
2736 * Handle case when outgoing request is answered with 481 (Call/
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002737 * Transaction Does Not Exist), 408, or when it's timed out. In these
2738 * cases, disconnect session (i.e. dialog usage only).
2739 */
2740 if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||
2741 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
2742 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
Benny Prijono0b6340c2006-06-13 22:21:23 +00002743 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002744 {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002745 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijonoe4f2abb2006-02-10 14:04:05 +00002746 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2747 }
Benny Prijono268ca612006-02-07 12:34:11 +00002748 }
2749}
2750
Benny Prijono8ad55352006-02-08 11:16:05 +00002751/*
2752 * State CONNECTING is after 2xx response to INVITE is sent/received.
2753 */
2754static void inv_on_state_connecting( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002755{
2756 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2757 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2758
2759 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2760
Benny Prijono8ad55352006-02-08 11:16:05 +00002761 if (tsx == inv->invite_tsx) {
Benny Prijono268ca612006-02-07 12:34:11 +00002762
Benny Prijono8ad55352006-02-08 11:16:05 +00002763 /*
2764 * Handle INVITE state progression.
2765 */
Benny Prijono268ca612006-02-07 12:34:11 +00002766 switch (tsx->state) {
2767
2768 case PJSIP_TSX_STATE_CONFIRMED:
Benny Prijono7d910092007-06-20 04:19:46 +00002769 /* It can only go here if incoming ACK request has the same Via
2770 * branch parameter as the INVITE transaction.
2771 */
2772 if (tsx->status_code/100 == 2) {
2773 if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
2774 inv_check_sdp_in_incoming_msg(inv, tsx,
2775 e->body.tsx_state.src.rdata);
2776 }
2777
Benny Prijono38998232006-02-08 22:44:25 +00002778 inv_set_state(inv, PJSIP_INV_STATE_CONFIRMED, e);
Benny Prijono7d910092007-06-20 04:19:46 +00002779 }
Benny Prijono268ca612006-02-07 12:34:11 +00002780 break;
2781
2782 case PJSIP_TSX_STATE_TERMINATED:
2783 /* INVITE transaction can be terminated either because UAC
2784 * transaction received 2xx response or because of transport
2785 * error.
2786 */
2787 if (tsx->status_code/100 != 2) {
Benny Prijono0b6340c2006-06-13 22:21:23 +00002788 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono8ad55352006-02-08 11:16:05 +00002789 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002790 }
2791 break;
2792
2793 case PJSIP_TSX_STATE_DESTROYED:
2794 /* Do nothing. */
2795 break;
2796
2797 default:
2798 pj_assert(!"Unexpected state");
2799 }
2800
Benny Prijono8ad55352006-02-08 11:16:05 +00002801 } else if (tsx->role == PJSIP_ROLE_UAS &&
2802 tsx->method.id == PJSIP_BYE_METHOD &&
2803 tsx->status_code < 200 &&
2804 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
2805 {
2806
2807 /*
2808 * Handle incoming BYE.
2809 */
2810
2811 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
2812
Benny Prijono38998232006-02-08 22:44:25 +00002813 } else if (tsx->method.id == PJSIP_BYE_METHOD &&
2814 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00002815 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
2816 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono38998232006-02-08 22:44:25 +00002817 {
2818
2819 /*
2820 * Outgoing BYE
2821 */
2822 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
2823
Benny Prijono268ca612006-02-07 12:34:11 +00002824 }
Benny Prijono70127222006-07-02 14:53:05 +00002825 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
2826 tsx->role == PJSIP_ROLE_UAS &&
2827 tsx->status_code < 200 &&
2828 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
2829 {
Benny Prijono38998232006-02-08 22:44:25 +00002830
Benny Prijono70127222006-07-02 14:53:05 +00002831 /*
2832 * Handle strandled incoming CANCEL.
2833 */
2834 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
2835 pjsip_tx_data *tdata;
2836 pj_status_t status;
2837
2838 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
2839 if (status != PJ_SUCCESS) return;
2840
2841 status = pjsip_dlg_send_response(dlg, tsx, tdata);
2842 if (status != PJ_SUCCESS) return;
2843
Benny Prijono1f7767b2007-10-03 18:28:49 +00002844 } else if (tsx->role == PJSIP_ROLE_UAS &&
2845 tsx->state == PJSIP_TSX_STATE_TRYING &&
2846 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
2847 {
2848 /*
2849 * Handle incoming UPDATE
2850 */
2851 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
2852
2853
2854 } else if (tsx->role == PJSIP_ROLE_UAC &&
2855 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
2856 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
2857 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
2858 {
2859 /*
2860 * Handle response to outgoing UPDATE request.
2861 */
2862 inv_handle_update_response(inv, e);
2863
2864 } else if (tsx->role == PJSIP_ROLE_UAS &&
2865 tsx->state == PJSIP_TSX_STATE_TRYING &&
2866 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
2867 {
2868 /*
2869 * Handle incoming PRACK
2870 */
2871 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
2872
2873 } else if (tsx->role == PJSIP_ROLE_UAC) {
2874 /*
2875 * Handle case when outgoing request is answered with 481 (Call/
2876 * Transaction Does Not Exist), 408, or when it's timed out. In these
2877 * cases, disconnect session (i.e. dialog usage only).
2878 */
2879 if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||
2880 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
2881 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
2882 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
2883 {
2884 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
2885 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
2886 }
Benny Prijono70127222006-07-02 14:53:05 +00002887 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00002888
Benny Prijono268ca612006-02-07 12:34:11 +00002889}
2890
Benny Prijono8ad55352006-02-08 11:16:05 +00002891/*
2892 * State CONFIRMED is after ACK is sent/received.
2893 */
2894static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00002895{
2896 pjsip_transaction *tsx = e->body.tsx_state.tsx;
2897 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
2898
2899 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
2900
Benny Prijono268ca612006-02-07 12:34:11 +00002901
Benny Prijono8ad55352006-02-08 11:16:05 +00002902 if (tsx->method.id == PJSIP_BYE_METHOD &&
2903 tsx->role == PJSIP_ROLE_UAC &&
Benny Prijonoa66c7152006-02-09 01:26:14 +00002904 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
2905 tsx->state == PJSIP_TSX_STATE_TERMINATED))
Benny Prijono8ad55352006-02-08 11:16:05 +00002906 {
Benny Prijono38998232006-02-08 22:44:25 +00002907
Benny Prijono8ad55352006-02-08 11:16:05 +00002908 /*
Benny Prijono38998232006-02-08 22:44:25 +00002909 * Outgoing BYE
Benny Prijono8ad55352006-02-08 11:16:05 +00002910 */
Benny Prijono8ad55352006-02-08 11:16:05 +00002911
Benny Prijonoa66c7152006-02-09 01:26:14 +00002912 inv_handle_bye_response( inv, tsx, e->body.tsx_state.src.rdata, e);
Benny Prijono268ca612006-02-07 12:34:11 +00002913
Benny Prijono8ad55352006-02-08 11:16:05 +00002914 }
2915 else if (tsx->method.id == PJSIP_BYE_METHOD &&
2916 tsx->role == PJSIP_ROLE_UAS &&
2917 tsx->status_code < 200 &&
2918 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
2919 {
Benny Prijonoccf95622006-02-07 18:48:01 +00002920
Benny Prijono8ad55352006-02-08 11:16:05 +00002921 /*
2922 * Handle incoming BYE.
2923 */
Benny Prijono268ca612006-02-07 12:34:11 +00002924
Benny Prijono8ad55352006-02-08 11:16:05 +00002925 inv_respond_incoming_bye( inv, tsx, e->body.tsx_state.src.rdata, e );
2926
Benny Prijono268ca612006-02-07 12:34:11 +00002927 }
Benny Prijono70127222006-07-02 14:53:05 +00002928 else if (tsx->method.id == PJSIP_CANCEL_METHOD &&
2929 tsx->role == PJSIP_ROLE_UAS &&
2930 tsx->status_code < 200 &&
2931 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
2932 {
2933
2934 /*
2935 * Handle strandled incoming CANCEL.
2936 */
2937 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
2938 pjsip_tx_data *tdata;
2939 pj_status_t status;
2940
2941 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
2942 if (status != PJ_SUCCESS) return;
2943
2944 status = pjsip_dlg_send_response(dlg, tsx, tdata);
2945 if (status != PJ_SUCCESS) return;
2946
2947 }
Benny Prijono26ff9062006-02-21 23:47:00 +00002948 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
2949 tsx->role == PJSIP_ROLE_UAS)
2950 {
2951
2952 /*
2953 * Handle incoming re-INVITE
2954 */
2955 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
2956
2957 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
2958 pjsip_tx_data *tdata;
2959 pj_status_t status;
2960
2961 /* Check if we have INVITE pending. */
2962 if (inv->invite_tsx && inv->invite_tsx!=tsx) {
Benny Prijono46249942007-02-19 22:23:14 +00002963 pj_str_t reason;
2964
2965 reason = pj_str("Another INVITE transaction in progress");
Benny Prijono26ff9062006-02-21 23:47:00 +00002966
2967 /* Can not receive re-INVITE while another one is pending. */
Benny Prijono46249942007-02-19 22:23:14 +00002968 status = pjsip_dlg_create_response( inv->dlg, rdata, 500,
2969 &reason, &tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00002970 if (status != PJ_SUCCESS)
2971 return;
2972
2973 status = pjsip_dlg_send_response( inv->dlg, tsx, tdata);
2974
2975
2976 return;
2977 }
2978
2979 /* Save the invite transaction. */
2980 inv->invite_tsx = tsx;
2981
2982 /* Process SDP in incoming message. */
2983 status = inv_check_sdp_in_incoming_msg(inv, tsx, rdata);
2984
2985 if (status != PJ_SUCCESS) {
2986
2987 /* Not Acceptable */
2988 const pjsip_hdr *accept;
2989
2990 status = pjsip_dlg_create_response(inv->dlg, rdata,
2991 488, NULL, &tdata);
2992 if (status != PJ_SUCCESS)
2993 return;
2994
2995
2996 accept = pjsip_endpt_get_capability(dlg->endpt, PJSIP_H_ACCEPT,
2997 NULL);
2998 if (accept) {
Benny Prijonoa1e69682007-05-11 15:14:34 +00002999 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
Benny Prijono26ff9062006-02-21 23:47:00 +00003000 pjsip_hdr_clone(tdata->pool, accept));
3001 }
3002
3003 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3004
3005 return;
3006 }
3007
3008 /* Create 2xx ANSWER */
3009 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3010 if (status != PJ_SUCCESS)
3011 return;
3012
Benny Prijono7d910092007-06-20 04:19:46 +00003013 /* If the INVITE request has SDP body, send answer.
3014 * Otherwise generate offer from local active SDP.
3015 */
3016 if (rdata->msg_info.msg->body != NULL) {
3017 status = process_answer(inv, 200, tdata, NULL);
3018 } else {
Benny Prijono77998ce2007-06-20 10:03:46 +00003019 /* INVITE does not have SDP.
3020 * If on_create_offer() callback is implemented, ask app.
3021 * to generate an offer, otherwise just send active local
3022 * SDP to signal that nothing gets modified.
3023 */
3024 pjmedia_sdp_session *sdp = NULL;
3025
3026 if (mod_inv.cb.on_create_offer) {
3027 (*mod_inv.cb.on_create_offer)(inv, &sdp);
3028 if (sdp) {
3029 status = pjmedia_sdp_neg_modify_local_offer(dlg->pool,
3030 inv->neg,
3031 sdp);
3032 }
3033 }
3034
3035 if (sdp == NULL) {
3036 const pjmedia_sdp_session *active_sdp = NULL;
3037 status = pjmedia_sdp_neg_send_local_offer(dlg->pool,
3038 inv->neg,
3039 &active_sdp);
3040 if (status == PJ_SUCCESS)
3041 sdp = (pjmedia_sdp_session*) active_sdp;
3042 }
3043
3044 if (sdp) {
3045 tdata->msg->body = create_sdp_body(tdata->pool, sdp);
Benny Prijono7d910092007-06-20 04:19:46 +00003046 }
3047 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003048
Benny Prijono1d9b9a42006-09-25 13:40:12 +00003049 if (status != PJ_SUCCESS) {
3050 /*
3051 * SDP negotiation has failed.
3052 */
3053 pj_status_t rc;
3054 pj_str_t reason;
3055
3056 /* Delete the 2xx answer */
3057 pjsip_tx_data_dec_ref(tdata);
3058
3059 /* Create 500 response */
3060 reason = pj_str("SDP negotiation failed");
3061 rc = pjsip_dlg_create_response(dlg, rdata, 500, &reason,
3062 &tdata);
3063 if (rc == PJ_SUCCESS) {
3064 pjsip_warning_hdr *w;
3065 const pj_str_t *endpt_name;
3066
3067 endpt_name = pjsip_endpt_name(dlg->endpt);
3068 w = pjsip_warning_hdr_create_from_status(tdata->pool,
3069 endpt_name,
3070 status);
3071 if (w)
3072 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)w);
3073
3074 pjsip_inv_send_msg(inv, tdata);
3075 }
3076 return;
3077 }
3078
3079 /* Send 2xx regardless of the status of negotiation */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003080 status = pjsip_inv_send_msg(inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003081
Benny Prijono7d910092007-06-20 04:19:46 +00003082 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
3083 /* This is the case where ACK has the same branch as
3084 * the INVITE request.
3085 */
3086 if (tsx->status_code/100 == 2 &&
3087 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3088 {
3089 inv_check_sdp_in_incoming_msg(inv, tsx,
3090 e->body.tsx_state.src.rdata);
3091 }
3092
Benny Prijono26ff9062006-02-21 23:47:00 +00003093 }
3094
3095 }
3096 else if (tsx->method.id == PJSIP_INVITE_METHOD &&
3097 tsx->role == PJSIP_ROLE_UAC)
3098 {
3099 /*
3100 * Handle outgoing re-INVITE
3101 */
3102 if (tsx->state == PJSIP_TSX_STATE_TERMINATED &&
3103 tsx->status_code/100 == 2)
3104 {
3105
3106 /* Re-INVITE was accepted. */
3107
3108 /* Process SDP */
3109 inv_check_sdp_in_incoming_msg(inv, tsx,
3110 e->body.tsx_state.src.rdata);
3111
3112 /* Send ACK */
Benny Prijono853ab812007-06-12 15:40:38 +00003113 inv_send_ack(inv, e->body.tsx_state.src.rdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003114
3115 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED &&
3116 (tsx->status_code==401 || tsx->status_code==407))
3117 {
3118 pjsip_tx_data *tdata;
3119 pj_status_t status;
3120
3121 /* Handle authentication challenge. */
3122 status = pjsip_auth_clt_reinit_req( &dlg->auth_sess,
3123 e->body.tsx_state.src.rdata,
3124 tsx->last_tx,
3125 &tdata);
3126 if (status != PJ_SUCCESS)
3127 return;
3128
3129 /* Send re-INVITE */
Benny Prijonoe8b0d3b2006-03-17 17:57:52 +00003130 status = pjsip_inv_send_msg( inv, tdata);
Benny Prijono26ff9062006-02-21 23:47:00 +00003131
3132 } else if (tsx->status_code==PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||
3133 tsx->status_code==PJSIP_SC_REQUEST_TIMEOUT ||
3134 tsx->status_code >= 700)
3135 {
3136 /*
3137 * Handle responses that terminates dialog.
3138 */
Benny Prijono0b6340c2006-06-13 22:21:23 +00003139 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
Benny Prijono26ff9062006-02-21 23:47:00 +00003140 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
Benny Prijono77998ce2007-06-20 10:03:46 +00003141
3142 } else if (tsx->status_code >= 300 && tsx->status_code < 700) {
3143
3144 pjmedia_sdp_neg_state neg_state;
3145
3146 /* Outgoing INVITE transaction has failed, cancel SDP nego */
3147 neg_state = pjmedia_sdp_neg_get_state(inv->neg);
3148 if (neg_state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) {
3149 pjmedia_sdp_neg_cancel_offer(inv->neg);
3150 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003151 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003152
3153 } else if (tsx->role == PJSIP_ROLE_UAS &&
3154 tsx->state == PJSIP_TSX_STATE_TRYING &&
3155 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3156 {
3157 /*
3158 * Handle incoming UPDATE
3159 */
3160 inv_respond_incoming_update(inv, e->body.tsx_state.src.rdata);
3161
3162 } else if (tsx->role == PJSIP_ROLE_UAC &&
3163 (tsx->state == PJSIP_TSX_STATE_COMPLETED ||
3164 tsx->state == PJSIP_TSX_STATE_TERMINATED) &&
3165 pjsip_method_cmp(&tsx->method, &pjsip_update_method)==0)
3166 {
3167 /*
3168 * Handle response to outgoing UPDATE request.
3169 */
3170 inv_handle_update_response(inv, e);
3171
3172 } else if (tsx->role == PJSIP_ROLE_UAS &&
3173 tsx->state == PJSIP_TSX_STATE_TRYING &&
3174 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0)
3175 {
3176 /*
3177 * Handle strandled incoming PRACK
3178 */
3179 inv_respond_incoming_prack(inv, e->body.tsx_state.src.rdata);
3180
3181 } else if (tsx->role == PJSIP_ROLE_UAC) {
3182 /*
3183 * Handle case when outgoing request is answered with 481 (Call/
3184 * Transaction Does Not Exist), 408, or when it's timed out. In these
3185 * cases, disconnect session (i.e. dialog usage only).
3186 */
3187 if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST ||
3188 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT ||
3189 tsx->status_code == PJSIP_SC_TSX_TIMEOUT ||
3190 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR)
3191 {
3192 inv_set_cause(inv, tsx->status_code, &tsx->status_text);
3193 inv_set_state(inv, PJSIP_INV_STATE_DISCONNECTED, e);
3194 }
Benny Prijono26ff9062006-02-21 23:47:00 +00003195 }
Benny Prijono1f7767b2007-10-03 18:28:49 +00003196
Benny Prijono268ca612006-02-07 12:34:11 +00003197}
3198
Benny Prijono8ad55352006-02-08 11:16:05 +00003199/*
3200 * After session has been terminated, but before dialog is destroyed
3201 * (because dialog has other usages, or because dialog is waiting for
3202 * the last transaction to terminate).
3203 */
3204static void inv_on_state_disconnected( pjsip_inv_session *inv, pjsip_event *e)
Benny Prijono268ca612006-02-07 12:34:11 +00003205{
Benny Prijono8ad55352006-02-08 11:16:05 +00003206 pjsip_transaction *tsx = e->body.tsx_state.tsx;
3207 pjsip_dialog *dlg = pjsip_tsx_get_dlg(tsx);
Benny Prijono268ca612006-02-07 12:34:11 +00003208
Benny Prijono8ad55352006-02-08 11:16:05 +00003209 PJ_ASSERT_ON_FAIL(tsx && dlg, return);
3210
Benny Prijono70127222006-07-02 14:53:05 +00003211 if (tsx->role == PJSIP_ROLE_UAS &&
Benny Prijono8ad55352006-02-08 11:16:05 +00003212 tsx->status_code < 200 &&
3213 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
3214 {
Benny Prijono70127222006-07-02 14:53:05 +00003215 pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
Benny Prijono8ad55352006-02-08 11:16:05 +00003216
3217 /*
Benny Prijono70127222006-07-02 14:53:05 +00003218 * Respond BYE with 200/OK
Benny Prijono8ad55352006-02-08 11:16:05 +00003219 */
Benny Prijono70127222006-07-02 14:53:05 +00003220 if (tsx->method.id == PJSIP_BYE_METHOD) {
3221 inv_respond_incoming_bye( inv, tsx, rdata, e );
3222 } else if (tsx->method.id == PJSIP_CANCEL_METHOD) {
3223 /*
3224 * Respond CANCEL with 200/OK too.
3225 */
3226 pjsip_tx_data *tdata;
3227 pj_status_t status;
Benny Prijono8ad55352006-02-08 11:16:05 +00003228
Benny Prijono70127222006-07-02 14:53:05 +00003229 status = pjsip_dlg_create_response(dlg, rdata, 200, NULL, &tdata);
3230 if (status != PJ_SUCCESS) return;
Benny Prijono8ad55352006-02-08 11:16:05 +00003231
Benny Prijono70127222006-07-02 14:53:05 +00003232 status = pjsip_dlg_send_response(dlg, tsx, tdata);
3233 if (status != PJ_SUCCESS) return;
3234
3235 }
Benny Prijono8ad55352006-02-08 11:16:05 +00003236 }
Benny Prijono268ca612006-02-07 12:34:11 +00003237}
3238