blob: ae8a98df77a6294057960a65b00f1afbc20ab558 [file] [log] [blame]
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny 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>
31
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000032#define THIS_FILE "sip_100rel.c"
33
Benny Prijono1f7767b2007-10-03 18:28:49 +000034/* PRACK method */
35PJ_DEF_DATA(const pjsip_method) pjsip_prack_method =
36{
37 PJSIP_OTHER_METHOD,
38 { "PRACK", 5 }
39};
40
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000041typedef struct dlg_data dlg_data;
42
43/*
44 * Static prototypes.
45 */
46static pj_status_t mod_100rel_load(pjsip_endpoint *endpt);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000047
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000048static void on_retransmit(pj_timer_heap_t *timer_heap,
49 struct pj_timer_entry *entry);
50
51
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000052const pj_str_t tag_100rel = { "100rel", 6 };
53const pj_str_t RSEQ = { "RSeq", 4 };
54const pj_str_t RACK = { "RAck", 4 };
55
56
57/* 100rel module */
58static struct mod_100rel
59{
60 pjsip_module mod;
61 pjsip_endpoint *endpt;
62} mod_100rel =
63{
64 {
65 NULL, NULL, /* prev, next. */
66 { "mod-100rel", 10 }, /* Name. */
67 -1, /* Id */
68 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
69 &mod_100rel_load, /* load() */
70 NULL, /* start() */
71 NULL, /* stop() */
72 NULL, /* unload() */
73 NULL, /* on_rx_request() */
74 NULL, /* on_rx_response() */
75 NULL, /* on_tx_request. */
76 NULL, /* on_tx_response() */
Benny Prijono1f7767b2007-10-03 18:28:49 +000077 NULL, /* on_tsx_state() */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000078 }
79
80};
81
82/* List of pending transmission (may include the final response as well) */
Benny Prijono373633c2007-09-30 18:06:41 +000083typedef struct tx_data_list_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000084{
Benny Prijono373633c2007-09-30 18:06:41 +000085 PJ_DECL_LIST_MEMBER(struct tx_data_list_t);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000086 pj_uint32_t rseq;
87 pjsip_tx_data *tdata;
Benny Prijono373633c2007-09-30 18:06:41 +000088} tx_data_list_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000089
90
91/* Below, UAS and UAC roles are of the INVITE transaction */
92
93/* UAS state. */
Benny Prijono373633c2007-09-30 18:06:41 +000094typedef struct uas_state_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000095{
96 pj_int32_t cseq;
97 pj_uint32_t rseq; /* Initialized to -1 */
Benny Prijono373633c2007-09-30 18:06:41 +000098 tx_data_list_t tx_data_list;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000099 unsigned retransmit_count;
100 pj_timer_entry retransmit_timer;
Benny Prijono373633c2007-09-30 18:06:41 +0000101} uas_state_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000102
103
104/* UAC state */
Benny Prijono373633c2007-09-30 18:06:41 +0000105typedef struct uac_state_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000106{
107 pj_int32_t cseq;
108 pj_uint32_t rseq; /* Initialized to -1 */
Benny Prijono373633c2007-09-30 18:06:41 +0000109} uac_state_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000110
111
112/* State attached to each dialog. */
113struct dlg_data
114{
115 pjsip_inv_session *inv;
Benny Prijono373633c2007-09-30 18:06:41 +0000116 uas_state_t *uas_state;
117 uac_state_t *uac_state;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000118};
119
120
121/*****************************************************************************
122 **
123 ** Module
124 **
125 *****************************************************************************
126 */
127static pj_status_t mod_100rel_load(pjsip_endpoint *endpt)
128{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000129 mod_100rel.endpt = endpt;
130 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
131 PJSIP_H_ALLOW, NULL,
132 1, &pjsip_prack_method.name);
133 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
134 PJSIP_H_SUPPORTED, NULL,
135 1, &tag_100rel);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000136
Benny Prijono1f7767b2007-10-03 18:28:49 +0000137 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000138}
139
140static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg)
141{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000142 pjsip_require_hdr *hreq;
143
144 hreq = (pjsip_require_hdr*)
145 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
146
147 while (hreq) {
148 unsigned i;
149 for (i=0; i<hreq->count; ++i) {
150 if (!pj_stricmp(&hreq->values[i], &tag_100rel)) {
151 return hreq;
152 }
153 }
154
155 if ((void*)hreq->next == (void*)&msg->hdr)
156 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000157
158 hreq = (pjsip_require_hdr*)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000159 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000160
Benny Prijono1f7767b2007-10-03 18:28:49 +0000161 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000162
Benny Prijono1f7767b2007-10-03 18:28:49 +0000163 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000164}
165
166
167/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000168 * Get PRACK method constant.
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000169 */
Benny Prijono1f7767b2007-10-03 18:28:49 +0000170PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000171{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000172 return &pjsip_prack_method;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000173}
174
175
176/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000177 * init module
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000178 */
179PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt)
180{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000181 if (mod_100rel.mod.id != -1)
182 return PJ_SUCCESS;
183
184 return pjsip_endpt_register_module(endpt, &mod_100rel.mod);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000185}
186
187
188/*
189 * API: attach 100rel support in invite session. Called by
190 * sip_inv.c
191 */
192PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv)
193{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000194 dlg_data *dd;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000195
Benny Prijono1f7767b2007-10-03 18:28:49 +0000196 /* Check that 100rel module has been initialized */
197 PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000198
Benny Prijono1f7767b2007-10-03 18:28:49 +0000199 /* Create and attach as dialog usage */
200 dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data);
201 dd->inv = inv;
202 pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000203
Benny Prijono1f7767b2007-10-03 18:28:49 +0000204 PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached"));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000205
Benny Prijono1f7767b2007-10-03 18:28:49 +0000206 return PJ_SUCCESS;
207}
208
209
210/*
211 * Check if incoming response has reliable provisional response feature.
212 */
213PJ_DEF(pj_bool_t) pjsip_100rel_is_reliable(pjsip_rx_data *rdata)
214{
215 pjsip_msg *msg = rdata->msg_info.msg;
216
217 PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG, PJ_FALSE);
218
219 return msg->line.status.code > 100 && msg->line.status.code < 200 &&
220 rdata->msg_info.require != NULL &&
221 find_req_hdr(msg) != NULL;
222}
223
224
225/*
226 * Create PRACK request for the incoming reliable provisional response.
227 */
228PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
229 pjsip_rx_data *rdata,
230 pjsip_tx_data **p_tdata)
231{
232 dlg_data *dd;
233 pjsip_transaction *tsx;
234 pjsip_msg *msg;
235 pjsip_generic_string_hdr *rseq_hdr;
236 pjsip_generic_string_hdr *rack_hdr;
237 unsigned rseq;
238 pj_str_t rack;
239 char rack_buf[80];
240 pjsip_tx_data *tdata;
241 pj_status_t status;
242
243 *p_tdata = NULL;
244
245 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
246 PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED);
247
248 tsx = pjsip_rdata_get_tsx(rdata);
249 msg = rdata->msg_info.msg;
250
251 /* Check our assumptions */
252 pj_assert( tsx->role == PJSIP_ROLE_UAC &&
253 tsx->method.id == PJSIP_INVITE_METHOD &&
254 msg->line.status.code > 100 &&
255 msg->line.status.code < 200);
256
257
258 /* Get the RSeq header */
259 rseq_hdr = (pjsip_generic_string_hdr*)
260 pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL);
261 if (rseq_hdr == NULL) {
262 PJ_LOG(4,(dd->inv->dlg->obj_name,
263 "Ignoring provisional response with no RSeq header"));
264 return PJSIP_EMISSINGHDR;
265 }
266 rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);
267
268 /* Create new UAC state if we don't have one */
269 if (dd->uac_state == NULL) {
270 dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool,
271 uac_state_t);
272 dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
273 dd->uac_state->rseq = rseq - 1;
274 }
275
276 /* If this is from new INVITE transaction, reset UAC state */
277 if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) {
278 dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
279 dd->uac_state->rseq = rseq - 1;
280 }
281
282 /* Ignore provisional response retransmission */
283 if (rseq <= dd->uac_state->rseq) {
284 /* This should have been handled before */
285 return PJ_EIGNORED;
286
287 /* Ignore provisional response with out-of-order RSeq */
288 } else if (rseq != dd->uac_state->rseq + 1) {
289 PJ_LOG(4,(dd->inv->dlg->obj_name,
290 "Ignoring provisional response because RSeq jump "
291 "(expecting %u, got %u)",
292 dd->uac_state->rseq+1, rseq));
293 return PJ_EIGNORED;
294 }
295
296 /* Update our RSeq */
297 dd->uac_state->rseq = rseq;
298
299 /* Create PRACK */
300 status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method,
301 -1, &tdata);
302 if (status != PJ_SUCCESS)
303 return status;
304
305 /* Create RAck header */
306 rack.ptr = rack_buf;
307 rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf),
308 "%u %u %.*s",
309 rseq, rdata->msg_info.cseq->cseq,
310 (int)tsx->method.name.slen,
311 tsx->method.name.ptr);
312 rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack);
313 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr);
314
315 /* Done */
316 *p_tdata = tdata;
317
318 return PJ_SUCCESS;
319}
320
321
322/*
323 * Send PRACK request.
324 */
325PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv,
326 pjsip_tx_data *tdata)
327{
328 dlg_data *dd;
329
330 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
331 PJ_ASSERT_ON_FAIL(dd != NULL,
332 {pjsip_tx_data_dec_ref(tdata); return PJSIP_ENOTINITIALIZED; });
333
334 return pjsip_dlg_send_request(inv->dlg, tdata,
335 mod_100rel.mod.id, (void*) dd);
336
337}
338
339
340/*
341 * Notify 100rel module that the invite session has been disconnected.
342 */
343PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv)
344{
345 dlg_data *dd;
346
347 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
348 if (!dd)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000349 return PJ_SUCCESS;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000350
351 /* Make sure we don't have pending transmission */
352 if (dd->uas_state) {
353 pj_assert(!dd->uas_state->retransmit_timer.id);
354 pj_assert(pj_list_empty(&dd->uas_state->tx_data_list));
355 }
356
357 return PJ_SUCCESS;
358}
359
360
361static void parse_rack(const pj_str_t *rack,
362 pj_uint32_t *p_rseq, pj_int32_t *p_seq,
363 pj_str_t *p_method)
364{
365 const char *p = rack->ptr, *end = p + rack->slen;
366 pj_str_t token;
367
368 token.ptr = (char*)p;
369 while (p < end && pj_isdigit(*p))
370 ++p;
371 token.slen = p - token.ptr;
372 *p_rseq = pj_strtoul(&token);
373
374 ++p;
375 token.ptr = (char*)p;
376 while (p < end && pj_isdigit(*p))
377 ++p;
378 token.slen = p - token.ptr;
379 *p_seq = pj_strtoul(&token);
380
381 ++p;
382 if (p < end) {
383 p_method->ptr = (char*)p;
384 p_method->slen = end - p;
385 } else {
386 p_method->ptr = NULL;
387 p_method->slen = 0;
388 }
389}
390
391/* Clear all responses in the transmission list */
392static void clear_all_responses(dlg_data *dd)
393{
394 tx_data_list_t *tl;
395
396 tl = dd->uas_state->tx_data_list.next;
397 while (tl != &dd->uas_state->tx_data_list) {
398 pjsip_tx_data_dec_ref(tl->tdata);
399 tl = tl->next;
400 }
401 pj_list_init(&dd->uas_state->tx_data_list);
402}
403
404
405/*
406 * Handle incoming PRACK request.
407 */
408PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv,
409 pjsip_rx_data *rdata)
410{
411 dlg_data *dd;
412 pjsip_transaction *tsx;
413 pjsip_msg *msg;
414 pjsip_generic_string_hdr *rack_hdr;
415 pjsip_tx_data *tdata;
416 pj_uint32_t rseq;
417 pj_int32_t cseq;
418 pj_str_t method;
419 pj_status_t status;
420
Benny Prijono1f7767b2007-10-03 18:28:49 +0000421 tsx = pjsip_rdata_get_tsx(rdata);
422 pj_assert(tsx != NULL);
423
424 msg = rdata->msg_info.msg;
425
Benny Prijono2d2cc942008-09-11 08:00:47 +0000426 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
427 if (dd == NULL) {
428 /* UAC sends us PRACK while we didn't send reliable provisional
429 * response. Respond with 400 (?)
430 */
431 const pj_str_t reason = pj_str("Unexpected PRACK");
432
433 status = pjsip_dlg_create_response(inv->dlg, rdata, 400,
434 &reason, &tdata);
435 if (status == PJ_SUCCESS) {
436 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
437 }
438 return PJSIP_ENOTINITIALIZED;
439 }
440
Benny Prijono1f7767b2007-10-03 18:28:49 +0000441 /* Always reply with 200/OK for PRACK */
442 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
443 if (status == PJ_SUCCESS) {
444 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
445 }
446
447 /* Ignore if we don't have pending transmission */
448 if (dd->uas_state == NULL || pj_list_empty(&dd->uas_state->tx_data_list)) {
449 PJ_LOG(4,(dd->inv->dlg->obj_name,
450 "PRACK ignored - no pending response"));
451 return PJ_EIGNORED;
452 }
453
454 /* Find RAck header */
455 rack_hdr = (pjsip_generic_string_hdr*)
456 pjsip_msg_find_hdr_by_name(msg, &RACK, NULL);
457 if (!rack_hdr) {
458 /* RAck header not found */
459 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header"));
460 return PJSIP_EMISSINGHDR;
461 }
462
463 /* Parse RAck header */
464 parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method);
465
466
467 /* Match RAck against outgoing transmission */
468 if (rseq == dd->uas_state->tx_data_list.next->rseq &&
469 cseq == dd->uas_state->cseq)
470 {
471 /*
472 * Yes this PRACK matches outgoing transmission.
473 */
474 tx_data_list_t *tl = dd->uas_state->tx_data_list.next;
475
476 if (dd->uas_state->retransmit_timer.id) {
477 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
478 &dd->uas_state->retransmit_timer);
479 dd->uas_state->retransmit_timer.id = PJ_FALSE;
480 }
481
482 /* Remove from the list */
483 if (tl != &dd->uas_state->tx_data_list) {
484 pj_list_erase(tl);
485
486 /* Destroy the response */
487 pjsip_tx_data_dec_ref(tl->tdata);
488 }
489
490 /* Schedule next packet */
491 dd->uas_state->retransmit_count = 0;
492 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
493 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
494 }
495
496 } else {
497 /* No it doesn't match */
498 PJ_LOG(4,(dd->inv->dlg->obj_name,
499 "Rx PRACK with no matching reliable response"));
500 return PJ_EIGNORED;
501 }
502
503 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000504}
505
506
507/*
508 * This is retransmit timer callback, called initially to send the response,
509 * and subsequently when the retransmission time elapses.
510 */
511static void on_retransmit(pj_timer_heap_t *timer_heap,
512 struct pj_timer_entry *entry)
513{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000514 dlg_data *dd;
515 tx_data_list_t *tl;
516 pjsip_tx_data *tdata;
517 pj_bool_t final;
518 pj_time_val delay;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000519
Benny Prijono1f7767b2007-10-03 18:28:49 +0000520 PJ_UNUSED_ARG(timer_heap);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000521
Benny Prijono1f7767b2007-10-03 18:28:49 +0000522 dd = (dlg_data*) entry->user_data;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000523
Benny Prijono1f7767b2007-10-03 18:28:49 +0000524 entry->id = PJ_FALSE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000525
Benny Prijono1f7767b2007-10-03 18:28:49 +0000526 ++dd->uas_state->retransmit_count;
527 if (dd->uas_state->retransmit_count >= 7) {
528 /* If a reliable provisional response is retransmitted for
529 64*T1 seconds without reception of a corresponding PRACK,
530 the UAS SHOULD reject the original request with a 5xx
531 response.
532 */
533 pj_str_t reason = pj_str("Reliable response timed out");
534 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000535
Benny Prijono1f7767b2007-10-03 18:28:49 +0000536 /* Clear all pending responses */
537 clear_all_responses(dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000538
Benny Prijono1f7767b2007-10-03 18:28:49 +0000539 /* Send 500 response */
540 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata);
541 if (status == PJ_SUCCESS) {
542 pjsip_dlg_send_response(dd->inv->dlg,
543 dd->inv->invite_tsx,
544 tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000545 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000546 return;
547 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000548
Benny Prijono1f7767b2007-10-03 18:28:49 +0000549 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list));
550 tl = dd->uas_state->tx_data_list.next;
551 tdata = tl->tdata;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000552
Benny Prijono1f7767b2007-10-03 18:28:49 +0000553 pjsip_tx_data_add_ref(tdata);
554 final = tdata->msg->line.status.code >= 200;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000555
Benny Prijono1f7767b2007-10-03 18:28:49 +0000556 if (dd->uas_state->retransmit_count == 1) {
557 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata);
558 } else {
559 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata);
560 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000561
Benny Prijono1f7767b2007-10-03 18:28:49 +0000562 if (final) {
563 /* This is final response, which will be retransmitted by
564 * UA layer. There's no more task to do, so clear the
565 * transmission list and bail out.
566 */
567 clear_all_responses(dd);
568 return;
569 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000570
Benny Prijono1f7767b2007-10-03 18:28:49 +0000571 /* Schedule next retransmission */
572 if (dd->uas_state->retransmit_count < 6) {
573 delay.sec = 0;
574 delay.msec = (1 << dd->uas_state->retransmit_count) *
Benny Prijono4768c3c2008-02-22 11:10:17 +0000575 pjsip_cfg()->tsx.t1;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000576 pj_time_val_normalize(&delay);
577 } else {
578 delay.sec = 1;
579 delay.msec = 500;
580 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000581
582
Benny Prijono1f7767b2007-10-03 18:28:49 +0000583 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,
584 &dd->uas_state->retransmit_timer,
585 &delay);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000586
Benny Prijono1f7767b2007-10-03 18:28:49 +0000587 entry->id = PJ_TRUE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000588}
589
Benny Prijono1f7767b2007-10-03 18:28:49 +0000590
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000591/* Clone response. */
592static pjsip_tx_data *clone_tdata(dlg_data *dd,
593 const pjsip_tx_data *src)
594{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000595 pjsip_tx_data *dst;
596 const pjsip_hdr *hsrc;
597 pjsip_msg *msg;
598 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000599
Benny Prijono1f7767b2007-10-03 18:28:49 +0000600 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst);
601 if (status != PJ_SUCCESS)
602 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000603
Benny Prijono1f7767b2007-10-03 18:28:49 +0000604 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG);
605 dst->msg = msg;
606 pjsip_tx_data_add_ref(dst);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000607
Benny Prijono1f7767b2007-10-03 18:28:49 +0000608 /* Duplicate status line */
609 msg->line.status.code = src->msg->line.status.code;
610 pj_strdup(dst->pool, &msg->line.status.reason,
611 &src->msg->line.status.reason);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000612
Benny Prijono1f7767b2007-10-03 18:28:49 +0000613 /* Duplicate all headers */
614 hsrc = src->msg->hdr.next;
615 while (hsrc != &src->msg->hdr) {
616 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc);
617 pjsip_msg_add_hdr(msg, h);
618 hsrc = hsrc->next;
619 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000620
Benny Prijono1f7767b2007-10-03 18:28:49 +0000621 /* Duplicate message body */
622 if (src->msg->body)
623 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000624
Benny Prijono1f7767b2007-10-03 18:28:49 +0000625 PJ_LOG(5,(dd->inv->dlg->obj_name,
626 "Reliable response %s created",
627 pjsip_tx_data_get_info(dst)));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000628
Benny Prijono1f7767b2007-10-03 18:28:49 +0000629 return dst;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000630}
631
Benny Prijono1f7767b2007-10-03 18:28:49 +0000632
633/* Check if any pending response in transmission list has SDP */
Benny Prijono79d79882007-10-01 12:22:52 +0000634static pj_bool_t has_sdp(dlg_data *dd)
635{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000636 tx_data_list_t *tl;
Benny Prijono79d79882007-10-01 12:22:52 +0000637
Benny Prijono1f7767b2007-10-03 18:28:49 +0000638 tl = dd->uas_state->tx_data_list.next;
639 while (tl != &dd->uas_state->tx_data_list) {
640 if (tl->tdata->msg->body)
641 return PJ_TRUE;
642 tl = tl->next;
643 }
Benny Prijono79d79882007-10-01 12:22:52 +0000644
Benny Prijono1f7767b2007-10-03 18:28:49 +0000645 return PJ_FALSE;
Benny Prijono79d79882007-10-01 12:22:52 +0000646}
647
648
649/* Send response reliably */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000650PJ_DEF(pj_status_t) pjsip_100rel_tx_response(pjsip_inv_session *inv,
651 pjsip_tx_data *tdata)
652{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000653 pjsip_cseq_hdr *cseq_hdr;
654 pjsip_generic_string_hdr *rseq_hdr;
655 pjsip_require_hdr *req_hdr;
656 int status_code;
657 dlg_data *dd;
658 pjsip_tx_data *old_tdata;
659 pj_status_t status;
660
661 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
662 PJSIP_ENOTRESPONSEMSG);
663
664 status_code = tdata->msg->line.status.code;
665
666 /* 100 response doesn't need PRACK */
667 if (status_code == 100)
668 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
669
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000670
Benny Prijono1f7767b2007-10-03 18:28:49 +0000671 /* Get the 100rel data attached to this dialog */
672 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
673 PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP);
674
675
676 /* Clone tdata.
677 * We need to clone tdata because we may need to keep it in our
678 * retransmission list, while the original dialog may modify it
679 * if it wants to send another response.
680 */
681 old_tdata = tdata;
682 tdata = clone_tdata(dd, old_tdata);
683 pjsip_tx_data_dec_ref(old_tdata);
684
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000685
Benny Prijono1f7767b2007-10-03 18:28:49 +0000686 /* Get CSeq header, and make sure this is INVITE response */
687 cseq_hdr = (pjsip_cseq_hdr*)
688 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
689 PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG);
690 PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD,
691 PJ_EINVALIDOP);
692
693 /* Remove existing Require header */
694 req_hdr = find_req_hdr(tdata->msg);
695 if (req_hdr) {
696 pj_list_erase(req_hdr);
697 }
698
699 /* Remove existing RSeq header */
700 rseq_hdr = (pjsip_generic_string_hdr*)
701 pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL);
702 if (rseq_hdr)
703 pj_list_erase(rseq_hdr);
704
705 /* Different treatment for provisional and final response */
706 if (status_code/100 == 2) {
707
708 /* RFC 3262 Section 3: UAS Behavior:
709
710 The UAS MAY send a final response to the initial request
711 before having received PRACKs for all unacknowledged
712 reliable provisional responses, unless the final response
713 is 2xx and any of the unacknowledged reliable provisional
714 responses contained a session description. In that case,
715 it MUST NOT send a final response until those provisional
716 responses are acknowledged.
717 */
718
719 if (dd->uas_state && has_sdp(dd)) {
720 /* Yes we have transmitted 1xx with SDP reliably.
721 * In this case, must queue the 2xx response.
722 */
723 tx_data_list_t *tl;
724
725 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
726 tl->tdata = tdata;
727 tl->rseq = (pj_uint32_t)-1;
728 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
729
730 /* Will send later */
731 status = PJ_SUCCESS;
732
733 PJ_LOG(4,(dd->inv->dlg->obj_name,
734 "2xx response will be sent after PRACK"));
735
736 } else if (dd->uas_state) {
737 /*
738 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000739
Benny Prijono1f7767b2007-10-03 18:28:49 +0000740 If the UAS does send a final response when reliable
741 responses are still unacknowledged, it SHOULD NOT
742 continue to retransmit the unacknowledged reliable
743 provisional responses, but it MUST be prepared to
744 process PRACK requests for those outstanding
745 responses.
746 */
747
748 PJ_LOG(4,(dd->inv->dlg->obj_name,
749 "No SDP sent so far, sending 2xx now"));
750
751 /* Cancel the retransmit timer */
752 if (dd->uas_state->retransmit_timer.id) {
753 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
754 &dd->uas_state->retransmit_timer);
755 dd->uas_state->retransmit_timer.id = PJ_FALSE;
756 }
757
758 /* Clear all pending responses (drop 'em) */
759 clear_all_responses(dd);
760
761 /* And transmit the 2xx response */
762 status=pjsip_dlg_send_response(inv->dlg,
763 inv->invite_tsx, tdata);
764
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000765 } else {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000766 /* We didn't send any reliable provisional response */
767
768 /* Transmit the 2xx response */
769 status=pjsip_dlg_send_response(inv->dlg,
770 inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000771 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000772
773 } else if (status_code >= 300) {
774
775 /*
776 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000777
Benny Prijono1f7767b2007-10-03 18:28:49 +0000778 If the UAS does send a final response when reliable
779 responses are still unacknowledged, it SHOULD NOT
780 continue to retransmit the unacknowledged reliable
781 provisional responses, but it MUST be prepared to
782 process PRACK requests for those outstanding
783 responses.
784 */
785
786 /* Cancel the retransmit timer */
787 if (dd->uas_state && 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 /* Clear all pending responses (drop 'em) */
793 clear_all_responses(dd);
794 }
795
796 /* And transmit the 2xx response */
797 status=pjsip_dlg_send_response(inv->dlg,
798 inv->invite_tsx, tdata);
799
800 } else {
801 /*
802 * This is provisional response.
803 */
804 char rseq_str[32];
805 pj_str_t rseq;
806 tx_data_list_t *tl;
807
808 /* Create UAS state if we don't have one */
809 if (dd->uas_state == NULL) {
810 dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool,
811 uas_state_t);
812 dd->uas_state->cseq = cseq_hdr->cseq;
813 dd->uas_state->rseq = pj_rand() % 0x7FFF;
814 pj_list_init(&dd->uas_state->tx_data_list);
815 dd->uas_state->retransmit_timer.user_data = dd;
816 dd->uas_state->retransmit_timer.cb = &on_retransmit;
817 }
818
819 /* Check that CSeq match */
820 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq,
821 PJ_EINVALIDOP);
822
823 /* Add Require header */
824 req_hdr = pjsip_require_hdr_create(tdata->pool);
825 req_hdr->count = 1;
826 req_hdr->values[0] = tag_100rel;
827 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
828
829 /* Add RSeq header */
830 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u",
831 dd->uas_state->rseq);
832 rseq = pj_str(rseq_str);
833 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool,
834 &RSEQ, &rseq);
835 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr);
836
837 /* Create list entry for this response */
838 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
839 tl->tdata = tdata;
840 tl->rseq = dd->uas_state->rseq++;
841
842 /* Add to queue if there's pending response, otherwise
843 * transmit immediately.
844 */
845 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
846
847 int code = tdata->msg->line.status.code;
848
849 /* Will send later */
850 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
851 status = PJ_SUCCESS;
852
853 PJ_LOG(4,(dd->inv->dlg->obj_name,
854 "Reliable %d response enqueued (%d pending)",
855 code, pj_list_size(&dd->uas_state->tx_data_list)));
856
857 } else {
858 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
859
860 dd->uas_state->retransmit_count = 0;
861 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
862 status = PJ_SUCCESS;
863 }
864
865 }
866
867 return status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000868}
869
870