blob: 60b989b210081a9a62466f1a9e53264841660718 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
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);
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)
384 return PJ_SUCCESS;
385
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
456 tsx = pjsip_rdata_get_tsx(rdata);
457 pj_assert(tsx != NULL);
458
459 msg = rdata->msg_info.msg;
460
461 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
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);
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;
539}
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{
549 dlg_data *dd;
550 tx_data_list_t *tl;
551 pjsip_tx_data *tdata;
552 pj_bool_t final;
553 pj_time_val delay;
554
555 PJ_UNUSED_ARG(timer_heap);
556
557 dd = (dlg_data*) entry->user_data;
558
559 entry->id = PJ_FALSE;
560
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
566 response.
567 */
568 pj_str_t reason = pj_str("Reliable response timed out");
569 pj_status_t status;
570
571 /* Clear all pending responses */
572 clear_all_responses(dd);
573
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,
578 dd->inv->invite_tsx,
579 tdata);
580 }
581 return;
582 }
583
584 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list));
585 tl = dd->uas_state->tx_data_list.next;
586 tdata = tl->tdata;
587
588 pjsip_tx_data_add_ref(tdata);
589 final = tdata->msg->line.status.code >= 200;
590
591 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 }
596
597 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 }
605
606 /* Schedule next retransmission */
607 if (dd->uas_state->retransmit_count < 6) {
608 delay.sec = 0;
609 delay.msec = (1 << dd->uas_state->retransmit_count) *
610 pjsip_cfg()->tsx.t1;
611 pj_time_val_normalize(&delay);
612 } else {
613 delay.sec = 1;
614 delay.msec = 500;
615 }
616
617
618 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,
619 &dd->uas_state->retransmit_timer,
620 &delay);
621
622 entry->id = PJ_TRUE;
623}
624
625
626/* Clone response. */
627static pjsip_tx_data *clone_tdata(dlg_data *dd,
628 const pjsip_tx_data *src)
629{
630 pjsip_tx_data *dst;
631 const pjsip_hdr *hsrc;
632 pjsip_msg *msg;
633 pj_status_t status;
634
635 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst);
636 if (status != PJ_SUCCESS)
637 return NULL;
638
639 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG);
640 dst->msg = msg;
641 pjsip_tx_data_add_ref(dst);
642
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);
647
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);
653 hsrc = hsrc->next;
654 }
655
656 /* Duplicate message body */
657 if (src->msg->body)
658 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body);
659
660 PJ_LOG(5,(dd->inv->dlg->obj_name,
661 "Reliable response %s created",
662 pjsip_tx_data_get_info(dst)));
663
664 return dst;
665}
666
667
668/* Check if any pending response in transmission list has SDP */
669static pj_bool_t has_sdp(dlg_data *dd)
670{
671 tx_data_list_t *tl;
672
673 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 }
679
680 return PJ_FALSE;
681}
682
683
684/* Send response reliably */
685PJ_DEF(pj_status_t) pjsip_100rel_tx_response(pjsip_inv_session *inv,
686 pjsip_tx_data *tdata)
687{
688 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
705
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);
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
720
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,
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:
774
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
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
800 } else {
801 /* 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);
806 }
807
808 } else if (status_code >= 300) {
809
810 /*
811 RFC 3262 Section 3: UAS Behavior:
812
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
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;
903}
904
905