blob: 60b989b210081a9a62466f1a9e53264841660718 [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{
Sauw Minge7dbbc82011-10-24 09:28:13 +0000108 pj_str_t tag; /* To tag */
109 pj_int32_t cseq;
110 pj_uint32_t rseq; /* Initialized to -1 */
111 struct uac_state_t *next; /* next call leg */
Benny Prijono373633c2007-09-30 18:06:41 +0000112} uac_state_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000113
114
115/* State attached to each dialog. */
116struct dlg_data
117{
118 pjsip_inv_session *inv;
Benny Prijono373633c2007-09-30 18:06:41 +0000119 uas_state_t *uas_state;
Sauw Minge7dbbc82011-10-24 09:28:13 +0000120 uac_state_t *uac_state_list;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000121};
122
123
124/*****************************************************************************
125 **
126 ** Module
127 **
128 *****************************************************************************
129 */
130static pj_status_t mod_100rel_load(pjsip_endpoint *endpt)
131{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000132 mod_100rel.endpt = endpt;
133 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
134 PJSIP_H_ALLOW, NULL,
135 1, &pjsip_prack_method.name);
136 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
137 PJSIP_H_SUPPORTED, NULL,
138 1, &tag_100rel);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000139
Benny Prijono1f7767b2007-10-03 18:28:49 +0000140 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000141}
142
143static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg)
144{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000145 pjsip_require_hdr *hreq;
146
147 hreq = (pjsip_require_hdr*)
148 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
149
150 while (hreq) {
151 unsigned i;
152 for (i=0; i<hreq->count; ++i) {
153 if (!pj_stricmp(&hreq->values[i], &tag_100rel)) {
154 return hreq;
155 }
156 }
157
158 if ((void*)hreq->next == (void*)&msg->hdr)
159 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000160
161 hreq = (pjsip_require_hdr*)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000162 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000163
Benny Prijono1f7767b2007-10-03 18:28:49 +0000164 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000165
Benny Prijono1f7767b2007-10-03 18:28:49 +0000166 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000167}
168
169
170/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000171 * Get PRACK method constant.
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000172 */
Benny Prijono1f7767b2007-10-03 18:28:49 +0000173PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000174{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000175 return &pjsip_prack_method;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000176}
177
178
179/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000180 * init module
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000181 */
182PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt)
183{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000184 if (mod_100rel.mod.id != -1)
185 return PJ_SUCCESS;
186
187 return pjsip_endpt_register_module(endpt, &mod_100rel.mod);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000188}
189
190
191/*
192 * API: attach 100rel support in invite session. Called by
193 * sip_inv.c
194 */
195PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv)
196{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000197 dlg_data *dd;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000198
Benny Prijono1f7767b2007-10-03 18:28:49 +0000199 /* Check that 100rel module has been initialized */
200 PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000201
Benny Prijono1f7767b2007-10-03 18:28:49 +0000202 /* Create and attach as dialog usage */
203 dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data);
204 dd->inv = inv;
205 pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000206
Benny Prijono1f7767b2007-10-03 18:28:49 +0000207 PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached"));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000208
Benny Prijono1f7767b2007-10-03 18:28:49 +0000209 return PJ_SUCCESS;
210}
211
212
213/*
214 * Check if incoming response has reliable provisional response feature.
215 */
216PJ_DEF(pj_bool_t) pjsip_100rel_is_reliable(pjsip_rx_data *rdata)
217{
218 pjsip_msg *msg = rdata->msg_info.msg;
219
220 PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG, PJ_FALSE);
221
222 return msg->line.status.code > 100 && msg->line.status.code < 200 &&
223 rdata->msg_info.require != NULL &&
224 find_req_hdr(msg) != NULL;
225}
226
227
228/*
229 * Create PRACK request for the incoming reliable provisional response.
230 */
231PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
232 pjsip_rx_data *rdata,
233 pjsip_tx_data **p_tdata)
234{
235 dlg_data *dd;
Sauw Minge7dbbc82011-10-24 09:28:13 +0000236 uac_state_t *uac_state = NULL;
237 const pj_str_t *to_tag = &rdata->msg_info.to->tag;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000238 pjsip_transaction *tsx;
239 pjsip_msg *msg;
240 pjsip_generic_string_hdr *rseq_hdr;
241 pjsip_generic_string_hdr *rack_hdr;
242 unsigned rseq;
243 pj_str_t rack;
244 char rack_buf[80];
245 pjsip_tx_data *tdata;
246 pj_status_t status;
247
248 *p_tdata = NULL;
249
250 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
251 PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED);
252
253 tsx = pjsip_rdata_get_tsx(rdata);
254 msg = rdata->msg_info.msg;
255
256 /* Check our assumptions */
257 pj_assert( tsx->role == PJSIP_ROLE_UAC &&
258 tsx->method.id == PJSIP_INVITE_METHOD &&
259 msg->line.status.code > 100 &&
260 msg->line.status.code < 200);
261
262
263 /* Get the RSeq header */
264 rseq_hdr = (pjsip_generic_string_hdr*)
265 pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL);
266 if (rseq_hdr == NULL) {
267 PJ_LOG(4,(dd->inv->dlg->obj_name,
Sauw Minge7dbbc82011-10-24 09:28:13 +0000268 "Ignoring 100rel response with no RSeq header"));
Benny Prijono1f7767b2007-10-03 18:28:49 +0000269 return PJSIP_EMISSINGHDR;
270 }
271 rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);
272
Sauw Minge7dbbc82011-10-24 09:28:13 +0000273 /* Find UAC state for the specified call leg */
274 uac_state = dd->uac_state_list;
275 while (uac_state) {
Sauw Ming969227c2012-07-18 07:52:33 +0000276 if (pj_stricmp(&uac_state->tag, to_tag)==0)
Sauw Minge7dbbc82011-10-24 09:28:13 +0000277 break;
278 uac_state = uac_state->next;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000279 }
280
Sauw Minge7dbbc82011-10-24 09:28:13 +0000281 /* Create new UAC state if we don't have one */
282 if (uac_state == NULL) {
283 uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, uac_state_t);
284 uac_state->cseq = rdata->msg_info.cseq->cseq;
285 uac_state->rseq = rseq - 1;
286 pj_strdup(dd->inv->dlg->pool, &uac_state->tag, to_tag);
287 uac_state->next = dd->uac_state_list;
288 dd->uac_state_list = uac_state;
289 }
290
291 /* If this is from new INVITE transaction, reset UAC state. */
292 if (rdata->msg_info.cseq->cseq != uac_state->cseq) {
293 uac_state->cseq = rdata->msg_info.cseq->cseq;
294 uac_state->rseq = rseq - 1;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000295 }
296
297 /* Ignore provisional response retransmission */
Sauw Minge7dbbc82011-10-24 09:28:13 +0000298 if (rseq <= uac_state->rseq) {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000299 /* This should have been handled before */
300 return PJ_EIGNORED;
301
302 /* Ignore provisional response with out-of-order RSeq */
Sauw Minge7dbbc82011-10-24 09:28:13 +0000303 } else if (rseq != uac_state->rseq + 1) {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000304 PJ_LOG(4,(dd->inv->dlg->obj_name,
Sauw Minge7dbbc82011-10-24 09:28:13 +0000305 "Ignoring 100rel response because RSeq jump "
Benny Prijono1f7767b2007-10-03 18:28:49 +0000306 "(expecting %u, got %u)",
Sauw Minge7dbbc82011-10-24 09:28:13 +0000307 uac_state->rseq+1, rseq));
Benny Prijono1f7767b2007-10-03 18:28:49 +0000308 return PJ_EIGNORED;
309 }
310
311 /* Update our RSeq */
Sauw Minge7dbbc82011-10-24 09:28:13 +0000312 uac_state->rseq = rseq;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000313
314 /* Create PRACK */
315 status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method,
316 -1, &tdata);
317 if (status != PJ_SUCCESS)
318 return status;
319
Sauw Minge7dbbc82011-10-24 09:28:13 +0000320 /* If this response is a forked response from a different call-leg,
321 * update the req URI (https://trac.pjsip.org/repos/ticket/1364)
322 */
Sauw Ming969227c2012-07-18 07:52:33 +0000323 if (pj_stricmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) {
Sauw Minge7dbbc82011-10-24 09:28:13 +0000324 const pjsip_contact_hdr *mhdr;
325
326 mhdr = (const pjsip_contact_hdr*)
327 pjsip_msg_find_hdr(rdata->msg_info.msg,
328 PJSIP_H_CONTACT, NULL);
329 if (!mhdr || !mhdr->uri) {
330 PJ_LOG(4,(dd->inv->dlg->obj_name,
331 "Ignoring 100rel response with no or "
332 "invalid Contact header"));
333 pjsip_tx_data_dec_ref(tdata);
334 return PJ_EIGNORED;
335 }
336 tdata->msg->line.req.uri = (pjsip_uri*)
337 pjsip_uri_clone(tdata->pool, mhdr->uri);
338 }
339
Benny Prijono1f7767b2007-10-03 18:28:49 +0000340 /* Create RAck header */
341 rack.ptr = rack_buf;
342 rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf),
343 "%u %u %.*s",
344 rseq, rdata->msg_info.cseq->cseq,
345 (int)tsx->method.name.slen,
346 tsx->method.name.ptr);
347 rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack);
348 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr);
349
350 /* Done */
351 *p_tdata = tdata;
352
353 return PJ_SUCCESS;
354}
355
356
357/*
358 * Send PRACK request.
359 */
360PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv,
361 pjsip_tx_data *tdata)
362{
363 dlg_data *dd;
364
365 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
366 PJ_ASSERT_ON_FAIL(dd != NULL,
367 {pjsip_tx_data_dec_ref(tdata); return PJSIP_ENOTINITIALIZED; });
368
369 return pjsip_dlg_send_request(inv->dlg, tdata,
370 mod_100rel.mod.id, (void*) dd);
371
372}
373
374
375/*
376 * Notify 100rel module that the invite session has been disconnected.
377 */
378PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv)
379{
380 dlg_data *dd;
381
382 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
383 if (!dd)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000384 return PJ_SUCCESS;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000385
386 /* Make sure we don't have pending transmission */
387 if (dd->uas_state) {
388 pj_assert(!dd->uas_state->retransmit_timer.id);
389 pj_assert(pj_list_empty(&dd->uas_state->tx_data_list));
390 }
391
392 return PJ_SUCCESS;
393}
394
395
396static void parse_rack(const pj_str_t *rack,
397 pj_uint32_t *p_rseq, pj_int32_t *p_seq,
398 pj_str_t *p_method)
399{
400 const char *p = rack->ptr, *end = p + rack->slen;
401 pj_str_t token;
402
403 token.ptr = (char*)p;
404 while (p < end && pj_isdigit(*p))
405 ++p;
406 token.slen = p - token.ptr;
407 *p_rseq = pj_strtoul(&token);
408
409 ++p;
410 token.ptr = (char*)p;
411 while (p < end && pj_isdigit(*p))
412 ++p;
413 token.slen = p - token.ptr;
414 *p_seq = pj_strtoul(&token);
415
416 ++p;
417 if (p < end) {
418 p_method->ptr = (char*)p;
419 p_method->slen = end - p;
420 } else {
421 p_method->ptr = NULL;
422 p_method->slen = 0;
423 }
424}
425
426/* Clear all responses in the transmission list */
427static void clear_all_responses(dlg_data *dd)
428{
429 tx_data_list_t *tl;
430
431 tl = dd->uas_state->tx_data_list.next;
432 while (tl != &dd->uas_state->tx_data_list) {
433 pjsip_tx_data_dec_ref(tl->tdata);
434 tl = tl->next;
435 }
436 pj_list_init(&dd->uas_state->tx_data_list);
437}
438
439
440/*
441 * Handle incoming PRACK request.
442 */
443PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv,
444 pjsip_rx_data *rdata)
445{
446 dlg_data *dd;
447 pjsip_transaction *tsx;
448 pjsip_msg *msg;
449 pjsip_generic_string_hdr *rack_hdr;
450 pjsip_tx_data *tdata;
451 pj_uint32_t rseq;
452 pj_int32_t cseq;
453 pj_str_t method;
454 pj_status_t status;
455
Benny Prijono1f7767b2007-10-03 18:28:49 +0000456 tsx = pjsip_rdata_get_tsx(rdata);
457 pj_assert(tsx != NULL);
458
459 msg = rdata->msg_info.msg;
460
Benny Prijono2d2cc942008-09-11 08:00:47 +0000461 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
462 if (dd == NULL) {
463 /* UAC sends us PRACK while we didn't send reliable provisional
464 * response. Respond with 400 (?)
465 */
466 const pj_str_t reason = pj_str("Unexpected PRACK");
467
468 status = pjsip_dlg_create_response(inv->dlg, rdata, 400,
469 &reason, &tdata);
470 if (status == PJ_SUCCESS) {
471 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
472 }
473 return PJSIP_ENOTINITIALIZED;
474 }
475
Benny Prijono1f7767b2007-10-03 18:28:49 +0000476 /* Always reply with 200/OK for PRACK */
477 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
478 if (status == PJ_SUCCESS) {
479 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
480 }
481
482 /* Ignore if we don't have pending transmission */
483 if (dd->uas_state == NULL || pj_list_empty(&dd->uas_state->tx_data_list)) {
484 PJ_LOG(4,(dd->inv->dlg->obj_name,
485 "PRACK ignored - no pending response"));
486 return PJ_EIGNORED;
487 }
488
489 /* Find RAck header */
490 rack_hdr = (pjsip_generic_string_hdr*)
491 pjsip_msg_find_hdr_by_name(msg, &RACK, NULL);
492 if (!rack_hdr) {
493 /* RAck header not found */
494 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header"));
495 return PJSIP_EMISSINGHDR;
496 }
497
498 /* Parse RAck header */
499 parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method);
500
501
502 /* Match RAck against outgoing transmission */
503 if (rseq == dd->uas_state->tx_data_list.next->rseq &&
504 cseq == dd->uas_state->cseq)
505 {
506 /*
507 * Yes this PRACK matches outgoing transmission.
508 */
509 tx_data_list_t *tl = dd->uas_state->tx_data_list.next;
510
511 if (dd->uas_state->retransmit_timer.id) {
512 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
513 &dd->uas_state->retransmit_timer);
514 dd->uas_state->retransmit_timer.id = PJ_FALSE;
515 }
516
517 /* Remove from the list */
518 if (tl != &dd->uas_state->tx_data_list) {
519 pj_list_erase(tl);
520
521 /* Destroy the response */
522 pjsip_tx_data_dec_ref(tl->tdata);
523 }
524
525 /* Schedule next packet */
526 dd->uas_state->retransmit_count = 0;
527 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
528 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
529 }
530
531 } else {
532 /* No it doesn't match */
533 PJ_LOG(4,(dd->inv->dlg->obj_name,
534 "Rx PRACK with no matching reliable response"));
535 return PJ_EIGNORED;
536 }
537
538 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000539}
540
541
542/*
543 * This is retransmit timer callback, called initially to send the response,
544 * and subsequently when the retransmission time elapses.
545 */
546static void on_retransmit(pj_timer_heap_t *timer_heap,
547 struct pj_timer_entry *entry)
548{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000549 dlg_data *dd;
550 tx_data_list_t *tl;
551 pjsip_tx_data *tdata;
552 pj_bool_t final;
553 pj_time_val delay;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000554
Benny Prijono1f7767b2007-10-03 18:28:49 +0000555 PJ_UNUSED_ARG(timer_heap);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000556
Benny Prijono1f7767b2007-10-03 18:28:49 +0000557 dd = (dlg_data*) entry->user_data;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000558
Benny Prijono1f7767b2007-10-03 18:28:49 +0000559 entry->id = PJ_FALSE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000560
Benny Prijono1f7767b2007-10-03 18:28:49 +0000561 ++dd->uas_state->retransmit_count;
562 if (dd->uas_state->retransmit_count >= 7) {
563 /* If a reliable provisional response is retransmitted for
564 64*T1 seconds without reception of a corresponding PRACK,
565 the UAS SHOULD reject the original request with a 5xx
566 response.
567 */
568 pj_str_t reason = pj_str("Reliable response timed out");
569 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000570
Benny Prijono1f7767b2007-10-03 18:28:49 +0000571 /* Clear all pending responses */
572 clear_all_responses(dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000573
Benny Prijono1f7767b2007-10-03 18:28:49 +0000574 /* Send 500 response */
575 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata);
576 if (status == PJ_SUCCESS) {
577 pjsip_dlg_send_response(dd->inv->dlg,
578 dd->inv->invite_tsx,
579 tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000580 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000581 return;
582 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000583
Benny Prijono1f7767b2007-10-03 18:28:49 +0000584 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list));
585 tl = dd->uas_state->tx_data_list.next;
586 tdata = tl->tdata;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000587
Benny Prijono1f7767b2007-10-03 18:28:49 +0000588 pjsip_tx_data_add_ref(tdata);
589 final = tdata->msg->line.status.code >= 200;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000590
Benny Prijono1f7767b2007-10-03 18:28:49 +0000591 if (dd->uas_state->retransmit_count == 1) {
592 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata);
593 } else {
594 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata);
595 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000596
Benny Prijono1f7767b2007-10-03 18:28:49 +0000597 if (final) {
598 /* This is final response, which will be retransmitted by
599 * UA layer. There's no more task to do, so clear the
600 * transmission list and bail out.
601 */
602 clear_all_responses(dd);
603 return;
604 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000605
Benny Prijono1f7767b2007-10-03 18:28:49 +0000606 /* Schedule next retransmission */
607 if (dd->uas_state->retransmit_count < 6) {
608 delay.sec = 0;
609 delay.msec = (1 << dd->uas_state->retransmit_count) *
Benny Prijono4768c3c2008-02-22 11:10:17 +0000610 pjsip_cfg()->tsx.t1;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000611 pj_time_val_normalize(&delay);
612 } else {
613 delay.sec = 1;
614 delay.msec = 500;
615 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000616
617
Benny Prijono1f7767b2007-10-03 18:28:49 +0000618 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,
619 &dd->uas_state->retransmit_timer,
620 &delay);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000621
Benny Prijono1f7767b2007-10-03 18:28:49 +0000622 entry->id = PJ_TRUE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000623}
624
Benny Prijono1f7767b2007-10-03 18:28:49 +0000625
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000626/* Clone response. */
627static pjsip_tx_data *clone_tdata(dlg_data *dd,
628 const pjsip_tx_data *src)
629{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000630 pjsip_tx_data *dst;
631 const pjsip_hdr *hsrc;
632 pjsip_msg *msg;
633 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000634
Benny Prijono1f7767b2007-10-03 18:28:49 +0000635 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst);
636 if (status != PJ_SUCCESS)
637 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000638
Benny Prijono1f7767b2007-10-03 18:28:49 +0000639 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG);
640 dst->msg = msg;
641 pjsip_tx_data_add_ref(dst);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000642
Benny Prijono1f7767b2007-10-03 18:28:49 +0000643 /* Duplicate status line */
644 msg->line.status.code = src->msg->line.status.code;
645 pj_strdup(dst->pool, &msg->line.status.reason,
646 &src->msg->line.status.reason);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000647
Benny Prijono1f7767b2007-10-03 18:28:49 +0000648 /* Duplicate all headers */
649 hsrc = src->msg->hdr.next;
650 while (hsrc != &src->msg->hdr) {
651 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc);
652 pjsip_msg_add_hdr(msg, h);
653 hsrc = hsrc->next;
654 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000655
Benny Prijono1f7767b2007-10-03 18:28:49 +0000656 /* Duplicate message body */
657 if (src->msg->body)
658 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000659
Benny Prijono1f7767b2007-10-03 18:28:49 +0000660 PJ_LOG(5,(dd->inv->dlg->obj_name,
661 "Reliable response %s created",
662 pjsip_tx_data_get_info(dst)));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000663
Benny Prijono1f7767b2007-10-03 18:28:49 +0000664 return dst;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000665}
666
Benny Prijono1f7767b2007-10-03 18:28:49 +0000667
668/* Check if any pending response in transmission list has SDP */
Benny Prijono79d79882007-10-01 12:22:52 +0000669static pj_bool_t has_sdp(dlg_data *dd)
670{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000671 tx_data_list_t *tl;
Benny Prijono79d79882007-10-01 12:22:52 +0000672
Benny Prijono1f7767b2007-10-03 18:28:49 +0000673 tl = dd->uas_state->tx_data_list.next;
674 while (tl != &dd->uas_state->tx_data_list) {
675 if (tl->tdata->msg->body)
676 return PJ_TRUE;
677 tl = tl->next;
678 }
Benny Prijono79d79882007-10-01 12:22:52 +0000679
Benny Prijono1f7767b2007-10-03 18:28:49 +0000680 return PJ_FALSE;
Benny Prijono79d79882007-10-01 12:22:52 +0000681}
682
683
684/* Send response reliably */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000685PJ_DEF(pj_status_t) pjsip_100rel_tx_response(pjsip_inv_session *inv,
686 pjsip_tx_data *tdata)
687{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000688 pjsip_cseq_hdr *cseq_hdr;
689 pjsip_generic_string_hdr *rseq_hdr;
690 pjsip_require_hdr *req_hdr;
691 int status_code;
692 dlg_data *dd;
693 pjsip_tx_data *old_tdata;
694 pj_status_t status;
695
696 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
697 PJSIP_ENOTRESPONSEMSG);
698
699 status_code = tdata->msg->line.status.code;
700
701 /* 100 response doesn't need PRACK */
702 if (status_code == 100)
703 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
704
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000705
Benny Prijono1f7767b2007-10-03 18:28:49 +0000706 /* Get the 100rel data attached to this dialog */
707 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
708 PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP);
709
710
711 /* Clone tdata.
712 * We need to clone tdata because we may need to keep it in our
713 * retransmission list, while the original dialog may modify it
714 * if it wants to send another response.
715 */
716 old_tdata = tdata;
717 tdata = clone_tdata(dd, old_tdata);
718 pjsip_tx_data_dec_ref(old_tdata);
719
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000720
Benny Prijono1f7767b2007-10-03 18:28:49 +0000721 /* Get CSeq header, and make sure this is INVITE response */
722 cseq_hdr = (pjsip_cseq_hdr*)
723 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
724 PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG);
725 PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD,
726 PJ_EINVALIDOP);
727
728 /* Remove existing Require header */
729 req_hdr = find_req_hdr(tdata->msg);
730 if (req_hdr) {
731 pj_list_erase(req_hdr);
732 }
733
734 /* Remove existing RSeq header */
735 rseq_hdr = (pjsip_generic_string_hdr*)
736 pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL);
737 if (rseq_hdr)
738 pj_list_erase(rseq_hdr);
739
740 /* Different treatment for provisional and final response */
741 if (status_code/100 == 2) {
742
743 /* RFC 3262 Section 3: UAS Behavior:
744
745 The UAS MAY send a final response to the initial request
746 before having received PRACKs for all unacknowledged
747 reliable provisional responses, unless the final response
748 is 2xx and any of the unacknowledged reliable provisional
749 responses contained a session description. In that case,
750 it MUST NOT send a final response until those provisional
751 responses are acknowledged.
752 */
753
754 if (dd->uas_state && has_sdp(dd)) {
755 /* Yes we have transmitted 1xx with SDP reliably.
756 * In this case, must queue the 2xx response.
757 */
758 tx_data_list_t *tl;
759
760 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
761 tl->tdata = tdata;
762 tl->rseq = (pj_uint32_t)-1;
763 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
764
765 /* Will send later */
766 status = PJ_SUCCESS;
767
768 PJ_LOG(4,(dd->inv->dlg->obj_name,
769 "2xx response will be sent after PRACK"));
770
771 } else if (dd->uas_state) {
772 /*
773 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000774
Benny Prijono1f7767b2007-10-03 18:28:49 +0000775 If the UAS does send a final response when reliable
776 responses are still unacknowledged, it SHOULD NOT
777 continue to retransmit the unacknowledged reliable
778 provisional responses, but it MUST be prepared to
779 process PRACK requests for those outstanding
780 responses.
781 */
782
783 PJ_LOG(4,(dd->inv->dlg->obj_name,
784 "No SDP sent so far, sending 2xx now"));
785
786 /* Cancel the retransmit timer */
787 if (dd->uas_state->retransmit_timer.id) {
788 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
789 &dd->uas_state->retransmit_timer);
790 dd->uas_state->retransmit_timer.id = PJ_FALSE;
791 }
792
793 /* Clear all pending responses (drop 'em) */
794 clear_all_responses(dd);
795
796 /* And transmit the 2xx response */
797 status=pjsip_dlg_send_response(inv->dlg,
798 inv->invite_tsx, tdata);
799
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000800 } else {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000801 /* We didn't send any reliable provisional response */
802
803 /* Transmit the 2xx response */
804 status=pjsip_dlg_send_response(inv->dlg,
805 inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000806 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000807
808 } else if (status_code >= 300) {
809
810 /*
811 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000812
Benny Prijono1f7767b2007-10-03 18:28:49 +0000813 If the UAS does send a final response when reliable
814 responses are still unacknowledged, it SHOULD NOT
815 continue to retransmit the unacknowledged reliable
816 provisional responses, but it MUST be prepared to
817 process PRACK requests for those outstanding
818 responses.
819 */
820
821 /* Cancel the retransmit timer */
822 if (dd->uas_state && dd->uas_state->retransmit_timer.id) {
823 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
824 &dd->uas_state->retransmit_timer);
825 dd->uas_state->retransmit_timer.id = PJ_FALSE;
826
827 /* Clear all pending responses (drop 'em) */
828 clear_all_responses(dd);
829 }
830
831 /* And transmit the 2xx response */
832 status=pjsip_dlg_send_response(inv->dlg,
833 inv->invite_tsx, tdata);
834
835 } else {
836 /*
837 * This is provisional response.
838 */
839 char rseq_str[32];
840 pj_str_t rseq;
841 tx_data_list_t *tl;
842
843 /* Create UAS state if we don't have one */
844 if (dd->uas_state == NULL) {
845 dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool,
846 uas_state_t);
847 dd->uas_state->cseq = cseq_hdr->cseq;
848 dd->uas_state->rseq = pj_rand() % 0x7FFF;
849 pj_list_init(&dd->uas_state->tx_data_list);
850 dd->uas_state->retransmit_timer.user_data = dd;
851 dd->uas_state->retransmit_timer.cb = &on_retransmit;
852 }
853
854 /* Check that CSeq match */
855 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq,
856 PJ_EINVALIDOP);
857
858 /* Add Require header */
859 req_hdr = pjsip_require_hdr_create(tdata->pool);
860 req_hdr->count = 1;
861 req_hdr->values[0] = tag_100rel;
862 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
863
864 /* Add RSeq header */
865 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u",
866 dd->uas_state->rseq);
867 rseq = pj_str(rseq_str);
868 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool,
869 &RSEQ, &rseq);
870 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr);
871
872 /* Create list entry for this response */
873 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
874 tl->tdata = tdata;
875 tl->rseq = dd->uas_state->rseq++;
876
877 /* Add to queue if there's pending response, otherwise
878 * transmit immediately.
879 */
880 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
881
882 int code = tdata->msg->line.status.code;
883
884 /* Will send later */
885 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
886 status = PJ_SUCCESS;
887
888 PJ_LOG(4,(dd->inv->dlg->obj_name,
889 "Reliable %d response enqueued (%d pending)",
890 code, pj_list_size(&dd->uas_state->tx_data_list)));
891
892 } else {
893 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
894
895 dd->uas_state->retransmit_count = 0;
896 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
897 status = PJ_SUCCESS;
898 }
899
900 }
901
902 return status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000903}
904
905