blob: 86105ca9195b2d84ab4ea6cf2c8aadb6bee82ed9 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id: sip_100rel.c 4613 2013-10-08 09:08:13Z bennylp $ */
Tristan Matthews0a329cc2013-07-17 13:20:14 -04002/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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#include <pj/string.h>
32
33#define THIS_FILE "sip_100rel.c"
34
35/* PRACK method */
36PJ_DEF_DATA(const pjsip_method) pjsip_prack_method =
37{
38 PJSIP_OTHER_METHOD,
39 { "PRACK", 5 }
40};
41
42typedef struct dlg_data dlg_data;
43
44/*
45 * Static prototypes.
46 */
47static pj_status_t mod_100rel_load(pjsip_endpoint *endpt);
48
49static void on_retransmit(pj_timer_heap_t *timer_heap,
50 struct pj_timer_entry *entry);
51
52
53const 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() */
78 NULL, /* on_tsx_state() */
79 }
80
81};
82
83/* List of pending transmission (may include the final response as well) */
84typedef struct tx_data_list_t
85{
86 PJ_DECL_LIST_MEMBER(struct tx_data_list_t);
87 pj_uint32_t rseq;
88 pjsip_tx_data *tdata;
89} tx_data_list_t;
90
91
92/* Below, UAS and UAC roles are of the INVITE transaction */
93
94/* UAS state. */
95typedef struct uas_state_t
96{
97 pj_int32_t cseq;
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;
102} uas_state_t;
103
104
105/* UAC state */
106typedef struct uac_state_t
107{
108 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 */
112} uac_state_t;
113
114
115/* State attached to each dialog. */
116struct dlg_data
117{
118 pjsip_inv_session *inv;
119 uas_state_t *uas_state;
120 uac_state_t *uac_state_list;
121};
122
123
124/*****************************************************************************
125 **
126 ** Module
127 **
128 *****************************************************************************
129 */
130static pj_status_t mod_100rel_load(pjsip_endpoint *endpt)
131{
132 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);
139
140 return PJ_SUCCESS;
141}
142
143static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg)
144{
145 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;
160
161 hreq = (pjsip_require_hdr*)
162 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next);
163
164 }
165
166 return NULL;
167}
168
169
170/*
171 * Get PRACK method constant.
172 */
173PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void)
174{
175 return &pjsip_prack_method;
176}
177
178
179/*
180 * init module
181 */
182PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt)
183{
184 if (mod_100rel.mod.id != -1)
185 return PJ_SUCCESS;
186
187 return pjsip_endpt_register_module(endpt, &mod_100rel.mod);
188}
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{
197 dlg_data *dd;
198
199 /* Check that 100rel module has been initialized */
200 PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP);
201
202 /* 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);
206
207 PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached"));
208
209 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;
236 uac_state_t *uac_state = NULL;
237 const pj_str_t *to_tag = &rdata->msg_info.to->tag;
238 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,
268 "Ignoring 100rel response with no RSeq header"));
269 return PJSIP_EMISSINGHDR;
270 }
271 rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);
272
273 /* Find UAC state for the specified call leg */
274 uac_state = dd->uac_state_list;
275 while (uac_state) {
276 if (pj_stricmp(&uac_state->tag, to_tag)==0)
277 break;
278 uac_state = uac_state->next;
279 }
280
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;
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;
295 }
296
297 /* Ignore provisional response retransmission */
298 if (rseq <= uac_state->rseq) {
299 /* This should have been handled before */
300 return PJ_EIGNORED;
301
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));
308 return PJ_EIGNORED;
309 }
310
311 /* Update our RSeq */
312 uac_state->rseq = rseq;
313
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
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)
322 */
323 if (pj_stricmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) {
324 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
340 /* 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);
Alexandre Lision8af73cb2013-12-10 14:11:20 -0500347 if (rack.slen < 1 || rack.slen >= (int)sizeof(rack_buf)) {
348 return PJ_ETOOSMALL;
349 }
Tristan Matthews0a329cc2013-07-17 13:20:14 -0400350 rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack);
351 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr);
352
353 /* Done */
354 *p_tdata = tdata;
355
356 return PJ_SUCCESS;
357}
358
359
360/*
361 * Send PRACK request.
362 */
363PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv,
364 pjsip_tx_data *tdata)
365{
366 dlg_data *dd;
367
368 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
369 PJ_ASSERT_ON_FAIL(dd != NULL,
370 {pjsip_tx_data_dec_ref(tdata); return PJSIP_ENOTINITIALIZED; });
371
372 return pjsip_dlg_send_request(inv->dlg, tdata,
373 mod_100rel.mod.id, (void*) dd);
374
375}
376
377
378/*
379 * Notify 100rel module that the invite session has been disconnected.
380 */
381PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv)
382{
383 dlg_data *dd;
384
385 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
386 if (!dd)
387 return PJ_SUCCESS;
388
389 /* Make sure we don't have pending transmission */
390 if (dd->uas_state) {
391 pj_assert(!dd->uas_state->retransmit_timer.id);
392 pj_assert(pj_list_empty(&dd->uas_state->tx_data_list));
393 }
394
395 return PJ_SUCCESS;
396}
397
398
399static void parse_rack(const pj_str_t *rack,
400 pj_uint32_t *p_rseq, pj_int32_t *p_seq,
401 pj_str_t *p_method)
402{
403 const char *p = rack->ptr, *end = p + rack->slen;
404 pj_str_t token;
405
406 token.ptr = (char*)p;
407 while (p < end && pj_isdigit(*p))
408 ++p;
409 token.slen = p - token.ptr;
410 *p_rseq = pj_strtoul(&token);
411
412 ++p;
413 token.ptr = (char*)p;
414 while (p < end && pj_isdigit(*p))
415 ++p;
416 token.slen = p - token.ptr;
417 *p_seq = pj_strtoul(&token);
418
419 ++p;
420 if (p < end) {
421 p_method->ptr = (char*)p;
422 p_method->slen = end - p;
423 } else {
424 p_method->ptr = NULL;
425 p_method->slen = 0;
426 }
427}
428
429/* Clear all responses in the transmission list */
430static void clear_all_responses(dlg_data *dd)
431{
432 tx_data_list_t *tl;
433
434 tl = dd->uas_state->tx_data_list.next;
435 while (tl != &dd->uas_state->tx_data_list) {
436 pjsip_tx_data_dec_ref(tl->tdata);
437 tl = tl->next;
438 }
439 pj_list_init(&dd->uas_state->tx_data_list);
440}
441
442
443/*
444 * Handle incoming PRACK request.
445 */
446PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv,
447 pjsip_rx_data *rdata)
448{
449 dlg_data *dd;
450 pjsip_transaction *tsx;
451 pjsip_msg *msg;
452 pjsip_generic_string_hdr *rack_hdr;
453 pjsip_tx_data *tdata;
454 pj_uint32_t rseq;
455 pj_int32_t cseq;
456 pj_str_t method;
457 pj_status_t status;
458
459 tsx = pjsip_rdata_get_tsx(rdata);
460 pj_assert(tsx != NULL);
461
462 msg = rdata->msg_info.msg;
463
464 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
465 if (dd == NULL) {
466 /* UAC sends us PRACK while we didn't send reliable provisional
467 * response. Respond with 400 (?)
468 */
469 const pj_str_t reason = pj_str("Unexpected PRACK");
470
471 status = pjsip_dlg_create_response(inv->dlg, rdata, 400,
472 &reason, &tdata);
473 if (status == PJ_SUCCESS) {
474 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
475 }
476 return PJSIP_ENOTINITIALIZED;
477 }
478
479 /* Always reply with 200/OK for PRACK */
480 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
481 if (status == PJ_SUCCESS) {
482 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
483 }
484
485 /* Ignore if we don't have pending transmission */
486 if (dd->uas_state == NULL || pj_list_empty(&dd->uas_state->tx_data_list)) {
487 PJ_LOG(4,(dd->inv->dlg->obj_name,
488 "PRACK ignored - no pending response"));
489 return PJ_EIGNORED;
490 }
491
492 /* Find RAck header */
493 rack_hdr = (pjsip_generic_string_hdr*)
494 pjsip_msg_find_hdr_by_name(msg, &RACK, NULL);
495 if (!rack_hdr) {
496 /* RAck header not found */
497 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header"));
498 return PJSIP_EMISSINGHDR;
499 }
500
501 /* Parse RAck header */
502 parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method);
503
504
505 /* Match RAck against outgoing transmission */
506 if (rseq == dd->uas_state->tx_data_list.next->rseq &&
507 cseq == dd->uas_state->cseq)
508 {
509 /*
510 * Yes this PRACK matches outgoing transmission.
511 */
512 tx_data_list_t *tl = dd->uas_state->tx_data_list.next;
513
514 if (dd->uas_state->retransmit_timer.id) {
515 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
516 &dd->uas_state->retransmit_timer);
517 dd->uas_state->retransmit_timer.id = PJ_FALSE;
518 }
519
520 /* Remove from the list */
521 if (tl != &dd->uas_state->tx_data_list) {
522 pj_list_erase(tl);
523
524 /* Destroy the response */
525 pjsip_tx_data_dec_ref(tl->tdata);
526 }
527
528 /* Schedule next packet */
529 dd->uas_state->retransmit_count = 0;
530 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
531 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
532 }
533
534 } else {
535 /* No it doesn't match */
536 PJ_LOG(4,(dd->inv->dlg->obj_name,
537 "Rx PRACK with no matching reliable response"));
538 return PJ_EIGNORED;
539 }
540
541 return PJ_SUCCESS;
542}
543
544
545/*
546 * This is retransmit timer callback, called initially to send the response,
547 * and subsequently when the retransmission time elapses.
548 */
549static void on_retransmit(pj_timer_heap_t *timer_heap,
550 struct pj_timer_entry *entry)
551{
552 dlg_data *dd;
553 tx_data_list_t *tl;
554 pjsip_tx_data *tdata;
555 pj_bool_t final;
556 pj_time_val delay;
557
558 PJ_UNUSED_ARG(timer_heap);
559
560 dd = (dlg_data*) entry->user_data;
561
562 entry->id = PJ_FALSE;
563
564 ++dd->uas_state->retransmit_count;
565 if (dd->uas_state->retransmit_count >= 7) {
566 /* If a reliable provisional response is retransmitted for
567 64*T1 seconds without reception of a corresponding PRACK,
568 the UAS SHOULD reject the original request with a 5xx
569 response.
570 */
571 pj_str_t reason = pj_str("Reliable response timed out");
572 pj_status_t status;
573
574 /* Clear all pending responses */
575 clear_all_responses(dd);
576
577 /* Send 500 response */
578 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata);
579 if (status == PJ_SUCCESS) {
580 pjsip_dlg_send_response(dd->inv->dlg,
581 dd->inv->invite_tsx,
582 tdata);
583 }
584 return;
585 }
586
587 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list));
588 tl = dd->uas_state->tx_data_list.next;
589 tdata = tl->tdata;
590
591 pjsip_tx_data_add_ref(tdata);
592 final = tdata->msg->line.status.code >= 200;
593
594 if (dd->uas_state->retransmit_count == 1) {
595 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata);
596 } else {
597 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata);
598 }
599
600 if (final) {
601 /* This is final response, which will be retransmitted by
602 * UA layer. There's no more task to do, so clear the
603 * transmission list and bail out.
604 */
605 clear_all_responses(dd);
606 return;
607 }
608
609 /* Schedule next retransmission */
610 if (dd->uas_state->retransmit_count < 6) {
611 delay.sec = 0;
612 delay.msec = (1 << dd->uas_state->retransmit_count) *
613 pjsip_cfg()->tsx.t1;
614 pj_time_val_normalize(&delay);
615 } else {
616 delay.sec = 1;
617 delay.msec = 500;
618 }
619
620
621 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,
622 &dd->uas_state->retransmit_timer,
623 &delay);
624
625 entry->id = PJ_TRUE;
626}
627
628
629/* Clone response. */
630static pjsip_tx_data *clone_tdata(dlg_data *dd,
631 const pjsip_tx_data *src)
632{
633 pjsip_tx_data *dst;
634 const pjsip_hdr *hsrc;
635 pjsip_msg *msg;
636 pj_status_t status;
637
638 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst);
639 if (status != PJ_SUCCESS)
640 return NULL;
641
642 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG);
643 dst->msg = msg;
644 pjsip_tx_data_add_ref(dst);
645
646 /* Duplicate status line */
647 msg->line.status.code = src->msg->line.status.code;
648 pj_strdup(dst->pool, &msg->line.status.reason,
649 &src->msg->line.status.reason);
650
651 /* Duplicate all headers */
652 hsrc = src->msg->hdr.next;
653 while (hsrc != &src->msg->hdr) {
654 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc);
655 pjsip_msg_add_hdr(msg, h);
656 hsrc = hsrc->next;
657 }
658
659 /* Duplicate message body */
660 if (src->msg->body)
661 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body);
662
663 PJ_LOG(5,(dd->inv->dlg->obj_name,
664 "Reliable response %s created",
665 pjsip_tx_data_get_info(dst)));
666
667 return dst;
668}
669
670
671/* Check if any pending response in transmission list has SDP */
672static pj_bool_t has_sdp(dlg_data *dd)
673{
674 tx_data_list_t *tl;
675
676 tl = dd->uas_state->tx_data_list.next;
677 while (tl != &dd->uas_state->tx_data_list) {
678 if (tl->tdata->msg->body)
679 return PJ_TRUE;
680 tl = tl->next;
681 }
682
683 return PJ_FALSE;
684}
685
686
687/* Send response reliably */
688PJ_DEF(pj_status_t) pjsip_100rel_tx_response(pjsip_inv_session *inv,
689 pjsip_tx_data *tdata)
690{
691 pjsip_cseq_hdr *cseq_hdr;
692 pjsip_generic_string_hdr *rseq_hdr;
693 pjsip_require_hdr *req_hdr;
694 int status_code;
695 dlg_data *dd;
696 pjsip_tx_data *old_tdata;
697 pj_status_t status;
698
699 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
700 PJSIP_ENOTRESPONSEMSG);
701
702 status_code = tdata->msg->line.status.code;
703
704 /* 100 response doesn't need PRACK */
705 if (status_code == 100)
706 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
707
708
709 /* Get the 100rel data attached to this dialog */
710 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
711 PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP);
712
713
714 /* Clone tdata.
715 * We need to clone tdata because we may need to keep it in our
716 * retransmission list, while the original dialog may modify it
717 * if it wants to send another response.
718 */
719 old_tdata = tdata;
720 tdata = clone_tdata(dd, old_tdata);
721 pjsip_tx_data_dec_ref(old_tdata);
722
723
724 /* Get CSeq header, and make sure this is INVITE response */
725 cseq_hdr = (pjsip_cseq_hdr*)
726 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
727 PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG);
728 PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD,
729 PJ_EINVALIDOP);
730
731 /* Remove existing Require header */
732 req_hdr = find_req_hdr(tdata->msg);
733 if (req_hdr) {
734 pj_list_erase(req_hdr);
735 }
736
737 /* Remove existing RSeq header */
738 rseq_hdr = (pjsip_generic_string_hdr*)
739 pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL);
740 if (rseq_hdr)
741 pj_list_erase(rseq_hdr);
742
743 /* Different treatment for provisional and final response */
744 if (status_code/100 == 2) {
745
746 /* RFC 3262 Section 3: UAS Behavior:
747
748 The UAS MAY send a final response to the initial request
749 before having received PRACKs for all unacknowledged
750 reliable provisional responses, unless the final response
751 is 2xx and any of the unacknowledged reliable provisional
752 responses contained a session description. In that case,
753 it MUST NOT send a final response until those provisional
754 responses are acknowledged.
755 */
756
757 if (dd->uas_state && has_sdp(dd)) {
758 /* Yes we have transmitted 1xx with SDP reliably.
759 * In this case, must queue the 2xx response.
760 */
761 tx_data_list_t *tl;
762
763 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
764 tl->tdata = tdata;
765 tl->rseq = (pj_uint32_t)-1;
766 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
767
768 /* Will send later */
769 status = PJ_SUCCESS;
770
771 PJ_LOG(4,(dd->inv->dlg->obj_name,
772 "2xx response will be sent after PRACK"));
773
774 } else if (dd->uas_state) {
775 /*
776 RFC 3262 Section 3: UAS Behavior:
777
778 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 PJ_LOG(4,(dd->inv->dlg->obj_name,
787 "No SDP sent so far, sending 2xx now"));
788
789 /* Cancel the retransmit timer */
790 if (dd->uas_state->retransmit_timer.id) {
791 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
792 &dd->uas_state->retransmit_timer);
793 dd->uas_state->retransmit_timer.id = PJ_FALSE;
794 }
795
796 /* Clear all pending responses (drop 'em) */
797 clear_all_responses(dd);
798
799 /* And transmit the 2xx response */
800 status=pjsip_dlg_send_response(inv->dlg,
801 inv->invite_tsx, tdata);
802
803 } else {
804 /* We didn't send any reliable provisional response */
805
806 /* Transmit the 2xx response */
807 status=pjsip_dlg_send_response(inv->dlg,
808 inv->invite_tsx, tdata);
809 }
810
811 } else if (status_code >= 300) {
812
813 /*
814 RFC 3262 Section 3: UAS Behavior:
815
816 If the UAS does send a final response when reliable
817 responses are still unacknowledged, it SHOULD NOT
818 continue to retransmit the unacknowledged reliable
819 provisional responses, but it MUST be prepared to
820 process PRACK requests for those outstanding
821 responses.
822 */
823
824 /* Cancel the retransmit timer */
825 if (dd->uas_state && dd->uas_state->retransmit_timer.id) {
826 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
827 &dd->uas_state->retransmit_timer);
828 dd->uas_state->retransmit_timer.id = PJ_FALSE;
829
830 /* Clear all pending responses (drop 'em) */
831 clear_all_responses(dd);
832 }
833
834 /* And transmit the 2xx response */
835 status=pjsip_dlg_send_response(inv->dlg,
836 inv->invite_tsx, tdata);
837
838 } else {
839 /*
840 * This is provisional response.
841 */
842 char rseq_str[32];
843 pj_str_t rseq;
844 tx_data_list_t *tl;
845
846 /* Create UAS state if we don't have one */
847 if (dd->uas_state == NULL) {
848 dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool,
849 uas_state_t);
850 dd->uas_state->cseq = cseq_hdr->cseq;
851 dd->uas_state->rseq = pj_rand() % 0x7FFF;
852 pj_list_init(&dd->uas_state->tx_data_list);
853 dd->uas_state->retransmit_timer.user_data = dd;
854 dd->uas_state->retransmit_timer.cb = &on_retransmit;
855 }
856
857 /* Check that CSeq match */
858 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq,
859 PJ_EINVALIDOP);
860
861 /* Add Require header */
862 req_hdr = pjsip_require_hdr_create(tdata->pool);
863 req_hdr->count = 1;
864 req_hdr->values[0] = tag_100rel;
865 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
866
867 /* Add RSeq header */
868 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u",
869 dd->uas_state->rseq);
870 rseq = pj_str(rseq_str);
871 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool,
872 &RSEQ, &rseq);
873 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr);
874
875 /* Create list entry for this response */
876 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
877 tl->tdata = tdata;
878 tl->rseq = dd->uas_state->rseq++;
879
880 /* Add to queue if there's pending response, otherwise
881 * transmit immediately.
882 */
883 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
884
885 int code = tdata->msg->line.status.code;
886
887 /* Will send later */
888 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
889 status = PJ_SUCCESS;
890
891 PJ_LOG(4,(dd->inv->dlg->obj_name,
892 "Reliable %d response enqueued (%d pending)",
893 code, pj_list_size(&dd->uas_state->tx_data_list)));
894
895 } else {
896 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
897
898 dd->uas_state->retransmit_count = 0;
899 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
900 status = PJ_SUCCESS;
901 }
902
903 }
904
905 return status;
906}
907
908