blob: 657b298cdb702830afbcf8105fc4cf4cecaadeb5 [file] [log] [blame]
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonodcfc0ba2007-09-30 16:50:27 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjsip-ua/sip_100rel.h>
20#include <pjsip/sip_endpoint.h>
21#include <pjsip/sip_event.h>
22#include <pjsip/sip_module.h>
23#include <pjsip/sip_transaction.h>
24#include <pj/assert.h>
25#include <pj/ctype.h>
26#include <pj/log.h>
27#include <pj/os.h>
28#include <pj/pool.h>
29#include <pj/rand.h>
30
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000031#define THIS_FILE "sip_100rel.c"
32
Benny Prijono1f7767b2007-10-03 18:28:49 +000033/* PRACK method */
34PJ_DEF_DATA(const pjsip_method) pjsip_prack_method =
35{
36 PJSIP_OTHER_METHOD,
37 { "PRACK", 5 }
38};
39
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000040typedef struct dlg_data dlg_data;
41
42/*
43 * Static prototypes.
44 */
45static pj_status_t mod_100rel_load(pjsip_endpoint *endpt);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000046
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000047static void on_retransmit(pj_timer_heap_t *timer_heap,
48 struct pj_timer_entry *entry);
49
50
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000051const pj_str_t tag_100rel = { "100rel", 6 };
52const pj_str_t RSEQ = { "RSeq", 4 };
53const pj_str_t RACK = { "RAck", 4 };
54
55
56/* 100rel module */
57static struct mod_100rel
58{
59 pjsip_module mod;
60 pjsip_endpoint *endpt;
61} mod_100rel =
62{
63 {
64 NULL, NULL, /* prev, next. */
65 { "mod-100rel", 10 }, /* Name. */
66 -1, /* Id */
67 PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
68 &mod_100rel_load, /* load() */
69 NULL, /* start() */
70 NULL, /* stop() */
71 NULL, /* unload() */
72 NULL, /* on_rx_request() */
73 NULL, /* on_rx_response() */
74 NULL, /* on_tx_request. */
75 NULL, /* on_tx_response() */
Benny Prijono1f7767b2007-10-03 18:28:49 +000076 NULL, /* on_tsx_state() */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000077 }
78
79};
80
81/* List of pending transmission (may include the final response as well) */
Benny Prijono373633c2007-09-30 18:06:41 +000082typedef struct tx_data_list_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000083{
Benny Prijono373633c2007-09-30 18:06:41 +000084 PJ_DECL_LIST_MEMBER(struct tx_data_list_t);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000085 pj_uint32_t rseq;
86 pjsip_tx_data *tdata;
Benny Prijono373633c2007-09-30 18:06:41 +000087} tx_data_list_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000088
89
90/* Below, UAS and UAC roles are of the INVITE transaction */
91
92/* UAS state. */
Benny Prijono373633c2007-09-30 18:06:41 +000093typedef struct uas_state_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000094{
95 pj_int32_t cseq;
96 pj_uint32_t rseq; /* Initialized to -1 */
Benny Prijono373633c2007-09-30 18:06:41 +000097 tx_data_list_t tx_data_list;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +000098 unsigned retransmit_count;
99 pj_timer_entry retransmit_timer;
Benny Prijono373633c2007-09-30 18:06:41 +0000100} uas_state_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000101
102
103/* UAC state */
Benny Prijono373633c2007-09-30 18:06:41 +0000104typedef struct uac_state_t
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000105{
106 pj_int32_t cseq;
107 pj_uint32_t rseq; /* Initialized to -1 */
Benny Prijono373633c2007-09-30 18:06:41 +0000108} uac_state_t;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000109
110
111/* State attached to each dialog. */
112struct dlg_data
113{
114 pjsip_inv_session *inv;
Benny Prijono373633c2007-09-30 18:06:41 +0000115 uas_state_t *uas_state;
116 uac_state_t *uac_state;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000117};
118
119
120/*****************************************************************************
121 **
122 ** Module
123 **
124 *****************************************************************************
125 */
126static pj_status_t mod_100rel_load(pjsip_endpoint *endpt)
127{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000128 mod_100rel.endpt = endpt;
129 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
130 PJSIP_H_ALLOW, NULL,
131 1, &pjsip_prack_method.name);
132 pjsip_endpt_add_capability(endpt, &mod_100rel.mod,
133 PJSIP_H_SUPPORTED, NULL,
134 1, &tag_100rel);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000135
Benny Prijono1f7767b2007-10-03 18:28:49 +0000136 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000137}
138
139static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg)
140{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000141 pjsip_require_hdr *hreq;
142
143 hreq = (pjsip_require_hdr*)
144 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL);
145
146 while (hreq) {
147 unsigned i;
148 for (i=0; i<hreq->count; ++i) {
149 if (!pj_stricmp(&hreq->values[i], &tag_100rel)) {
150 return hreq;
151 }
152 }
153
154 if ((void*)hreq->next == (void*)&msg->hdr)
155 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000156
157 hreq = (pjsip_require_hdr*)
Benny Prijono1f7767b2007-10-03 18:28:49 +0000158 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000159
Benny Prijono1f7767b2007-10-03 18:28:49 +0000160 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000161
Benny Prijono1f7767b2007-10-03 18:28:49 +0000162 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000163}
164
165
166/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000167 * Get PRACK method constant.
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000168 */
Benny Prijono1f7767b2007-10-03 18:28:49 +0000169PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000170{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000171 return &pjsip_prack_method;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000172}
173
174
175/*
Benny Prijono1f7767b2007-10-03 18:28:49 +0000176 * init module
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000177 */
178PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt)
179{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000180 if (mod_100rel.mod.id != -1)
181 return PJ_SUCCESS;
182
183 return pjsip_endpt_register_module(endpt, &mod_100rel.mod);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000184}
185
186
187/*
188 * API: attach 100rel support in invite session. Called by
189 * sip_inv.c
190 */
191PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv)
192{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000193 dlg_data *dd;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000194
Benny Prijono1f7767b2007-10-03 18:28:49 +0000195 /* Check that 100rel module has been initialized */
196 PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000197
Benny Prijono1f7767b2007-10-03 18:28:49 +0000198 /* Create and attach as dialog usage */
199 dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data);
200 dd->inv = inv;
201 pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000202
Benny Prijono1f7767b2007-10-03 18:28:49 +0000203 PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached"));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000204
Benny Prijono1f7767b2007-10-03 18:28:49 +0000205 return PJ_SUCCESS;
206}
207
208
209/*
210 * Check if incoming response has reliable provisional response feature.
211 */
212PJ_DEF(pj_bool_t) pjsip_100rel_is_reliable(pjsip_rx_data *rdata)
213{
214 pjsip_msg *msg = rdata->msg_info.msg;
215
216 PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG, PJ_FALSE);
217
218 return msg->line.status.code > 100 && msg->line.status.code < 200 &&
219 rdata->msg_info.require != NULL &&
220 find_req_hdr(msg) != NULL;
221}
222
223
224/*
225 * Create PRACK request for the incoming reliable provisional response.
226 */
227PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
228 pjsip_rx_data *rdata,
229 pjsip_tx_data **p_tdata)
230{
231 dlg_data *dd;
232 pjsip_transaction *tsx;
233 pjsip_msg *msg;
234 pjsip_generic_string_hdr *rseq_hdr;
235 pjsip_generic_string_hdr *rack_hdr;
236 unsigned rseq;
237 pj_str_t rack;
238 char rack_buf[80];
239 pjsip_tx_data *tdata;
240 pj_status_t status;
241
242 *p_tdata = NULL;
243
244 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
245 PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED);
246
247 tsx = pjsip_rdata_get_tsx(rdata);
248 msg = rdata->msg_info.msg;
249
250 /* Check our assumptions */
251 pj_assert( tsx->role == PJSIP_ROLE_UAC &&
252 tsx->method.id == PJSIP_INVITE_METHOD &&
253 msg->line.status.code > 100 &&
254 msg->line.status.code < 200);
255
256
257 /* Get the RSeq header */
258 rseq_hdr = (pjsip_generic_string_hdr*)
259 pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL);
260 if (rseq_hdr == NULL) {
261 PJ_LOG(4,(dd->inv->dlg->obj_name,
262 "Ignoring provisional response with no RSeq header"));
263 return PJSIP_EMISSINGHDR;
264 }
265 rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);
266
267 /* Create new UAC state if we don't have one */
268 if (dd->uac_state == NULL) {
269 dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool,
270 uac_state_t);
271 dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
272 dd->uac_state->rseq = rseq - 1;
273 }
274
275 /* If this is from new INVITE transaction, reset UAC state */
276 if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) {
277 dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
278 dd->uac_state->rseq = rseq - 1;
279 }
280
281 /* Ignore provisional response retransmission */
282 if (rseq <= dd->uac_state->rseq) {
283 /* This should have been handled before */
284 return PJ_EIGNORED;
285
286 /* Ignore provisional response with out-of-order RSeq */
287 } else if (rseq != dd->uac_state->rseq + 1) {
288 PJ_LOG(4,(dd->inv->dlg->obj_name,
289 "Ignoring provisional response because RSeq jump "
290 "(expecting %u, got %u)",
291 dd->uac_state->rseq+1, rseq));
292 return PJ_EIGNORED;
293 }
294
295 /* Update our RSeq */
296 dd->uac_state->rseq = rseq;
297
298 /* Create PRACK */
299 status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method,
300 -1, &tdata);
301 if (status != PJ_SUCCESS)
302 return status;
303
304 /* Create RAck header */
305 rack.ptr = rack_buf;
306 rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf),
307 "%u %u %.*s",
308 rseq, rdata->msg_info.cseq->cseq,
309 (int)tsx->method.name.slen,
310 tsx->method.name.ptr);
311 rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack);
312 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr);
313
314 /* Done */
315 *p_tdata = tdata;
316
317 return PJ_SUCCESS;
318}
319
320
321/*
322 * Send PRACK request.
323 */
324PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv,
325 pjsip_tx_data *tdata)
326{
327 dlg_data *dd;
328
329 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
330 PJ_ASSERT_ON_FAIL(dd != NULL,
331 {pjsip_tx_data_dec_ref(tdata); return PJSIP_ENOTINITIALIZED; });
332
333 return pjsip_dlg_send_request(inv->dlg, tdata,
334 mod_100rel.mod.id, (void*) dd);
335
336}
337
338
339/*
340 * Notify 100rel module that the invite session has been disconnected.
341 */
342PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv)
343{
344 dlg_data *dd;
345
346 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
347 if (!dd)
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000348 return PJ_SUCCESS;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000349
350 /* Make sure we don't have pending transmission */
351 if (dd->uas_state) {
352 pj_assert(!dd->uas_state->retransmit_timer.id);
353 pj_assert(pj_list_empty(&dd->uas_state->tx_data_list));
354 }
355
356 return PJ_SUCCESS;
357}
358
359
360static void parse_rack(const pj_str_t *rack,
361 pj_uint32_t *p_rseq, pj_int32_t *p_seq,
362 pj_str_t *p_method)
363{
364 const char *p = rack->ptr, *end = p + rack->slen;
365 pj_str_t token;
366
367 token.ptr = (char*)p;
368 while (p < end && pj_isdigit(*p))
369 ++p;
370 token.slen = p - token.ptr;
371 *p_rseq = pj_strtoul(&token);
372
373 ++p;
374 token.ptr = (char*)p;
375 while (p < end && pj_isdigit(*p))
376 ++p;
377 token.slen = p - token.ptr;
378 *p_seq = pj_strtoul(&token);
379
380 ++p;
381 if (p < end) {
382 p_method->ptr = (char*)p;
383 p_method->slen = end - p;
384 } else {
385 p_method->ptr = NULL;
386 p_method->slen = 0;
387 }
388}
389
390/* Clear all responses in the transmission list */
391static void clear_all_responses(dlg_data *dd)
392{
393 tx_data_list_t *tl;
394
395 tl = dd->uas_state->tx_data_list.next;
396 while (tl != &dd->uas_state->tx_data_list) {
397 pjsip_tx_data_dec_ref(tl->tdata);
398 tl = tl->next;
399 }
400 pj_list_init(&dd->uas_state->tx_data_list);
401}
402
403
404/*
405 * Handle incoming PRACK request.
406 */
407PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv,
408 pjsip_rx_data *rdata)
409{
410 dlg_data *dd;
411 pjsip_transaction *tsx;
412 pjsip_msg *msg;
413 pjsip_generic_string_hdr *rack_hdr;
414 pjsip_tx_data *tdata;
415 pj_uint32_t rseq;
416 pj_int32_t cseq;
417 pj_str_t method;
418 pj_status_t status;
419
420 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
421 PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED);
422
423 tsx = pjsip_rdata_get_tsx(rdata);
424 pj_assert(tsx != NULL);
425
426 msg = rdata->msg_info.msg;
427
428 /* Always reply with 200/OK for PRACK */
429 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata);
430 if (status == PJ_SUCCESS) {
431 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata);
432 }
433
434 /* Ignore if we don't have pending transmission */
435 if (dd->uas_state == NULL || pj_list_empty(&dd->uas_state->tx_data_list)) {
436 PJ_LOG(4,(dd->inv->dlg->obj_name,
437 "PRACK ignored - no pending response"));
438 return PJ_EIGNORED;
439 }
440
441 /* Find RAck header */
442 rack_hdr = (pjsip_generic_string_hdr*)
443 pjsip_msg_find_hdr_by_name(msg, &RACK, NULL);
444 if (!rack_hdr) {
445 /* RAck header not found */
446 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header"));
447 return PJSIP_EMISSINGHDR;
448 }
449
450 /* Parse RAck header */
451 parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method);
452
453
454 /* Match RAck against outgoing transmission */
455 if (rseq == dd->uas_state->tx_data_list.next->rseq &&
456 cseq == dd->uas_state->cseq)
457 {
458 /*
459 * Yes this PRACK matches outgoing transmission.
460 */
461 tx_data_list_t *tl = dd->uas_state->tx_data_list.next;
462
463 if (dd->uas_state->retransmit_timer.id) {
464 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
465 &dd->uas_state->retransmit_timer);
466 dd->uas_state->retransmit_timer.id = PJ_FALSE;
467 }
468
469 /* Remove from the list */
470 if (tl != &dd->uas_state->tx_data_list) {
471 pj_list_erase(tl);
472
473 /* Destroy the response */
474 pjsip_tx_data_dec_ref(tl->tdata);
475 }
476
477 /* Schedule next packet */
478 dd->uas_state->retransmit_count = 0;
479 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
480 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
481 }
482
483 } else {
484 /* No it doesn't match */
485 PJ_LOG(4,(dd->inv->dlg->obj_name,
486 "Rx PRACK with no matching reliable response"));
487 return PJ_EIGNORED;
488 }
489
490 return PJ_SUCCESS;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000491}
492
493
494/*
495 * This is retransmit timer callback, called initially to send the response,
496 * and subsequently when the retransmission time elapses.
497 */
498static void on_retransmit(pj_timer_heap_t *timer_heap,
499 struct pj_timer_entry *entry)
500{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000501 dlg_data *dd;
502 tx_data_list_t *tl;
503 pjsip_tx_data *tdata;
504 pj_bool_t final;
505 pj_time_val delay;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000506
Benny Prijono1f7767b2007-10-03 18:28:49 +0000507 PJ_UNUSED_ARG(timer_heap);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000508
Benny Prijono1f7767b2007-10-03 18:28:49 +0000509 dd = (dlg_data*) entry->user_data;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000510
Benny Prijono1f7767b2007-10-03 18:28:49 +0000511 entry->id = PJ_FALSE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000512
Benny Prijono1f7767b2007-10-03 18:28:49 +0000513 ++dd->uas_state->retransmit_count;
514 if (dd->uas_state->retransmit_count >= 7) {
515 /* If a reliable provisional response is retransmitted for
516 64*T1 seconds without reception of a corresponding PRACK,
517 the UAS SHOULD reject the original request with a 5xx
518 response.
519 */
520 pj_str_t reason = pj_str("Reliable response timed out");
521 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000522
Benny Prijono1f7767b2007-10-03 18:28:49 +0000523 /* Clear all pending responses */
524 clear_all_responses(dd);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000525
Benny Prijono1f7767b2007-10-03 18:28:49 +0000526 /* Send 500 response */
527 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata);
528 if (status == PJ_SUCCESS) {
529 pjsip_dlg_send_response(dd->inv->dlg,
530 dd->inv->invite_tsx,
531 tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000532 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000533 return;
534 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000535
Benny Prijono1f7767b2007-10-03 18:28:49 +0000536 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list));
537 tl = dd->uas_state->tx_data_list.next;
538 tdata = tl->tdata;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000539
Benny Prijono1f7767b2007-10-03 18:28:49 +0000540 pjsip_tx_data_add_ref(tdata);
541 final = tdata->msg->line.status.code >= 200;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000542
Benny Prijono1f7767b2007-10-03 18:28:49 +0000543 if (dd->uas_state->retransmit_count == 1) {
544 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata);
545 } else {
546 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata);
547 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000548
Benny Prijono1f7767b2007-10-03 18:28:49 +0000549 if (final) {
550 /* This is final response, which will be retransmitted by
551 * UA layer. There's no more task to do, so clear the
552 * transmission list and bail out.
553 */
554 clear_all_responses(dd);
555 return;
556 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000557
Benny Prijono1f7767b2007-10-03 18:28:49 +0000558 /* Schedule next retransmission */
559 if (dd->uas_state->retransmit_count < 6) {
560 delay.sec = 0;
561 delay.msec = (1 << dd->uas_state->retransmit_count) *
Benny Prijono4768c3c2008-02-22 11:10:17 +0000562 pjsip_cfg()->tsx.t1;
Benny Prijono1f7767b2007-10-03 18:28:49 +0000563 pj_time_val_normalize(&delay);
564 } else {
565 delay.sec = 1;
566 delay.msec = 500;
567 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000568
569
Benny Prijono1f7767b2007-10-03 18:28:49 +0000570 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt,
571 &dd->uas_state->retransmit_timer,
572 &delay);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000573
Benny Prijono1f7767b2007-10-03 18:28:49 +0000574 entry->id = PJ_TRUE;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000575}
576
Benny Prijono1f7767b2007-10-03 18:28:49 +0000577
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000578/* Clone response. */
579static pjsip_tx_data *clone_tdata(dlg_data *dd,
580 const pjsip_tx_data *src)
581{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000582 pjsip_tx_data *dst;
583 const pjsip_hdr *hsrc;
584 pjsip_msg *msg;
585 pj_status_t status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000586
Benny Prijono1f7767b2007-10-03 18:28:49 +0000587 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst);
588 if (status != PJ_SUCCESS)
589 return NULL;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000590
Benny Prijono1f7767b2007-10-03 18:28:49 +0000591 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG);
592 dst->msg = msg;
593 pjsip_tx_data_add_ref(dst);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000594
Benny Prijono1f7767b2007-10-03 18:28:49 +0000595 /* Duplicate status line */
596 msg->line.status.code = src->msg->line.status.code;
597 pj_strdup(dst->pool, &msg->line.status.reason,
598 &src->msg->line.status.reason);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000599
Benny Prijono1f7767b2007-10-03 18:28:49 +0000600 /* Duplicate all headers */
601 hsrc = src->msg->hdr.next;
602 while (hsrc != &src->msg->hdr) {
603 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc);
604 pjsip_msg_add_hdr(msg, h);
605 hsrc = hsrc->next;
606 }
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000607
Benny Prijono1f7767b2007-10-03 18:28:49 +0000608 /* Duplicate message body */
609 if (src->msg->body)
610 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000611
Benny Prijono1f7767b2007-10-03 18:28:49 +0000612 PJ_LOG(5,(dd->inv->dlg->obj_name,
613 "Reliable response %s created",
614 pjsip_tx_data_get_info(dst)));
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000615
Benny Prijono1f7767b2007-10-03 18:28:49 +0000616 return dst;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000617}
618
Benny Prijono1f7767b2007-10-03 18:28:49 +0000619
620/* Check if any pending response in transmission list has SDP */
Benny Prijono79d79882007-10-01 12:22:52 +0000621static pj_bool_t has_sdp(dlg_data *dd)
622{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000623 tx_data_list_t *tl;
Benny Prijono79d79882007-10-01 12:22:52 +0000624
Benny Prijono1f7767b2007-10-03 18:28:49 +0000625 tl = dd->uas_state->tx_data_list.next;
626 while (tl != &dd->uas_state->tx_data_list) {
627 if (tl->tdata->msg->body)
628 return PJ_TRUE;
629 tl = tl->next;
630 }
Benny Prijono79d79882007-10-01 12:22:52 +0000631
Benny Prijono1f7767b2007-10-03 18:28:49 +0000632 return PJ_FALSE;
Benny Prijono79d79882007-10-01 12:22:52 +0000633}
634
635
636/* Send response reliably */
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000637PJ_DEF(pj_status_t) pjsip_100rel_tx_response(pjsip_inv_session *inv,
638 pjsip_tx_data *tdata)
639{
Benny Prijono1f7767b2007-10-03 18:28:49 +0000640 pjsip_cseq_hdr *cseq_hdr;
641 pjsip_generic_string_hdr *rseq_hdr;
642 pjsip_require_hdr *req_hdr;
643 int status_code;
644 dlg_data *dd;
645 pjsip_tx_data *old_tdata;
646 pj_status_t status;
647
648 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG,
649 PJSIP_ENOTRESPONSEMSG);
650
651 status_code = tdata->msg->line.status.code;
652
653 /* 100 response doesn't need PRACK */
654 if (status_code == 100)
655 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata);
656
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000657
Benny Prijono1f7767b2007-10-03 18:28:49 +0000658 /* Get the 100rel data attached to this dialog */
659 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
660 PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP);
661
662
663 /* Clone tdata.
664 * We need to clone tdata because we may need to keep it in our
665 * retransmission list, while the original dialog may modify it
666 * if it wants to send another response.
667 */
668 old_tdata = tdata;
669 tdata = clone_tdata(dd, old_tdata);
670 pjsip_tx_data_dec_ref(old_tdata);
671
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000672
Benny Prijono1f7767b2007-10-03 18:28:49 +0000673 /* Get CSeq header, and make sure this is INVITE response */
674 cseq_hdr = (pjsip_cseq_hdr*)
675 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
676 PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG);
677 PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD,
678 PJ_EINVALIDOP);
679
680 /* Remove existing Require header */
681 req_hdr = find_req_hdr(tdata->msg);
682 if (req_hdr) {
683 pj_list_erase(req_hdr);
684 }
685
686 /* Remove existing RSeq header */
687 rseq_hdr = (pjsip_generic_string_hdr*)
688 pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL);
689 if (rseq_hdr)
690 pj_list_erase(rseq_hdr);
691
692 /* Different treatment for provisional and final response */
693 if (status_code/100 == 2) {
694
695 /* RFC 3262 Section 3: UAS Behavior:
696
697 The UAS MAY send a final response to the initial request
698 before having received PRACKs for all unacknowledged
699 reliable provisional responses, unless the final response
700 is 2xx and any of the unacknowledged reliable provisional
701 responses contained a session description. In that case,
702 it MUST NOT send a final response until those provisional
703 responses are acknowledged.
704 */
705
706 if (dd->uas_state && has_sdp(dd)) {
707 /* Yes we have transmitted 1xx with SDP reliably.
708 * In this case, must queue the 2xx response.
709 */
710 tx_data_list_t *tl;
711
712 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
713 tl->tdata = tdata;
714 tl->rseq = (pj_uint32_t)-1;
715 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
716
717 /* Will send later */
718 status = PJ_SUCCESS;
719
720 PJ_LOG(4,(dd->inv->dlg->obj_name,
721 "2xx response will be sent after PRACK"));
722
723 } else if (dd->uas_state) {
724 /*
725 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000726
Benny Prijono1f7767b2007-10-03 18:28:49 +0000727 If the UAS does send a final response when reliable
728 responses are still unacknowledged, it SHOULD NOT
729 continue to retransmit the unacknowledged reliable
730 provisional responses, but it MUST be prepared to
731 process PRACK requests for those outstanding
732 responses.
733 */
734
735 PJ_LOG(4,(dd->inv->dlg->obj_name,
736 "No SDP sent so far, sending 2xx now"));
737
738 /* Cancel the retransmit timer */
739 if (dd->uas_state->retransmit_timer.id) {
740 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
741 &dd->uas_state->retransmit_timer);
742 dd->uas_state->retransmit_timer.id = PJ_FALSE;
743 }
744
745 /* Clear all pending responses (drop 'em) */
746 clear_all_responses(dd);
747
748 /* And transmit the 2xx response */
749 status=pjsip_dlg_send_response(inv->dlg,
750 inv->invite_tsx, tdata);
751
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000752 } else {
Benny Prijono1f7767b2007-10-03 18:28:49 +0000753 /* We didn't send any reliable provisional response */
754
755 /* Transmit the 2xx response */
756 status=pjsip_dlg_send_response(inv->dlg,
757 inv->invite_tsx, tdata);
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000758 }
Benny Prijono1f7767b2007-10-03 18:28:49 +0000759
760 } else if (status_code >= 300) {
761
762 /*
763 RFC 3262 Section 3: UAS Behavior:
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000764
Benny Prijono1f7767b2007-10-03 18:28:49 +0000765 If the UAS does send a final response when reliable
766 responses are still unacknowledged, it SHOULD NOT
767 continue to retransmit the unacknowledged reliable
768 provisional responses, but it MUST be prepared to
769 process PRACK requests for those outstanding
770 responses.
771 */
772
773 /* Cancel the retransmit timer */
774 if (dd->uas_state && dd->uas_state->retransmit_timer.id) {
775 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt,
776 &dd->uas_state->retransmit_timer);
777 dd->uas_state->retransmit_timer.id = PJ_FALSE;
778
779 /* Clear all pending responses (drop 'em) */
780 clear_all_responses(dd);
781 }
782
783 /* And transmit the 2xx response */
784 status=pjsip_dlg_send_response(inv->dlg,
785 inv->invite_tsx, tdata);
786
787 } else {
788 /*
789 * This is provisional response.
790 */
791 char rseq_str[32];
792 pj_str_t rseq;
793 tx_data_list_t *tl;
794
795 /* Create UAS state if we don't have one */
796 if (dd->uas_state == NULL) {
797 dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool,
798 uas_state_t);
799 dd->uas_state->cseq = cseq_hdr->cseq;
800 dd->uas_state->rseq = pj_rand() % 0x7FFF;
801 pj_list_init(&dd->uas_state->tx_data_list);
802 dd->uas_state->retransmit_timer.user_data = dd;
803 dd->uas_state->retransmit_timer.cb = &on_retransmit;
804 }
805
806 /* Check that CSeq match */
807 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq,
808 PJ_EINVALIDOP);
809
810 /* Add Require header */
811 req_hdr = pjsip_require_hdr_create(tdata->pool);
812 req_hdr->count = 1;
813 req_hdr->values[0] = tag_100rel;
814 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr);
815
816 /* Add RSeq header */
817 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u",
818 dd->uas_state->rseq);
819 rseq = pj_str(rseq_str);
820 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool,
821 &RSEQ, &rseq);
822 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr);
823
824 /* Create list entry for this response */
825 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t);
826 tl->tdata = tdata;
827 tl->rseq = dd->uas_state->rseq++;
828
829 /* Add to queue if there's pending response, otherwise
830 * transmit immediately.
831 */
832 if (!pj_list_empty(&dd->uas_state->tx_data_list)) {
833
834 int code = tdata->msg->line.status.code;
835
836 /* Will send later */
837 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
838 status = PJ_SUCCESS;
839
840 PJ_LOG(4,(dd->inv->dlg->obj_name,
841 "Reliable %d response enqueued (%d pending)",
842 code, pj_list_size(&dd->uas_state->tx_data_list)));
843
844 } else {
845 pj_list_push_back(&dd->uas_state->tx_data_list, tl);
846
847 dd->uas_state->retransmit_count = 0;
848 on_retransmit(NULL, &dd->uas_state->retransmit_timer);
849 status = PJ_SUCCESS;
850 }
851
852 }
853
854 return status;
Benny Prijonodcfc0ba2007-09-30 16:50:27 +0000855}
856
857