1
/* $Id: sip_100rel.c 4208 2012-07-18 07:52:33Z ming $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
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>
31
#include <pj/string.h>
33
#define THIS_FILE "sip_100rel.c"
36
PJ_DEF_DATA(const pjsip_method) pjsip_prack_method =
42
typedef struct dlg_data dlg_data;
47
static pj_status_t mod_100rel_load(pjsip_endpoint *endpt);
49
static void on_retransmit(pj_timer_heap_t *timer_heap,
50
struct pj_timer_entry *entry);
53
const pj_str_t tag_100rel = { "100rel", 6 };
54
const pj_str_t RSEQ = { "RSeq", 4 };
55
const pj_str_t RACK = { "RAck", 4 };
59
static struct mod_100rel
62
pjsip_endpoint *endpt;
66
NULL, NULL, /* prev, next. */
67
{ "mod-100rel", 10 }, /* Name. */
69
PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
70
&mod_100rel_load, /* load() */
74
NULL, /* on_rx_request() */
75
NULL, /* on_rx_response() */
76
NULL, /* on_tx_request. */
77
NULL, /* on_tx_response() */
78
NULL, /* on_tsx_state() */
83
/* List of pending transmission (may include the final response as well) */
84
typedef struct tx_data_list_t
86
PJ_DECL_LIST_MEMBER(struct tx_data_list_t);
92
/* Below, UAS and UAC roles are of the INVITE transaction */
95
typedef struct uas_state_t
98
pj_uint32_t rseq; /* Initialized to -1 */
99
tx_data_list_t tx_data_list;
100
unsigned retransmit_count;
101
pj_timer_entry retransmit_timer;
106
typedef struct uac_state_t
108
pj_str_t tag; /* To tag */
110
pj_uint32_t rseq; /* Initialized to -1 */
111
struct uac_state_t *next; /* next call leg */
115
/* State attached to each dialog. */
118
pjsip_inv_session *inv;
119
uas_state_t *uas_state;
120
uac_state_t *uac_state_list;
124
/*****************************************************************************
128
*****************************************************************************
130
static pj_status_t mod_100rel_load(pjsip_endpoint *endpt)
132
mod_100rel.endpt = endpt;
133
pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
135
1, &pjsip_prack_method.name);
136
pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
137
PJSIP_H_SUPPORTED, NULL,
143
static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg)
145
pjsip_require_hdr *hreq;
147
hreq = (pjsip_require_hdr*)
148
pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
152
for (i=0; i<hreq->count; ++i) {
153
if (!pj_stricmp(&hreq->values[i], &tag_100rel)) {
158
if ((void*)hreq->next == (void*)&msg->hdr)
161
hreq = (pjsip_require_hdr*)
162
pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next);
171
* Get PRACK method constant.
173
PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void)
175
return &pjsip_prack_method;
182
PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt)
184
if (mod_100rel.mod.id != -1)
187
return pjsip_endpt_register_module(endpt, &mod_100rel.mod);
192
* API: attach 100rel support in invite session. Called by
195
PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv)
199
/* Check that 100rel module has been initialized */
200
PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP);
202
/* Create and attach as dialog usage */
203
dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data);
205
pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd);
207
PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached"));
214
* Check if incoming response has reliable provisional response feature.
216
PJ_DEF(pj_bool_t) pjsip_100rel_is_reliable(pjsip_rx_data *rdata)
218
pjsip_msg *msg = rdata->msg_info.msg;
220
PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG, PJ_FALSE);
222
return msg->line.status.code > 100 && msg->line.status.code < 200 &&
223
rdata->msg_info.require != NULL &&
224
find_req_hdr(msg) != NULL;
229
* Create PRACK request for the incoming reliable provisional response.
231
PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
232
pjsip_rx_data *rdata,
233
pjsip_tx_data **p_tdata)
236
uac_state_t *uac_state = NULL;
237
const pj_str_t *to_tag = &rdata->msg_info.to->tag;
238
pjsip_transaction *tsx;
240
pjsip_generic_string_hdr *rseq_hdr;
241
pjsip_generic_string_hdr *rack_hdr;
245
pjsip_tx_data *tdata;
250
dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
251
PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED);
253
tsx = pjsip_rdata_get_tsx(rdata);
254
msg = rdata->msg_info.msg;
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);
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,
268
"Ignoring 100rel response with no RSeq header"));
269
return PJSIP_EMISSINGHDR;
271
rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);
273
/* Find UAC state for the specified call leg */
274
uac_state = dd->uac_state_list;
276
if (pj_stricmp(&uac_state->tag, to_tag)==0)
278
uac_state = uac_state->next;
281
/* 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;
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;
297
/* Ignore provisional response retransmission */
298
if (rseq <= uac_state->rseq) {
299
/* This should have been handled before */
302
/* Ignore provisional response with out-of-order RSeq */
303
} else if (rseq != uac_state->rseq + 1) {
304
PJ_LOG(4,(dd->inv->dlg->obj_name,
305
"Ignoring 100rel response because RSeq jump "
306
"(expecting %u, got %u)",
307
uac_state->rseq+1, rseq));
311
/* Update our RSeq */
312
uac_state->rseq = rseq;
315
status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method,
317
if (status != PJ_SUCCESS)
320
/* If this response is a forked response from a different call-leg,
321
* update the req URI (https://trac.pjsip.org/repos/ticket/1364)
323
if (pj_stricmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) {
324
const pjsip_contact_hdr *mhdr;
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);
336
tdata->msg->line.req.uri = (pjsip_uri*)
337
pjsip_uri_clone(tdata->pool, mhdr->uri);
340
/* Create RAck header */
342
rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf),
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);
358
* Send PRACK request.
360
PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv,
361
pjsip_tx_data *tdata)
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; });
369
return pjsip_dlg_send_request(inv->dlg, tdata,
370
mod_100rel.mod.id, (void*) dd);
376
* Notify 100rel module that the invite session has been disconnected.
378
PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv)
382
dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
386
/* Make sure we don't have pending transmission */
388
pj_assert(!dd->uas_state->retransmit_timer.id);
389
pj_assert(pj_list_empty(&dd->uas_state->tx_data_list));
396
static void parse_rack(const pj_str_t *rack,
397
pj_uint32_t *p_rseq, pj_int32_t *p_seq,
400
const char *p = rack->ptr, *end = p + rack->slen;
403
token.ptr = (char*)p;
404
while (p < end && pj_isdigit(*p))
406
token.slen = p - token.ptr;
407
*p_rseq = pj_strtoul(&token);
410
token.ptr = (char*)p;
411
while (p < end && pj_isdigit(*p))
413
token.slen = p - token.ptr;
414
*p_seq = pj_strtoul(&token);
418
p_method->ptr = (char*)p;
419
p_method->slen = end - p;
421
p_method->ptr = NULL;
426
/* Clear all responses in the transmission list */
427
static void clear_all_responses(dlg_data *dd)
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);
436
pj_list_init(&dd->uas_state->tx_data_list);
441
* Handle incoming PRACK request.
443
PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv,
444
pjsip_rx_data *rdata)
447
pjsip_transaction *tsx;
449
pjsip_generic_string_hdr *rack_hdr;
450
pjsip_tx_data *tdata;
456
tsx = pjsip_rdata_get_tsx(rdata);
457
pj_assert(tsx != NULL);
459
msg = rdata->msg_info.msg;
461
dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
463
/* UAC sends us PRACK while we didn't send reliable provisional
464
* response. Respond with 400 (?)
466
const pj_str_t reason = pj_str("Unexpected PRACK");
468
status = pjsip_dlg_create_response(inv->dlg, rdata, 400,
470
if (status == PJ_SUCCESS) {
471
status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
473
return PJSIP_ENOTINITIALIZED;
476
/* 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);
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"));
489
/* Find RAck header */
490
rack_hdr = (pjsip_generic_string_hdr*)
491
pjsip_msg_find_hdr_by_name(msg, &RACK, NULL);
493
/* RAck header not found */
494
PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header"));
495
return PJSIP_EMISSINGHDR;
498
/* Parse RAck header */
499
parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method);
502
/* Match RAck against outgoing transmission */
503
if (rseq == dd->uas_state->tx_data_list.next->rseq &&
504
cseq == dd->uas_state->cseq)
507
* Yes this PRACK matches outgoing transmission.
509
tx_data_list_t *tl = dd->uas_state->tx_data_list.next;
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;
517
/* Remove from the list */
518
if (tl != &dd->uas_state->tx_data_list) {
521
/* Destroy the response */
522
pjsip_tx_data_dec_ref(tl->tdata);
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);
532
/* No it doesn't match */
533
PJ_LOG(4,(dd->inv->dlg->obj_name,
534
"Rx PRACK with no matching reliable response"));
543
* This is retransmit timer callback, called initially to send the response,
544
* and subsequently when the retransmission time elapses.
546
static void on_retransmit(pj_timer_heap_t *timer_heap,
547
struct pj_timer_entry *entry)
551
pjsip_tx_data *tdata;
555
PJ_UNUSED_ARG(timer_heap);
557
dd = (dlg_data*) entry->user_data;
559
entry->id = PJ_FALSE;
561
++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
568
pj_str_t reason = pj_str("Reliable response timed out");
571
/* Clear all pending responses */
572
clear_all_responses(dd);
574
/* 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,
584
pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list));
585
tl = dd->uas_state->tx_data_list.next;
588
pjsip_tx_data_add_ref(tdata);
589
final = tdata->msg->line.status.code >= 200;
591
if (dd->uas_state->retransmit_count == 1) {
592
pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata);
594
pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata);
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.
602
clear_all_responses(dd);
606
/* Schedule next retransmission */
607
if (dd->uas_state->retransmit_count < 6) {
609
delay.msec = (1 << dd->uas_state->retransmit_count) *
611
pj_time_val_normalize(&delay);
618
pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,
619
&dd->uas_state->retransmit_timer,
626
/* Clone response. */
627
static pjsip_tx_data *clone_tdata(dlg_data *dd,
628
const pjsip_tx_data *src)
631
const pjsip_hdr *hsrc;
635
status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst);
636
if (status != PJ_SUCCESS)
639
msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG);
641
pjsip_tx_data_add_ref(dst);
643
/* 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);
648
/* 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);
656
/* Duplicate message body */
658
msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body);
660
PJ_LOG(5,(dd->inv->dlg->obj_name,
661
"Reliable response %s created",
662
pjsip_tx_data_get_info(dst)));
668
/* Check if any pending response in transmission list has SDP */
669
static pj_bool_t has_sdp(dlg_data *dd)
673
tl = dd->uas_state->tx_data_list.next;
674
while (tl != &dd->uas_state->tx_data_list) {
675
if (tl->tdata->msg->body)
684
/* Send response reliably */
685
PJ_DEF(pj_status_t) pjsip_100rel_tx_response(pjsip_inv_session *inv,
686
pjsip_tx_data *tdata)
688
pjsip_cseq_hdr *cseq_hdr;
689
pjsip_generic_string_hdr *rseq_hdr;
690
pjsip_require_hdr *req_hdr;
693
pjsip_tx_data *old_tdata;
696
PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
697
PJSIP_ENOTRESPONSEMSG);
699
status_code = tdata->msg->line.status.code;
701
/* 100 response doesn't need PRACK */
702
if (status_code == 100)
703
return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
706
/* 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);
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.
717
tdata = clone_tdata(dd, old_tdata);
718
pjsip_tx_data_dec_ref(old_tdata);
721
/* 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,
728
/* Remove existing Require header */
729
req_hdr = find_req_hdr(tdata->msg);
731
pj_list_erase(req_hdr);
734
/* Remove existing RSeq header */
735
rseq_hdr = (pjsip_generic_string_hdr*)
736
pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL);
738
pj_list_erase(rseq_hdr);
740
/* Different treatment for provisional and final response */
741
if (status_code/100 == 2) {
743
/* RFC 3262 Section 3: UAS Behavior:
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.
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.
760
tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
762
tl->rseq = (pj_uint32_t)-1;
763
pj_list_push_back(&dd->uas_state->tx_data_list, tl);
765
/* Will send later */
768
PJ_LOG(4,(dd->inv->dlg->obj_name,
769
"2xx response will be sent after PRACK"));
771
} else if (dd->uas_state) {
773
RFC 3262 Section 3: UAS Behavior:
775
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
783
PJ_LOG(4,(dd->inv->dlg->obj_name,
784
"No SDP sent so far, sending 2xx now"));
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;
793
/* Clear all pending responses (drop 'em) */
794
clear_all_responses(dd);
796
/* And transmit the 2xx response */
797
status=pjsip_dlg_send_response(inv->dlg,
798
inv->invite_tsx, tdata);
801
/* We didn't send any reliable provisional response */
803
/* Transmit the 2xx response */
804
status=pjsip_dlg_send_response(inv->dlg,
805
inv->invite_tsx, tdata);
808
} else if (status_code >= 300) {
811
RFC 3262 Section 3: UAS Behavior:
813
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
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;
827
/* Clear all pending responses (drop 'em) */
828
clear_all_responses(dd);
831
/* And transmit the 2xx response */
832
status=pjsip_dlg_send_response(inv->dlg,
833
inv->invite_tsx, tdata);
837
* This is provisional response.
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,
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;
854
/* Check that CSeq match */
855
PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq,
858
/* Add Require header */
859
req_hdr = pjsip_require_hdr_create(tdata->pool);
861
req_hdr->values[0] = tag_100rel;
862
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
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,
870
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr);
872
/* Create list entry for this response */
873
tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
875
tl->rseq = dd->uas_state->rseq++;
877
/* Add to queue if there's pending response, otherwise
878
* transmit immediately.
880
if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
882
int code = tdata->msg->line.status.code;
884
/* Will send later */
885
pj_list_push_back(&dd->uas_state->tx_data_list, tl);
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)));
893
pj_list_push_back(&dd->uas_state->tx_data_list, tl);
895
dd->uas_state->retransmit_count = 0;
896
on_retransmit(NULL, &dd->uas_state->retransmit_timer);