blob: 5d49731ee006bf32910033e6235e09aa72ca4d1e [file] [log] [blame]
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001/* $Id$ */
2/*
Nanang Izzuddina62ffc92011-05-05 06:14:19 +00003 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjsip-ua/sip_100rel.h>
21#include <pjsip/sip_endpoint.h>
22#include <pjsip/sip_event.h>
23#include <pjsip/sip_module.h>
24#include <pjsip/sip_transaction.h>
25#include <pj/assert.h>
26#include <pj/ctype.h>
27#include <pj/log.h>
28#include <pj/os.h>
29#include <pj/pool.h>
30#include <pj/rand.h>
Benny Prijonoc45d9512010-12-10 11:04:30 +000031#include <pj/string.h>
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000032
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000033#define THIS_FILE "sip_100rel.c"
34
Benny Prijono1f7767b2007-10-03 18:28:49 +000035/* PRACK method */
36PJ_DEF_DATA(const pjsip_method) pjsip_prack_method =
37{
38 PJSIP_OTHER_METHOD,
39 { "PRACK", 5 }
40};
41
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000042typedef struct dlg_data dlg_data;
43
44/*
45 * Static prototypes.
46 */
47static pj_status_t mod_100rel_load(pjsip_endpoint *endpt);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000048
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000049static void on_retransmit(pj_timer_heap_t *timer_heap,
50 struct pj_timer_entry *entry);
51
52
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000053const pj_str_t tag_100rel = { "100rel", 6 };
54const pj_str_t RSEQ = { "RSeq", 4 };
55const pj_str_t RACK = { "RAck", 4 };
56
57
58/* 100rel module */
59static struct mod_100rel
60{
61 pjsip_module mod;
62 pjsip_endpoint *endpt;
63} mod_100rel =
64{
65 {
66 NULL, NULL, /* prev, next. */
67 { "mod-100rel", 10 }, /* Name. */
68 -1, /* Id */
69 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
70 &mod_100rel_load, /* load() */
71 NULL, /* start() */
72 NULL, /* stop() */
73 NULL, /* unload() */
74 NULL, /* on_rx_request() */
75 NULL, /* on_rx_response() */
76 NULL, /* on_tx_request. */
77 NULL, /* on_tx_response() */
Benny Prijono1f7767b2007-10-03 18:28:49 +000078 NULL, /* on_tsx_state() */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000079 }
80
81};
82
83/* List of pending transmission (may include the final response as well) */
Benny Prijono373633c2007-09-30 18:06:41 +000084typedef struct tx_data_list_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000085{
Benny Prijono373633c2007-09-30 18:06:41 +000086 PJ_DECL_LIST_MEMBER(struct tx_data_list_t);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000087 pj_uint32_t rseq;
88 pjsip_tx_data *tdata;
Benny Prijono373633c2007-09-30 18:06:41 +000089} tx_data_list_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000090
91
92/* Below, UAS and UAC roles are of the INVITE transaction */
93
94/* UAS state. */
Benny Prijono373633c2007-09-30 18:06:41 +000095typedef struct uas_state_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000096{
97 pj_int32_t cseq;
98 pj_uint32_t rseq; /* Initialized to -1 */
Benny Prijono373633c2007-09-30 18:06:41 +000099 tx_data_list_t tx_data_list;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000100 unsigned retransmit_count;
101 pj_timer_entry retransmit_timer;
Benny Prijono373633c2007-09-30 18:06:41 +0000102} uas_state_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000103
104
105/* UAC state */
Benny Prijono373633c2007-09-30 18:06:41 +0000106typedef struct uac_state_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000107{
108 pj_int32_t cseq;
109 pj_uint32_t rseq; /* Initialized to -1 */
Benny Prijono373633c2007-09-30 18:06:41 +0000110} uac_state_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000111
112
113/* State attached to each dialog. */
114struct dlg_data
115{
116 pjsip_inv_session *inv;
Benny Prijono373633c2007-09-30 18:06:41 +0000117 uas_state_t *uas_state;
118 uac_state_t *uac_state;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000119};
120
121
122/*****************************************************************************
123 **
124 ** Module
125 **
126 *****************************************************************************
127 */
128static pj_status_t mod_100rel_load(pjsip_endpoint *endpt)
129{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000130 mod_100rel.endpt = endpt;
131 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
132 PJSIP_H_ALLOW, NULL,
133 1, &pjsip_prack_method.name);
134 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
135 PJSIP_H_SUPPORTED, NULL,
136 1, &tag_100rel);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000137
Benny Prijono1f7767b2007-10-03 18:28:49 +0000138 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000139}
140
141static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg)
142{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000143 pjsip_require_hdr *hreq;
144
145 hreq = (pjsip_require_hdr*)
146 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
147
148 while (hreq) {
149 unsigned i;
150 for (i=0; i<hreq->count; ++i) {
151 if (!pj_stricmp(&hreq->values[i], &tag_100rel)) {
152 return hreq;
153 }
154 }
155
156 if ((void*)hreq->next == (void*)&msg->hdr)
157 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000158
159 hreq = (pjsip_require_hdr*)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000160 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000161
Benny Prijono1f7767b2007-10-03 18:28:49 +0000162 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000163
Benny Prijono1f7767b2007-10-03 18:28:49 +0000164 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000165}
166
167
168/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000169 * Get PRACK method constant.
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000170 */
Benny Prijono1f7767b2007-10-03 18:28:49 +0000171PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000172{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000173 return &pjsip_prack_method;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000174}
175
176
177/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000178 * init module
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000179 */
180PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt)
181{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000182 if (mod_100rel.mod.id != -1)
183 return PJ_SUCCESS;
184
185 return pjsip_endpt_register_module(endpt, &mod_100rel.mod);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000186}
187
188
189/*
190 * API: attach 100rel support in invite session. Called by
191 * sip_inv.c
192 */
193PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv)
194{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000195 dlg_data *dd;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000196
Benny Prijono1f7767b2007-10-03 18:28:49 +0000197 /* Check that 100rel module has been initialized */
198 PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000199
Benny Prijono1f7767b2007-10-03 18:28:49 +0000200 /* Create and attach as dialog usage */
201 dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data);
202 dd->inv = inv;
203 pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000204
Benny Prijono1f7767b2007-10-03 18:28:49 +0000205 PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached"));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000206
Benny Prijono1f7767b2007-10-03 18:28:49 +0000207 return PJ_SUCCESS;
208}
209
210
211/*
212 * Check if incoming response has reliable provisional response feature.
213 */
214PJ_DEF(pj_bool_t) pjsip_100rel_is_reliable(pjsip_rx_data *rdata)
215{
216 pjsip_msg *msg = rdata->msg_info.msg;
217
218 PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG, PJ_FALSE);
219
220 return msg->line.status.code > 100 && msg->line.status.code < 200 &&
221 rdata->msg_info.require != NULL &&
222 find_req_hdr(msg) != NULL;
223}
224
225
226/*
227 * Create PRACK request for the incoming reliable provisional response.
228 */
229PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
230 pjsip_rx_data *rdata,
231 pjsip_tx_data **p_tdata)
232{
233 dlg_data *dd;
234 pjsip_transaction *tsx;
235 pjsip_msg *msg;
236 pjsip_generic_string_hdr *rseq_hdr;
237 pjsip_generic_string_hdr *rack_hdr;
238 unsigned rseq;
239 pj_str_t rack;
240 char rack_buf[80];
241 pjsip_tx_data *tdata;
242 pj_status_t status;
243
244 *p_tdata = NULL;
245
246 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
247 PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED);
248
249 tsx = pjsip_rdata_get_tsx(rdata);
250 msg = rdata->msg_info.msg;
251
252 /* Check our assumptions */
253 pj_assert( tsx->role == PJSIP_ROLE_UAC &&
254 tsx->method.id == PJSIP_INVITE_METHOD &&
255 msg->line.status.code > 100 &&
256 msg->line.status.code < 200);
257
258
259 /* Get the RSeq header */
260 rseq_hdr = (pjsip_generic_string_hdr*)
261 pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL);
262 if (rseq_hdr == NULL) {
263 PJ_LOG(4,(dd->inv->dlg->obj_name,
264 "Ignoring provisional response with no RSeq header"));
265 return PJSIP_EMISSINGHDR;
266 }
267 rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);
268
269 /* Create new UAC state if we don't have one */
270 if (dd->uac_state == NULL) {
271 dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool,
272 uac_state_t);
273 dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
274 dd->uac_state->rseq = rseq - 1;
275 }
276
277 /* If this is from new INVITE transaction, reset UAC state */
278 if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) {
279 dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
280 dd->uac_state->rseq = rseq - 1;
281 }
282
283 /* Ignore provisional response retransmission */
284 if (rseq <= dd->uac_state->rseq) {
285 /* This should have been handled before */
286 return PJ_EIGNORED;
287
288 /* Ignore provisional response with out-of-order RSeq */
289 } else if (rseq != dd->uac_state->rseq + 1) {
290 PJ_LOG(4,(dd->inv->dlg->obj_name,
291 "Ignoring provisional response because RSeq jump "
292 "(expecting %u, got %u)",
293 dd->uac_state->rseq+1, rseq));
294 return PJ_EIGNORED;
295 }
296
297 /* Update our RSeq */
298 dd->uac_state->rseq = rseq;
299
300 /* Create PRACK */
301 status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method,
302 -1, &tdata);
303 if (status != PJ_SUCCESS)
304 return status;
305
306 /* Create RAck header */
307 rack.ptr = rack_buf;
308 rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf),
309 "%u %u %.*s",
310 rseq, rdata->msg_info.cseq->cseq,
311 (int)tsx->method.name.slen,
312 tsx->method.name.ptr);
313 rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack);
314 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr);
315
316 /* Done */
317 *p_tdata = tdata;
318
319 return PJ_SUCCESS;
320}
321
322
323/*
324 * Send PRACK request.
325 */
326PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv,
327 pjsip_tx_data *tdata)
328{
329 dlg_data *dd;
330
331 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
332 PJ_ASSERT_ON_FAIL(dd != NULL,
333 {pjsip_tx_data_dec_ref(tdata); return PJSIP_ENOTINITIALIZED; });
334
335 return pjsip_dlg_send_request(inv->dlg, tdata,
336 mod_100rel.mod.id, (void*) dd);
337
338}
339
340
341/*
342 * Notify 100rel module that the invite session has been disconnected.
343 */
344PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv)
345{
346 dlg_data *dd;
347
348 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
349 if (!dd)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000350 return PJ_SUCCESS;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000351
352 /* Make sure we don't have pending transmission */
353 if (dd->uas_state) {
354 pj_assert(!dd->uas_state->retransmit_timer.id);
355 pj_assert(pj_list_empty(&dd->uas_state->tx_data_list));
356 }
357
358 return PJ_SUCCESS;
359}
360
361
362static void parse_rack(const pj_str_t *rack,
363 pj_uint32_t *p_rseq, pj_int32_t *p_seq,
364 pj_str_t *p_method)
365{
366 const char *p = rack->ptr, *end = p + rack->slen;
367 pj_str_t token;
368
369 token.ptr = (char*)p;
370 while (p < end && pj_isdigit(*p))
371 ++p;
372 token.slen = p - token.ptr;
373 *p_rseq = pj_strtoul(&token);
374
375 ++p;
376 token.ptr = (char*)p;
377 while (p < end && pj_isdigit(*p))
378 ++p;
379 token.slen = p - token.ptr;
380 *p_seq = pj_strtoul(&token);
381
382 ++p;
383 if (p < end) {
384 p_method->ptr = (char*)p;
385 p_method->slen = end - p;
386 } else {
387 p_method->ptr = NULL;
388 p_method->slen = 0;
389 }
390}
391
392/* Clear all responses in the transmission list */
393static void clear_all_responses(dlg_data *dd)
394{
395 tx_data_list_t *tl;
396
397 tl = dd->uas_state->tx_data_list.next;
398 while (tl != &dd->uas_state->tx_data_list) {
399 pjsip_tx_data_dec_ref(tl->tdata);
400 tl = tl->next;
401 }
402 pj_list_init(&dd->uas_state->tx_data_list);
403}
404
405
406/*
407 * Handle incoming PRACK request.
408 */
409PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv,
410 pjsip_rx_data *rdata)
411{
412 dlg_data *dd;
413 pjsip_transaction *tsx;
414 pjsip_msg *msg;
415 pjsip_generic_string_hdr *rack_hdr;
416 pjsip_tx_data *tdata;
417 pj_uint32_t rseq;
418 pj_int32_t cseq;
419 pj_str_t method;
420 pj_status_t status;
421
Benny Prijono1f7767b2007-10-03 18:28:49 +0000422 tsx = pjsip_rdata_get_tsx(rdata);
423 pj_assert(tsx != NULL);
424
425 msg = rdata->msg_info.msg;
426
Benny Prijono2d2cc942008-09-11 08:00:47 +0000427 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
428 if (dd == NULL) {
429 /* UAC sends us PRACK while we didn't send reliable provisional
430 * response. Respond with 400 (?)
431 */
432 const pj_str_t reason = pj_str("Unexpected PRACK");
433
434 status = pjsip_dlg_create_response(inv->dlg, rdata, 400,
435 &reason, &tdata);
436 if (status == PJ_SUCCESS) {
437 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
438 }
439 return PJSIP_ENOTINITIALIZED;
440 }
441
Benny Prijono1f7767b2007-10-03 18:28:49 +0000442 /* Always reply with 200/OK for PRACK */
443 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
444 if (status == PJ_SUCCESS) {
445 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
446 }
447
448 /* Ignore if we don't have pending transmission */
449 if (dd->uas_state == NULL || pj_list_empty(&dd->uas_state->tx_data_list)) {
450 PJ_LOG(4,(dd->inv->dlg->obj_name,
451 "PRACK ignored - no pending response"));
452 return PJ_EIGNORED;
453 }
454
455 /* Find RAck header */
456 rack_hdr = (pjsip_generic_string_hdr*)
457 pjsip_msg_find_hdr_by_name(msg, &RACK, NULL);
458 if (!rack_hdr) {
459 /* RAck header not found */
460 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header"));
461 return PJSIP_EMISSINGHDR;
462 }
463
464 /* Parse RAck header */
465 parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method);
466
467
468 /* Match RAck against outgoing transmission */
469 if (rseq == dd->uas_state->tx_data_list.next->rseq &&
470 cseq == dd->uas_state->cseq)
471 {
472 /*
473 * Yes this PRACK matches outgoing transmission.
474 */
475 tx_data_list_t *tl = dd->uas_state->tx_data_list.next;
476
477 if (dd->uas_state->retransmit_timer.id) {
478 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
479 &dd->uas_state->retransmit_timer);
480 dd->uas_state->retransmit_timer.id = PJ_FALSE;
481 }
482
483 /* Remove from the list */
484 if (tl != &dd->uas_state->tx_data_list) {
485 pj_list_erase(tl);
486
487 /* Destroy the response */
488 pjsip_tx_data_dec_ref(tl->tdata);
489 }
490
491 /* Schedule next packet */
492 dd->uas_state->retransmit_count = 0;
493 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
494 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
495 }
496
497 } else {
498 /* No it doesn't match */
499 PJ_LOG(4,(dd->inv->dlg->obj_name,
500 "Rx PRACK with no matching reliable response"));
501 return PJ_EIGNORED;
502 }
503
504 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000505}
506
507
508/*
509 * This is retransmit timer callback, called initially to send the response,
510 * and subsequently when the retransmission time elapses.
511 */
512static void on_retransmit(pj_timer_heap_t *timer_heap,
513 struct pj_timer_entry *entry)
514{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000515 dlg_data *dd;
516 tx_data_list_t *tl;
517 pjsip_tx_data *tdata;
518 pj_bool_t final;
519 pj_time_val delay;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000520
Benny Prijono1f7767b2007-10-03 18:28:49 +0000521 PJ_UNUSED_ARG(timer_heap);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000522
Benny Prijono1f7767b2007-10-03 18:28:49 +0000523 dd = (dlg_data*) entry->user_data;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000524
Benny Prijono1f7767b2007-10-03 18:28:49 +0000525 entry->id = PJ_FALSE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000526
Benny Prijono1f7767b2007-10-03 18:28:49 +0000527 ++dd->uas_state->retransmit_count;
528 if (dd->uas_state->retransmit_count >= 7) {
529 /* If a reliable provisional response is retransmitted for
530 64*T1 seconds without reception of a corresponding PRACK,
531 the UAS SHOULD reject the original request with a 5xx
532 response.
533 */
534 pj_str_t reason = pj_str("Reliable response timed out");
535 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000536
Benny Prijono1f7767b2007-10-03 18:28:49 +0000537 /* Clear all pending responses */
538 clear_all_responses(dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000539
Benny Prijono1f7767b2007-10-03 18:28:49 +0000540 /* Send 500 response */
541 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata);
542 if (status == PJ_SUCCESS) {
543 pjsip_dlg_send_response(dd->inv->dlg,
544 dd->inv->invite_tsx,
545 tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000546 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000547 return;
548 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000549
Benny Prijono1f7767b2007-10-03 18:28:49 +0000550 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list));
551 tl = dd->uas_state->tx_data_list.next;
552 tdata = tl->tdata;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000553
Benny Prijono1f7767b2007-10-03 18:28:49 +0000554 pjsip_tx_data_add_ref(tdata);
555 final = tdata->msg->line.status.code >= 200;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000556
Benny Prijono1f7767b2007-10-03 18:28:49 +0000557 if (dd->uas_state->retransmit_count == 1) {
558 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata);
559 } else {
560 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata);
561 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000562
Benny Prijono1f7767b2007-10-03 18:28:49 +0000563 if (final) {
564 /* This is final response, which will be retransmitted by
565 * UA layer. There's no more task to do, so clear the
566 * transmission list and bail out.
567 */
568 clear_all_responses(dd);
569 return;
570 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000571
Benny Prijono1f7767b2007-10-03 18:28:49 +0000572 /* Schedule next retransmission */
573 if (dd->uas_state->retransmit_count < 6) {
574 delay.sec = 0;
575 delay.msec = (1 << dd->uas_state->retransmit_count) *
Benny Prijono4768c3c2008-02-22 11:10:17 +0000576 pjsip_cfg()->tsx.t1;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000577 pj_time_val_normalize(&delay);
578 } else {
579 delay.sec = 1;
580 delay.msec = 500;
581 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000582
583
Benny Prijono1f7767b2007-10-03 18:28:49 +0000584 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,
585 &dd->uas_state->retransmit_timer,
586 &delay);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000587
Benny Prijono1f7767b2007-10-03 18:28:49 +0000588 entry->id = PJ_TRUE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000589}
590
Benny Prijono1f7767b2007-10-03 18:28:49 +0000591
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000592/* Clone response. */
593static pjsip_tx_data *clone_tdata(dlg_data *dd,
594 const pjsip_tx_data *src)
595{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000596 pjsip_tx_data *dst;
597 const pjsip_hdr *hsrc;
598 pjsip_msg *msg;
599 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000600
Benny Prijono1f7767b2007-10-03 18:28:49 +0000601 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst);
602 if (status != PJ_SUCCESS)
603 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000604
Benny Prijono1f7767b2007-10-03 18:28:49 +0000605 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG);
606 dst->msg = msg;
607 pjsip_tx_data_add_ref(dst);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000608
Benny Prijono1f7767b2007-10-03 18:28:49 +0000609 /* Duplicate status line */
610 msg->line.status.code = src->msg->line.status.code;
611 pj_strdup(dst->pool, &msg->line.status.reason,
612 &src->msg->line.status.reason);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000613
Benny Prijono1f7767b2007-10-03 18:28:49 +0000614 /* Duplicate all headers */
615 hsrc = src->msg->hdr.next;
616 while (hsrc != &src->msg->hdr) {
617 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc);
618 pjsip_msg_add_hdr(msg, h);
619 hsrc = hsrc->next;
620 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000621
Benny Prijono1f7767b2007-10-03 18:28:49 +0000622 /* Duplicate message body */
623 if (src->msg->body)
624 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000625
Benny Prijono1f7767b2007-10-03 18:28:49 +0000626 PJ_LOG(5,(dd->inv->dlg->obj_name,
627 "Reliable response %s created",
628 pjsip_tx_data_get_info(dst)));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000629
Benny Prijono1f7767b2007-10-03 18:28:49 +0000630 return dst;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000631}
632
Benny Prijono1f7767b2007-10-03 18:28:49 +0000633
634/* Check if any pending response in transmission list has SDP */
Benny Prijono79d79882007-10-01 12:22:52 +0000635static pj_bool_t has_sdp(dlg_data *dd)
636{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000637 tx_data_list_t *tl;
Benny Prijono79d79882007-10-01 12:22:52 +0000638
Benny Prijono1f7767b2007-10-03 18:28:49 +0000639 tl = dd->uas_state->tx_data_list.next;
640 while (tl != &dd->uas_state->tx_data_list) {
641 if (tl->tdata->msg->body)
642 return PJ_TRUE;
643 tl = tl->next;
644 }
Benny Prijono79d79882007-10-01 12:22:52 +0000645
Benny Prijono1f7767b2007-10-03 18:28:49 +0000646 return PJ_FALSE;
Benny Prijono79d79882007-10-01 12:22:52 +0000647}
648
649
650/* Send response reliably */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000651PJ_DEF(pj_status_t) pjsip_100rel_tx_response(pjsip_inv_session *inv,
652 pjsip_tx_data *tdata)
653{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000654 pjsip_cseq_hdr *cseq_hdr;
655 pjsip_generic_string_hdr *rseq_hdr;
656 pjsip_require_hdr *req_hdr;
657 int status_code;
658 dlg_data *dd;
659 pjsip_tx_data *old_tdata;
660 pj_status_t status;
661
662 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
663 PJSIP_ENOTRESPONSEMSG);
664
665 status_code = tdata->msg->line.status.code;
666
667 /* 100 response doesn't need PRACK */
668 if (status_code == 100)
669 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
670
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000671
Benny Prijono1f7767b2007-10-03 18:28:49 +0000672 /* Get the 100rel data attached to this dialog */
673 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
674 PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP);
675
676
677 /* Clone tdata.
678 * We need to clone tdata because we may need to keep it in our
679 * retransmission list, while the original dialog may modify it
680 * if it wants to send another response.
681 */
682 old_tdata = tdata;
683 tdata = clone_tdata(dd, old_tdata);
684 pjsip_tx_data_dec_ref(old_tdata);
685
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000686
Benny Prijono1f7767b2007-10-03 18:28:49 +0000687 /* Get CSeq header, and make sure this is INVITE response */
688 cseq_hdr = (pjsip_cseq_hdr*)
689 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
690 PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG);
691 PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD,
692 PJ_EINVALIDOP);
693
694 /* Remove existing Require header */
695 req_hdr = find_req_hdr(tdata->msg);
696 if (req_hdr) {
697 pj_list_erase(req_hdr);
698 }
699
700 /* Remove existing RSeq header */
701 rseq_hdr = (pjsip_generic_string_hdr*)
702 pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL);
703 if (rseq_hdr)
704 pj_list_erase(rseq_hdr);
705
706 /* Different treatment for provisional and final response */
707 if (status_code/100 == 2) {
708
709 /* RFC 3262 Section 3: UAS Behavior:
710
711 The UAS MAY send a final response to the initial request
712 before having received PRACKs for all unacknowledged
713 reliable provisional responses, unless the final response
714 is 2xx and any of the unacknowledged reliable provisional
715 responses contained a session description. In that case,
716 it MUST NOT send a final response until those provisional
717 responses are acknowledged.
718 */
719
720 if (dd->uas_state && has_sdp(dd)) {
721 /* Yes we have transmitted 1xx with SDP reliably.
722 * In this case, must queue the 2xx response.
723 */
724 tx_data_list_t *tl;
725
726 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
727 tl->tdata = tdata;
728 tl->rseq = (pj_uint32_t)-1;
729 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
730
731 /* Will send later */
732 status = PJ_SUCCESS;
733
734 PJ_LOG(4,(dd->inv->dlg->obj_name,
735 "2xx response will be sent after PRACK"));
736
737 } else if (dd->uas_state) {
738 /*
739 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000740
Benny Prijono1f7767b2007-10-03 18:28:49 +0000741 If the UAS does send a final response when reliable
742 responses are still unacknowledged, it SHOULD NOT
743 continue to retransmit the unacknowledged reliable
744 provisional responses, but it MUST be prepared to
745 process PRACK requests for those outstanding
746 responses.
747 */
748
749 PJ_LOG(4,(dd->inv->dlg->obj_name,
750 "No SDP sent so far, sending 2xx now"));
751
752 /* Cancel the retransmit timer */
753 if (dd->uas_state->retransmit_timer.id) {
754 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
755 &dd->uas_state->retransmit_timer);
756 dd->uas_state->retransmit_timer.id = PJ_FALSE;
757 }
758
759 /* Clear all pending responses (drop 'em) */
760 clear_all_responses(dd);
761
762 /* And transmit the 2xx response */
763 status=pjsip_dlg_send_response(inv->dlg,
764 inv->invite_tsx, tdata);
765
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000766 } else {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000767 /* We didn't send any reliable provisional response */
768
769 /* Transmit the 2xx response */
770 status=pjsip_dlg_send_response(inv->dlg,
771 inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000772 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000773
774 } else if (status_code >= 300) {
775
776 /*
777 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000778
Benny Prijono1f7767b2007-10-03 18:28:49 +0000779 If the UAS does send a final response when reliable
780 responses are still unacknowledged, it SHOULD NOT
781 continue to retransmit the unacknowledged reliable
782 provisional responses, but it MUST be prepared to
783 process PRACK requests for those outstanding
784 responses.
785 */
786
787 /* Cancel the retransmit timer */
788 if (dd->uas_state && dd->uas_state->retransmit_timer.id) {
789 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
790 &dd->uas_state->retransmit_timer);
791 dd->uas_state->retransmit_timer.id = PJ_FALSE;
792
793 /* Clear all pending responses (drop 'em) */
794 clear_all_responses(dd);
795 }
796
797 /* And transmit the 2xx response */
798 status=pjsip_dlg_send_response(inv->dlg,
799 inv->invite_tsx, tdata);
800
801 } else {
802 /*
803 * This is provisional response.
804 */
805 char rseq_str[32];
806 pj_str_t rseq;
807 tx_data_list_t *tl;
808
809 /* Create UAS state if we don't have one */
810 if (dd->uas_state == NULL) {
811 dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool,
812 uas_state_t);
813 dd->uas_state->cseq = cseq_hdr->cseq;
814 dd->uas_state->rseq = pj_rand() % 0x7FFF;
815 pj_list_init(&dd->uas_state->tx_data_list);
816 dd->uas_state->retransmit_timer.user_data = dd;
817 dd->uas_state->retransmit_timer.cb = &on_retransmit;
818 }
819
820 /* Check that CSeq match */
821 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq,
822 PJ_EINVALIDOP);
823
824 /* Add Require header */
825 req_hdr = pjsip_require_hdr_create(tdata->pool);
826 req_hdr->count = 1;
827 req_hdr->values[0] = tag_100rel;
828 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
829
830 /* Add RSeq header */
831 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u",
832 dd->uas_state->rseq);
833 rseq = pj_str(rseq_str);
834 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool,
835 &RSEQ, &rseq);
836 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr);
837
838 /* Create list entry for this response */
839 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
840 tl->tdata = tdata;
841 tl->rseq = dd->uas_state->rseq++;
842
843 /* Add to queue if there's pending response, otherwise
844 * transmit immediately.
845 */
846 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
847
848 int code = tdata->msg->line.status.code;
849
850 /* Will send later */
851 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
852 status = PJ_SUCCESS;
853
854 PJ_LOG(4,(dd->inv->dlg->obj_name,
855 "Reliable %d response enqueued (%d pending)",
856 code, pj_list_size(&dd->uas_state->tx_data_list)));
857
858 } else {
859 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
860
861 dd->uas_state->retransmit_count = 0;
862 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
863 status = PJ_SUCCESS;
864 }
865
866 }
867
868 return status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000869}
870
871