Changeset 1469 for pjproject/trunk/pjsip/src/pjsip-ua/sip_100rel.c
- Timestamp:
- Oct 3, 2007 6:28:49 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsip-ua/sip_100rel.c
r1467 r1469 29 29 #include <pj/rand.h> 30 30 31 #if defined(PJSIP_HAS_100REL) && PJSIP_HAS_100REL!=032 33 31 #define THIS_FILE "sip_100rel.c" 34 32 33 /* PRACK method */ 34 PJ_DEF_DATA(const pjsip_method) pjsip_prack_method = 35 { 36 PJSIP_OTHER_METHOD, 37 { "PRACK", 5 } 38 }; 39 35 40 typedef struct dlg_data dlg_data; 36 41 … … 39 44 */ 40 45 static pj_status_t mod_100rel_load(pjsip_endpoint *endpt); 41 static void mod_100rel_on_tsx_state(pjsip_transaction*, pjsip_event*);42 46 43 47 static void handle_incoming_prack(dlg_data *dd, pjsip_transaction *tsx, … … 48 52 struct pj_timer_entry *entry); 49 53 50 51 /* PRACK method */52 const pjsip_method pjsip_prack_method =53 {54 PJSIP_OTHER_METHOD,55 { "PRACK", 5 }56 };57 54 58 55 const pj_str_t tag_100rel = { "100rel", 6 }; … … 81 78 NULL, /* on_tx_request. */ 82 79 NULL, /* on_tx_response() */ 83 &mod_100rel_on_tsx_state,/* on_tsx_state() */80 NULL, /* on_tsx_state() */ 84 81 } 85 82 … … 133 130 static pj_status_t mod_100rel_load(pjsip_endpoint *endpt) 134 131 { 135 mod_100rel.endpt = endpt; 136 pjsip_endpt_add_capability(endpt, &mod_100rel.mod, 137 PJSIP_H_ALLOW, NULL, 138 1, &pjsip_prack_method.name); 139 pjsip_endpt_add_capability(endpt, &mod_100rel.mod, 140 PJSIP_H_SUPPORTED, NULL, 141 1, &tag_100rel); 142 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 143 static 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 */ 173 PJ_DEF(const pjsip_method*) pjsip_get_prack_method(void) 174 { 175 return &pjsip_prack_method; 176 } 177 178 179 /* 180 * init module 181 */ 182 PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt) 183 { 184 if (mod_100rel.mod.id != -1) 143 185 return PJ_SUCCESS; 144 } 145 146 static pjsip_require_hdr *find_req_hdr(pjsip_msg *msg) 147 { 148 pjsip_require_hdr *hreq; 149 150 hreq = (pjsip_require_hdr*) 151 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, NULL); 152 153 while (hreq) { 154 unsigned i; 155 for (i=0; i<hreq->count; ++i) { 156 if (!pj_stricmp(&hreq->values[i], &tag_100rel)) { 157 return hreq; 158 } 159 } 160 161 if ((void*)hreq->next == (void*)&msg->hdr) 162 return NULL; 163 164 hreq = (pjsip_require_hdr*) 165 pjsip_msg_find_hdr(msg, PJSIP_H_REQUIRE, hreq->next); 166 167 } 168 169 return NULL; 170 } 171 172 static void mod_100rel_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) 173 { 174 pjsip_dialog *dlg; 175 dlg_data *dd; 176 177 dlg = pjsip_tsx_get_dlg(tsx); 178 if (!dlg) 179 return; 180 181 dd = (dlg_data*) dlg->mod_data[mod_100rel.mod.id]; 182 if (!dd) 183 return; 184 185 if (tsx->role == PJSIP_ROLE_UAS && 186 tsx->state == PJSIP_TSX_STATE_TRYING && 187 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0) 188 { 189 /* 190 * Handle incoming PRACK request. 191 */ 192 handle_incoming_prack(dd, tsx, e); 193 194 } else if (tsx->role == PJSIP_ROLE_UAC && 195 tsx->method.id == PJSIP_INVITE_METHOD && 196 e->type == PJSIP_EVENT_TSX_STATE && 197 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG && 198 e->body.tsx_state.src.rdata->msg_info.msg->line.status.code > 100 && 199 e->body.tsx_state.src.rdata->msg_info.msg->line.status.code < 200 && 200 e->body.tsx_state.src.rdata->msg_info.require != NULL) 201 { 202 /* 203 * Handle incoming provisional response which wants to 204 * be PRACK-ed 205 */ 206 207 if (find_req_hdr(e->body.tsx_state.src.rdata->msg_info.msg)) { 208 /* Received provisional response which needs to be 209 * PRACK-ed. 210 */ 211 handle_incoming_response(dd, tsx, e); 212 } 213 214 } else if (tsx->role == PJSIP_ROLE_UAC && 215 tsx->state == PJSIP_TSX_STATE_COMPLETED && 216 pjsip_method_cmp(&tsx->method, &pjsip_prack_method)==0) 217 { 218 /* 219 * Handle the status of outgoing PRACK request. 220 */ 221 if (tsx->status_code == PJSIP_SC_CALL_TSX_DOES_NOT_EXIST || 222 tsx->status_code == PJSIP_SC_REQUEST_TIMEOUT || 223 tsx->status_code == PJSIP_SC_TSX_TIMEOUT || 224 tsx->status_code == PJSIP_SC_TSX_TRANSPORT_ERROR) 225 { 226 /* These are fatal errors which should terminate 227 * the session AND dialog! 228 */ 229 PJ_TODO(TERMINATE_SESSION_ON_481); 230 } 231 232 } else if (tsx == dd->inv->invite_tsx && 233 tsx->role == PJSIP_ROLE_UAS && 234 tsx->state == PJSIP_TSX_STATE_TERMINATED) 235 { 236 /* Make sure we don't have pending transmission */ 237 if (dd->uas_state) { 238 pj_assert(!dd->uas_state->retransmit_timer.id); 239 pj_assert(pj_list_empty(&dd->uas_state->tx_data_list)); 240 } 241 } 242 } 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 */ 195 PJ_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 */ 216 PJ_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 */ 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) 234 { 235 dlg_data *dd; 236 pjsip_transaction *tsx; 237 pjsip_msg *msg; 238 pjsip_generic_string_hdr *rseq_hdr; 239 pjsip_generic_string_hdr *rack_hdr; 240 unsigned rseq; 241 pj_str_t rack; 242 char rack_buf[80]; 243 pjsip_tx_data *tdata; 244 pj_status_t status; 245 246 *p_tdata = NULL; 247 248 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 249 PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED); 250 251 tsx = pjsip_rdata_get_tsx(rdata); 252 msg = rdata->msg_info.msg; 253 254 /* Check our assumptions */ 255 pj_assert( tsx->role == PJSIP_ROLE_UAC && 256 tsx->method.id == PJSIP_INVITE_METHOD && 257 msg->line.status.code > 100 && 258 msg->line.status.code < 200); 259 260 261 /* Get the RSeq header */ 262 rseq_hdr = (pjsip_generic_string_hdr*) 263 pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL); 264 if (rseq_hdr == NULL) { 265 PJ_LOG(4,(dd->inv->dlg->obj_name, 266 "Ignoring provisional response with no RSeq header")); 267 return PJSIP_EMISSINGHDR; 268 } 269 rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue); 270 271 /* Create new UAC state if we don't have one */ 272 if (dd->uac_state == NULL) { 273 dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, 274 uac_state_t); 275 dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 276 dd->uac_state->rseq = rseq - 1; 277 } 278 279 /* If this is from new INVITE transaction, reset UAC state */ 280 if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) { 281 dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 282 dd->uac_state->rseq = rseq - 1; 283 } 284 285 /* Ignore provisional response retransmission */ 286 if (rseq <= dd->uac_state->rseq) { 287 /* This should have been handled before */ 288 return PJ_EIGNORED; 289 290 /* Ignore provisional response with out-of-order RSeq */ 291 } else if (rseq != dd->uac_state->rseq + 1) { 292 PJ_LOG(4,(dd->inv->dlg->obj_name, 293 "Ignoring provisional response because RSeq jump " 294 "(expecting %u, got %u)", 295 dd->uac_state->rseq+1, rseq)); 296 return PJ_EIGNORED; 297 } 298 299 /* Update our RSeq */ 300 dd->uac_state->rseq = rseq; 301 302 /* Create PRACK */ 303 status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method, 304 -1, &tdata); 305 if (status != PJ_SUCCESS) 306 return status; 307 308 /* Create RAck header */ 309 rack.ptr = rack_buf; 310 rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf), 311 "%u %u %.*s", 312 rseq, rdata->msg_info.cseq->cseq, 313 (int)tsx->method.name.slen, 314 tsx->method.name.ptr); 315 rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack); 316 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr); 317 318 /* Done */ 319 *p_tdata = tdata; 320 321 return PJ_SUCCESS; 322 } 323 324 325 /* 326 * Send PRACK request. 327 */ 328 PJ_DEF(pj_status_t) pjsip_100rel_send_prack( pjsip_inv_session *inv, 329 pjsip_tx_data *tdata) 330 { 331 dlg_data *dd; 332 333 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 334 PJ_ASSERT_ON_FAIL(dd != NULL, 335 {pjsip_tx_data_dec_ref(tdata); return PJSIP_ENOTINITIALIZED; }); 336 337 return pjsip_dlg_send_request(inv->dlg, tdata, 338 mod_100rel.mod.id, (void*) dd); 339 340 } 341 342 343 /* 344 * Notify 100rel module that the invite session has been disconnected. 345 */ 346 PJ_DEF(pj_status_t) pjsip_100rel_end_session(pjsip_inv_session *inv) 347 { 348 dlg_data *dd; 349 350 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 351 if (!dd) 352 return PJ_SUCCESS; 353 354 /* Make sure we don't have pending transmission */ 355 if (dd->uas_state) { 356 pj_assert(!dd->uas_state->retransmit_timer.id); 357 pj_assert(pj_list_empty(&dd->uas_state->tx_data_list)); 358 } 359 360 return PJ_SUCCESS; 361 } 362 243 363 244 364 static void parse_rack(const pj_str_t *rack, … … 246 366 pj_str_t *p_method) 247 367 { 248 const char *p = rack->ptr, *end = p + rack->slen; 249 pj_str_t token; 250 251 token.ptr = (char*)p; 252 while (p < end && pj_isdigit(*p)) 253 ++p; 254 token.slen = p - token.ptr; 255 *p_rseq = pj_strtoul(&token); 256 368 const char *p = rack->ptr, *end = p + rack->slen; 369 pj_str_t token; 370 371 token.ptr = (char*)p; 372 while (p < end && pj_isdigit(*p)) 257 373 ++p; 258 token.ptr = (char*)p;259 while (p < end && pj_isdigit(*p)) 260 ++p; 261 token.slen = p - token.ptr;262 *p_seq = pj_strtoul(&token);263 374 token.slen = p - token.ptr; 375 *p_rseq = pj_strtoul(&token); 376 377 ++p; 378 token.ptr = (char*)p; 379 while (p < end && pj_isdigit(*p)) 264 380 ++p; 265 if (p < end) { 266 p_method->ptr = (char*)p; 267 p_method->slen = end - p; 268 } else { 269 p_method->ptr = NULL; 270 p_method->slen = 0; 271 } 381 token.slen = p - token.ptr; 382 *p_seq = pj_strtoul(&token); 383 384 ++p; 385 if (p < end) { 386 p_method->ptr = (char*)p; 387 p_method->slen = end - p; 388 } else { 389 p_method->ptr = NULL; 390 p_method->slen = 0; 391 } 272 392 } 273 393 … … 275 395 static void clear_all_responses(dlg_data *dd) 276 396 { 277 tx_data_list_t *tl; 278 279 tl = dd->uas_state->tx_data_list.next; 280 while (tl != &dd->uas_state->tx_data_list) { 281 pjsip_tx_data_dec_ref(tl->tdata); 282 tl = tl->next; 397 tx_data_list_t *tl; 398 399 tl = dd->uas_state->tx_data_list.next; 400 while (tl != &dd->uas_state->tx_data_list) { 401 pjsip_tx_data_dec_ref(tl->tdata); 402 tl = tl->next; 403 } 404 pj_list_init(&dd->uas_state->tx_data_list); 405 } 406 407 408 /* 409 * Handle incoming PRACK request. 410 */ 411 PJ_DEF(pj_status_t) pjsip_100rel_on_rx_prack( pjsip_inv_session *inv, 412 pjsip_rx_data *rdata) 413 { 414 dlg_data *dd; 415 pjsip_transaction *tsx; 416 pjsip_msg *msg; 417 pjsip_generic_string_hdr *rack_hdr; 418 pjsip_tx_data *tdata; 419 pj_uint32_t rseq; 420 pj_int32_t cseq; 421 pj_str_t method; 422 pj_status_t status; 423 424 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 425 PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED); 426 427 tsx = pjsip_rdata_get_tsx(rdata); 428 pj_assert(tsx != NULL); 429 430 msg = rdata->msg_info.msg; 431 432 /* Always reply with 200/OK for PRACK */ 433 status = pjsip_dlg_create_response(inv->dlg, rdata, 200, NULL, &tdata); 434 if (status == PJ_SUCCESS) { 435 status = pjsip_dlg_send_response(inv->dlg, tsx, tdata); 436 } 437 438 /* Ignore if we don't have pending transmission */ 439 if (dd->uas_state == NULL || pj_list_empty(&dd->uas_state->tx_data_list)) { 440 PJ_LOG(4,(dd->inv->dlg->obj_name, 441 "PRACK ignored - no pending response")); 442 return PJ_EIGNORED; 443 } 444 445 /* Find RAck header */ 446 rack_hdr = (pjsip_generic_string_hdr*) 447 pjsip_msg_find_hdr_by_name(msg, &RACK, NULL); 448 if (!rack_hdr) { 449 /* RAck header not found */ 450 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header")); 451 return PJSIP_EMISSINGHDR; 452 } 453 454 /* Parse RAck header */ 455 parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method); 456 457 458 /* Match RAck against outgoing transmission */ 459 if (rseq == dd->uas_state->tx_data_list.next->rseq && 460 cseq == dd->uas_state->cseq) 461 { 462 /* 463 * Yes this PRACK matches outgoing transmission. 464 */ 465 tx_data_list_t *tl = dd->uas_state->tx_data_list.next; 466 467 if (dd->uas_state->retransmit_timer.id) { 468 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 469 &dd->uas_state->retransmit_timer); 470 dd->uas_state->retransmit_timer.id = PJ_FALSE; 283 471 } 284 pj_list_init(&dd->uas_state->tx_data_list); 285 } 286 287 288 static void handle_incoming_prack(dlg_data *dd, pjsip_transaction *tsx, 289 pjsip_event *e) 290 { 291 pjsip_rx_data *rdata; 292 pjsip_msg *msg; 293 pjsip_generic_string_hdr *rack_hdr; 294 pjsip_tx_data *tdata; 295 pj_uint32_t rseq; 296 pj_int32_t cseq; 297 pj_str_t method; 298 pj_status_t status; 299 300 301 rdata = e->body.tsx_state.src.rdata; 302 msg = rdata->msg_info.msg; 303 304 /* Always reply with 200/OK for PRACK */ 305 status = pjsip_endpt_create_response(tsx->endpt, rdata, 306 200, NULL, &tdata); 307 if (status == PJ_SUCCESS) 308 pjsip_tsx_send_msg(tsx, tdata); 309 310 /* Ignore if we don't have pending transmission */ 311 if (dd->uas_state == NULL || 312 pj_list_empty(&dd->uas_state->tx_data_list)) 313 { 314 PJ_LOG(4,(dd->inv->dlg->obj_name, 315 "PRACK ignored - no pending response")); 316 return; 472 473 /* Remove from the list */ 474 if (tl != &dd->uas_state->tx_data_list) { 475 pj_list_erase(tl); 476 477 /* Destroy the response */ 478 pjsip_tx_data_dec_ref(tl->tdata); 317 479 } 318 480 319 /* Find RAck header */ 320 rack_hdr = (pjsip_generic_string_hdr*) 321 pjsip_msg_find_hdr_by_name(msg, &RACK, NULL); 322 if (!rack_hdr) { 323 /* RAck header not found */ 324 PJ_LOG(4,(dd->inv->dlg->obj_name, "No RAck header")); 325 return; 481 /* Schedule next packet */ 482 dd->uas_state->retransmit_count = 0; 483 if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 484 on_retransmit(NULL, &dd->uas_state->retransmit_timer); 326 485 } 327 parse_rack(&rack_hdr->hvalue, &rseq, &cseq, &method); 328 329 /* Match RAck against outgoing transmission */ 330 if (rseq == dd->uas_state->tx_data_list.next->rseq && 331 cseq == dd->uas_state->cseq) 332 { 333 tx_data_list_t *tl = dd->uas_state->tx_data_list.next; 334 335 /* Yes it match! */ 336 if (dd->uas_state->retransmit_timer.id) { 337 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 338 &dd->uas_state->retransmit_timer); 339 dd->uas_state->retransmit_timer.id = PJ_FALSE; 340 } 341 342 /* Remove from the list */ 343 if (tl != &dd->uas_state->tx_data_list) { 344 pj_list_erase(tl); 345 346 /* Destroy the response */ 347 pjsip_tx_data_dec_ref(tl->tdata); 348 } 349 350 /* Schedule next packet */ 351 dd->uas_state->retransmit_count = 0; 352 if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 353 on_retransmit(NULL, &dd->uas_state->retransmit_timer); 354 } 355 356 } else { 357 /* No it doesn't match */ 358 PJ_LOG(4,(dd->inv->dlg->obj_name, 359 "Rx PRACK with no matching reliable response")); 360 } 361 } 362 363 364 /* 365 * Handle incoming provisional response with 100rel requirement. 366 * In this case we shall transmit PRACK request. 367 */ 368 static void handle_incoming_response(dlg_data *dd, pjsip_transaction *tsx, 369 pjsip_event *e) 370 { 371 pjsip_rx_data *rdata; 372 pjsip_msg *msg; 373 pjsip_generic_string_hdr *rseq_hdr; 374 pjsip_generic_string_hdr *rack_hdr; 375 unsigned rseq; 376 pj_str_t rack; 377 char rack_buf[80]; 378 pjsip_tx_data *tdata; 379 pj_status_t status; 380 381 rdata = e->body.tsx_state.src.rdata; 382 msg = rdata->msg_info.msg; 383 384 /* Check our assumptions */ 385 pj_assert( tsx->role == PJSIP_ROLE_UAC && 386 tsx->method.id == PJSIP_INVITE_METHOD && 387 e->type == PJSIP_EVENT_TSX_STATE && 388 e->body.tsx_state.type == PJSIP_EVENT_RX_MSG && 389 msg->line.status.code > 100 && 390 msg->line.status.code < 200); 391 392 393 /* Get the RSeq header */ 394 rseq_hdr = (pjsip_generic_string_hdr*) 395 pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL); 396 if (rseq_hdr == NULL) { 397 PJ_LOG(4,(dd->inv->dlg->obj_name, 398 "Ignoring provisional response with no RSeq header")); 399 return; 400 } 401 rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue); 402 403 /* Create new UAC state if we don't have one */ 404 if (dd->uac_state == NULL) { 405 dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, 406 uac_state_t); 407 dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 408 dd->uac_state->rseq = rseq - 1; 409 } 410 411 /* If this is from new INVITE transaction, reset UAC state */ 412 if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) { 413 dd->uac_state->cseq = rdata->msg_info.cseq->cseq; 414 dd->uac_state->rseq = rseq - 1; 415 } 416 417 /* Ignore provisional response retransmission */ 418 if (rseq <= dd->uac_state->rseq) { 419 /* This should have been handled before */ 420 return; 421 422 /* Ignore provisional response with out-of-order RSeq */ 423 } else if (rseq != dd->uac_state->rseq + 1) { 424 PJ_LOG(4,(dd->inv->dlg->obj_name, 425 "Ignoring provisional response because RSeq jump " 426 "(expecting %u, got %u)", 427 dd->uac_state->rseq+1, rseq)); 428 return; 429 } 430 431 /* Update our RSeq */ 432 dd->uac_state->rseq = rseq; 433 434 /* Create PRACK */ 435 status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method, 436 -1, &tdata); 437 if (status != PJ_SUCCESS) { 438 PJ_LOG(4,(dd->inv->dlg->obj_name, 439 "Error creating PRACK request (status=%d)", status)); 440 return; 441 } 442 443 /* Create RAck header */ 444 rack.ptr = rack_buf; 445 rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf), 446 "%u %u %.*s", 447 rseq, rdata->msg_info.cseq->cseq, 448 (int)tsx->method.name.slen, 449 tsx->method.name.ptr); 450 PJ_ASSERT_ON_FAIL(rack.slen > 0 && rack.slen < (int)sizeof(rack_buf), 451 { pjsip_tx_data_dec_ref(tdata); return; }); 452 rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack); 453 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr); 454 455 /* Send PRACK */ 456 pjsip_dlg_send_request(dd->inv->dlg, tdata, 457 mod_100rel.mod.id, (void*) dd); 458 459 } 460 461 462 /* 463 * API: init module 464 */ 465 PJ_DEF(pj_status_t) pjsip_100rel_init_module(pjsip_endpoint *endpt) 466 { 467 return pjsip_endpt_register_module(endpt, &mod_100rel.mod); 468 } 469 470 471 /* 472 * API: attach 100rel support in invite session. Called by 473 * sip_inv.c 474 */ 475 PJ_DEF(pj_status_t) pjsip_100rel_attach(pjsip_inv_session *inv) 476 { 477 dlg_data *dd; 478 479 /* Check that 100rel module has been initialized */ 480 PJ_ASSERT_RETURN(mod_100rel.mod.id >= 0, PJ_EINVALIDOP); 481 482 /* Create and attach as dialog usage */ 483 dd = PJ_POOL_ZALLOC_T(inv->dlg->pool, dlg_data); 484 dd->inv = inv; 485 pjsip_dlg_add_usage(inv->dlg, &mod_100rel.mod, (void*)dd); 486 487 PJ_LOG(5,(dd->inv->dlg->obj_name, "100rel module attached")); 488 489 return PJ_SUCCESS; 486 487 } else { 488 /* No it doesn't match */ 489 PJ_LOG(4,(dd->inv->dlg->obj_name, 490 "Rx PRACK with no matching reliable response")); 491 return PJ_EIGNORED; 492 } 493 494 return PJ_SUCCESS; 490 495 } 491 496 … … 498 503 struct pj_timer_entry *entry) 499 504 { 500 dlg_data *dd; 501 tx_data_list_t *tl; 502 pjsip_tx_data *tdata; 503 pj_bool_t final; 504 pj_time_val delay; 505 506 PJ_UNUSED_ARG(timer_heap); 507 508 dd = (dlg_data*) entry->user_data; 509 510 entry->id = PJ_FALSE; 511 512 ++dd->uas_state->retransmit_count; 513 if (dd->uas_state->retransmit_count >= 7) { 514 /* If a reliable provisional response is retransmitted for 515 64*T1 seconds without reception of a corresponding PRACK, 516 the UAS SHOULD reject the original request with a 5xx 517 response. 518 */ 519 pj_str_t reason = pj_str("Reliable response timed out"); 520 pj_status_t status; 521 522 /* Clear all pending responses */ 523 clear_all_responses(dd); 524 525 /* Send 500 response */ 526 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata); 527 if (status == PJ_SUCCESS) { 528 pjsip_dlg_send_response(dd->inv->dlg, 529 dd->inv->invite_tsx, 530 tdata); 531 } 532 return; 505 dlg_data *dd; 506 tx_data_list_t *tl; 507 pjsip_tx_data *tdata; 508 pj_bool_t final; 509 pj_time_val delay; 510 511 PJ_UNUSED_ARG(timer_heap); 512 513 dd = (dlg_data*) entry->user_data; 514 515 entry->id = PJ_FALSE; 516 517 ++dd->uas_state->retransmit_count; 518 if (dd->uas_state->retransmit_count >= 7) { 519 /* If a reliable provisional response is retransmitted for 520 64*T1 seconds without reception of a corresponding PRACK, 521 the UAS SHOULD reject the original request with a 5xx 522 response. 523 */ 524 pj_str_t reason = pj_str("Reliable response timed out"); 525 pj_status_t status; 526 527 /* Clear all pending responses */ 528 clear_all_responses(dd); 529 530 /* Send 500 response */ 531 status = pjsip_inv_end_session(dd->inv, 500, &reason, &tdata); 532 if (status == PJ_SUCCESS) { 533 pjsip_dlg_send_response(dd->inv->dlg, 534 dd->inv->invite_tsx, 535 tdata); 533 536 } 534 535 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list)); 536 tl = dd->uas_state->tx_data_list.next; 537 tdata = tl->tdata; 538 539 pjsip_tx_data_add_ref(tdata); 540 final = tdata->msg->line.status.code >= 200; 541 542 if (dd->uas_state->retransmit_count == 1) { 543 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata); 544 } else { 545 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata); 546 } 547 548 if (final) { 549 /* This is final response, which will be retransmitted by 550 * UA layer. There's no more task to do, so clear the 551 * transmission list and bail out. 552 */ 553 clear_all_responses(dd); 554 return; 555 } 556 557 /* Schedule next retransmission */ 558 if (dd->uas_state->retransmit_count < 6) { 559 delay.sec = 0; 560 delay.msec = (1 << dd->uas_state->retransmit_count) * 561 PJSIP_T1_TIMEOUT; 562 pj_time_val_normalize(&delay); 563 } else { 564 delay.sec = 1; 565 delay.msec = 500; 566 } 567 568 569 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt, 570 &dd->uas_state->retransmit_timer, 571 &delay); 572 573 entry->id = PJ_TRUE; 574 } 537 return; 538 } 539 540 pj_assert(!pj_list_empty(&dd->uas_state->tx_data_list)); 541 tl = dd->uas_state->tx_data_list.next; 542 tdata = tl->tdata; 543 544 pjsip_tx_data_add_ref(tdata); 545 final = tdata->msg->line.status.code >= 200; 546 547 if (dd->uas_state->retransmit_count == 1) { 548 pjsip_tsx_send_msg(dd->inv->invite_tsx, tdata); 549 } else { 550 pjsip_tsx_retransmit_no_state(dd->inv->invite_tsx, tdata); 551 } 552 553 if (final) { 554 /* This is final response, which will be retransmitted by 555 * UA layer. There's no more task to do, so clear the 556 * transmission list and bail out. 557 */ 558 clear_all_responses(dd); 559 return; 560 } 561 562 /* Schedule next retransmission */ 563 if (dd->uas_state->retransmit_count < 6) { 564 delay.sec = 0; 565 delay.msec = (1 << dd->uas_state->retransmit_count) * 566 PJSIP_T1_TIMEOUT; 567 pj_time_val_normalize(&delay); 568 } else { 569 delay.sec = 1; 570 delay.msec = 500; 571 } 572 573 574 pjsip_endpt_schedule_timer(dd->inv->dlg->endpt, 575 &dd->uas_state->retransmit_timer, 576 &delay); 577 578 entry->id = PJ_TRUE; 579 } 580 575 581 576 582 /* Clone response. */ … … 578 584 const pjsip_tx_data *src) 579 585 { 580 pjsip_tx_data *dst; 581 const pjsip_hdr *hsrc; 582 pjsip_msg *msg; 583 pj_status_t status; 584 585 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst); 586 if (status != PJ_SUCCESS) 587 return NULL; 588 589 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG); 590 dst->msg = msg; 591 pjsip_tx_data_add_ref(dst); 592 593 /* Duplicate status line */ 594 msg->line.status.code = src->msg->line.status.code; 595 pj_strdup(dst->pool, &msg->line.status.reason, 596 &src->msg->line.status.reason); 597 598 /* Duplicate all headers */ 599 hsrc = src->msg->hdr.next; 600 while (hsrc != &src->msg->hdr) { 601 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc); 602 pjsip_msg_add_hdr(msg, h); 603 hsrc = hsrc->next; 604 } 605 606 /* Duplicate message body */ 607 if (src->msg->body) 608 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body); 609 610 PJ_LOG(5,(dd->inv->dlg->obj_name, 611 "Reliable response %s created", 612 pjsip_tx_data_get_info(dst))); 613 614 return dst; 615 } 616 617 /* Check if pending response has SDP */ 586 pjsip_tx_data *dst; 587 const pjsip_hdr *hsrc; 588 pjsip_msg *msg; 589 pj_status_t status; 590 591 status = pjsip_endpt_create_tdata(dd->inv->dlg->endpt, &dst); 592 if (status != PJ_SUCCESS) 593 return NULL; 594 595 msg = pjsip_msg_create(dst->pool, PJSIP_RESPONSE_MSG); 596 dst->msg = msg; 597 pjsip_tx_data_add_ref(dst); 598 599 /* Duplicate status line */ 600 msg->line.status.code = src->msg->line.status.code; 601 pj_strdup(dst->pool, &msg->line.status.reason, 602 &src->msg->line.status.reason); 603 604 /* Duplicate all headers */ 605 hsrc = src->msg->hdr.next; 606 while (hsrc != &src->msg->hdr) { 607 pjsip_hdr *h = (pjsip_hdr*) pjsip_hdr_clone(dst->pool, hsrc); 608 pjsip_msg_add_hdr(msg, h); 609 hsrc = hsrc->next; 610 } 611 612 /* Duplicate message body */ 613 if (src->msg->body) 614 msg->body = pjsip_msg_body_clone(dst->pool, src->msg->body); 615 616 PJ_LOG(5,(dd->inv->dlg->obj_name, 617 "Reliable response %s created", 618 pjsip_tx_data_get_info(dst))); 619 620 return dst; 621 } 622 623 624 /* Check if any pending response in transmission list has SDP */ 618 625 static pj_bool_t has_sdp(dlg_data *dd) 619 626 { 620 621 622 623 624 625 626 627 628 629 627 tx_data_list_t *tl; 628 629 tl = dd->uas_state->tx_data_list.next; 630 while (tl != &dd->uas_state->tx_data_list) { 631 if (tl->tdata->msg->body) 632 return PJ_TRUE; 633 tl = tl->next; 634 } 635 636 return PJ_FALSE; 630 637 } 631 638 … … 635 642 pjsip_tx_data *tdata) 636 643 { 637 pjsip_cseq_hdr *cseq_hdr; 638 pjsip_generic_string_hdr *rseq_hdr; 639 pjsip_require_hdr *req_hdr; 640 int status_code; 641 dlg_data *dd; 642 pjsip_tx_data *old_tdata; 643 pj_status_t status; 644 645 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG, 644 pjsip_cseq_hdr *cseq_hdr; 645 pjsip_generic_string_hdr *rseq_hdr; 646 pjsip_require_hdr *req_hdr; 647 int status_code; 648 dlg_data *dd; 649 pjsip_tx_data *old_tdata; 650 pj_status_t status; 651 652 PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_RESPONSE_MSG, 653 PJSIP_ENOTRESPONSEMSG); 654 655 status_code = tdata->msg->line.status.code; 656 657 /* 100 response doesn't need PRACK */ 658 if (status_code == 100) 659 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata); 660 661 662 /* Get the 100rel data attached to this dialog */ 663 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 664 PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP); 665 666 667 /* Clone tdata. 668 * We need to clone tdata because we may need to keep it in our 669 * retransmission list, while the original dialog may modify it 670 * if it wants to send another response. 671 */ 672 old_tdata = tdata; 673 tdata = clone_tdata(dd, old_tdata); 674 pjsip_tx_data_dec_ref(old_tdata); 675 676 677 /* Get CSeq header, and make sure this is INVITE response */ 678 cseq_hdr = (pjsip_cseq_hdr*) 679 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); 680 PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG); 681 PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD, 682 PJ_EINVALIDOP); 683 684 /* Remove existing Require header */ 685 req_hdr = find_req_hdr(tdata->msg); 686 if (req_hdr) { 687 pj_list_erase(req_hdr); 688 } 689 690 /* Remove existing RSeq header */ 691 rseq_hdr = (pjsip_generic_string_hdr*) 692 pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL); 693 if (rseq_hdr) 694 pj_list_erase(rseq_hdr); 695 696 /* Different treatment for provisional and final response */ 697 if (status_code/100 == 2) { 698 699 /* RFC 3262 Section 3: UAS Behavior: 700 701 The UAS MAY send a final response to the initial request 702 before having received PRACKs for all unacknowledged 703 reliable provisional responses, unless the final response 704 is 2xx and any of the unacknowledged reliable provisional 705 responses contained a session description. In that case, 706 it MUST NOT send a final response until those provisional 707 responses are acknowledged. 708 */ 709 710 if (dd->uas_state && has_sdp(dd)) { 711 /* Yes we have transmitted 1xx with SDP reliably. 712 * In this case, must queue the 2xx response. 713 */ 714 tx_data_list_t *tl; 715 716 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 717 tl->tdata = tdata; 718 tl->rseq = (pj_uint32_t)-1; 719 pj_list_push_back(&dd->uas_state->tx_data_list, tl); 720 721 /* Will send later */ 722 status = PJ_SUCCESS; 723 724 PJ_LOG(4,(dd->inv->dlg->obj_name, 725 "2xx response will be sent after PRACK")); 726 727 } else if (dd->uas_state) { 728 /* 729 RFC 3262 Section 3: UAS Behavior: 730 731 If the UAS does send a final response when reliable 732 responses are still unacknowledged, it SHOULD NOT 733 continue to retransmit the unacknowledged reliable 734 provisional responses, but it MUST be prepared to 735 process PRACK requests for those outstanding 736 responses. 737 */ 738 739 PJ_LOG(4,(dd->inv->dlg->obj_name, 740 "No SDP sent so far, sending 2xx now")); 741 742 /* Cancel the retransmit timer */ 743 if (dd->uas_state->retransmit_timer.id) { 744 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 745 &dd->uas_state->retransmit_timer); 746 dd->uas_state->retransmit_timer.id = PJ_FALSE; 747 } 748 749 /* Clear all pending responses (drop 'em) */ 750 clear_all_responses(dd); 751 752 /* And transmit the 2xx response */ 753 status=pjsip_dlg_send_response(inv->dlg, 754 inv->invite_tsx, tdata); 755 756 } else { 757 /* We didn't send any reliable provisional response */ 758 759 /* Transmit the 2xx response */ 760 status=pjsip_dlg_send_response(inv->dlg, 761 inv->invite_tsx, tdata); 762 } 763 764 } else if (status_code >= 300) { 765 766 /* 767 RFC 3262 Section 3: UAS Behavior: 768 769 If the UAS does send a final response when reliable 770 responses are still unacknowledged, it SHOULD NOT 771 continue to retransmit the unacknowledged reliable 772 provisional responses, but it MUST be prepared to 773 process PRACK requests for those outstanding 774 responses. 775 */ 776 777 /* Cancel the retransmit timer */ 778 if (dd->uas_state && dd->uas_state->retransmit_timer.id) { 779 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 780 &dd->uas_state->retransmit_timer); 781 dd->uas_state->retransmit_timer.id = PJ_FALSE; 782 783 /* Clear all pending responses (drop 'em) */ 784 clear_all_responses(dd); 785 } 786 787 /* And transmit the 2xx response */ 788 status=pjsip_dlg_send_response(inv->dlg, 789 inv->invite_tsx, tdata); 790 791 } else { 792 /* 793 * This is provisional response. 794 */ 795 char rseq_str[32]; 796 pj_str_t rseq; 797 tx_data_list_t *tl; 798 799 /* Create UAS state if we don't have one */ 800 if (dd->uas_state == NULL) { 801 dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool, 802 uas_state_t); 803 dd->uas_state->cseq = cseq_hdr->cseq; 804 dd->uas_state->rseq = pj_rand() % 0x7FFF; 805 pj_list_init(&dd->uas_state->tx_data_list); 806 dd->uas_state->retransmit_timer.user_data = dd; 807 dd->uas_state->retransmit_timer.cb = &on_retransmit; 808 } 809 810 /* Check that CSeq match */ 811 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq, 646 812 PJ_EINVALIDOP); 647 648 status_code = tdata->msg->line.status.code; 649 650 /* 100 response doesn't need PRACK */ 651 if (status_code == 100) 652 return pjsip_dlg_send_response(inv->dlg, inv->invite_tsx, tdata); 653 654 /* Get the dialog data */ 655 dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id]; 656 PJ_ASSERT_RETURN(dd != NULL, PJ_EINVALIDOP); 657 658 659 /* Clone tdata */ 660 old_tdata = tdata; 661 tdata = clone_tdata(dd, old_tdata); 662 pjsip_tx_data_dec_ref(old_tdata); 663 664 /* Get CSeq header */ 665 cseq_hdr = (pjsip_cseq_hdr*) 666 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL); 667 PJ_ASSERT_RETURN(cseq_hdr != NULL, PJ_EBUG); 668 PJ_ASSERT_RETURN(cseq_hdr->method.id == PJSIP_INVITE_METHOD, 669 PJ_EINVALIDOP); 670 671 /* Remove existing Require header */ 672 req_hdr = find_req_hdr(tdata->msg); 673 if (req_hdr) { 674 pj_list_erase(req_hdr); 813 814 /* Add Require header */ 815 req_hdr = pjsip_require_hdr_create(tdata->pool); 816 req_hdr->count = 1; 817 req_hdr->values[0] = tag_100rel; 818 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr); 819 820 /* Add RSeq header */ 821 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u", 822 dd->uas_state->rseq); 823 rseq = pj_str(rseq_str); 824 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool, 825 &RSEQ, &rseq); 826 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr); 827 828 /* Create list entry for this response */ 829 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 830 tl->tdata = tdata; 831 tl->rseq = dd->uas_state->rseq++; 832 833 /* Add to queue if there's pending response, otherwise 834 * transmit immediately. 835 */ 836 if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 837 838 int code = tdata->msg->line.status.code; 839 840 /* Will send later */ 841 pj_list_push_back(&dd->uas_state->tx_data_list, tl); 842 status = PJ_SUCCESS; 843 844 PJ_LOG(4,(dd->inv->dlg->obj_name, 845 "Reliable %d response enqueued (%d pending)", 846 code, pj_list_size(&dd->uas_state->tx_data_list))); 847 848 } else { 849 pj_list_push_back(&dd->uas_state->tx_data_list, tl); 850 851 dd->uas_state->retransmit_count = 0; 852 on_retransmit(NULL, &dd->uas_state->retransmit_timer); 853 status = PJ_SUCCESS; 675 854 } 676 677 /* Remove existing RSeq header */ 678 rseq_hdr = (pjsip_generic_string_hdr*) 679 pjsip_msg_find_hdr_by_name(tdata->msg, &RSEQ, NULL); 680 if (rseq_hdr) 681 pj_list_erase(rseq_hdr); 682 683 /* Different treatment for provisional and final response */ 684 if (status_code/100 == 2) { 685 686 /* RFC 3262 Section 3: UAS Behavior: 687 688 The UAS MAY send a final response to the initial request 689 before having received PRACKs for all unacknowledged 690 reliable provisional responses, unless the final response 691 is 2xx and any of the unacknowledged reliable provisional 692 responses contained a session description. In that case, 693 it MUST NOT send a final response until those provisional 694 responses are acknowledged. 695 */ 696 697 if (dd->uas_state && has_sdp(dd)) { 698 /* Yes we have transmitted 1xx with SDP reliably. 699 * In this case, must queue the 2xx response. 700 */ 701 tx_data_list_t *tl; 702 703 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 704 tl->tdata = tdata; 705 tl->rseq = (pj_uint32_t)-1; 706 pj_list_push_back(&dd->uas_state->tx_data_list, tl); 707 708 /* Will send later */ 709 status = PJ_SUCCESS; 710 711 PJ_LOG(4,(dd->inv->dlg->obj_name, 712 "2xx response will be sent after PRACK")); 713 714 } else if (dd->uas_state) { 715 /* 716 If the UAS does send a final response when reliable 717 responses are still unacknowledged, it SHOULD NOT 718 continue to retransmit the unacknowledged reliable 719 provisional responses, but it MUST be prepared to 720 process PRACK requests for those outstanding 721 responses. 722 */ 723 724 PJ_LOG(4,(dd->inv->dlg->obj_name, 725 "No SDP sent so far, sending 2xx now")); 726 727 /* Cancel the retransmit timer */ 728 if (dd->uas_state->retransmit_timer.id) { 729 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 730 &dd->uas_state->retransmit_timer); 731 dd->uas_state->retransmit_timer.id = PJ_FALSE; 732 } 733 734 /* Clear all pending responses (drop 'em) */ 735 clear_all_responses(dd); 736 737 /* And transmit the 2xx response */ 738 status=pjsip_dlg_send_response(inv->dlg, 739 inv->invite_tsx, tdata); 740 741 } else { 742 /* We didn't send any reliable provisional response */ 743 744 /* Transmit the 2xx response */ 745 status=pjsip_dlg_send_response(inv->dlg, 746 inv->invite_tsx, tdata); 747 } 748 749 } else if (status_code >= 300) { 750 751 /* 752 If the UAS does send a final response when reliable 753 responses are still unacknowledged, it SHOULD NOT 754 continue to retransmit the unacknowledged reliable 755 provisional responses, but it MUST be prepared to 756 process PRACK requests for those outstanding 757 responses. 758 */ 759 760 /* Cancel the retransmit timer */ 761 if (dd->uas_state && dd->uas_state->retransmit_timer.id) { 762 pjsip_endpt_cancel_timer(dd->inv->dlg->endpt, 763 &dd->uas_state->retransmit_timer); 764 dd->uas_state->retransmit_timer.id = PJ_FALSE; 765 766 /* Clear all pending responses (drop 'em) */ 767 clear_all_responses(dd); 768 } 769 770 /* And transmit the 2xx response */ 771 status=pjsip_dlg_send_response(inv->dlg, 772 inv->invite_tsx, tdata); 773 774 } else { 775 /* 776 * This is provisional response. 777 */ 778 char rseq_str[32]; 779 pj_str_t rseq; 780 tx_data_list_t *tl; 781 782 /* Create UAS state if we don't have one */ 783 if (dd->uas_state == NULL) { 784 dd->uas_state = PJ_POOL_ZALLOC_T(inv->dlg->pool, 785 uas_state_t); 786 dd->uas_state->cseq = cseq_hdr->cseq; 787 dd->uas_state->rseq = pj_rand() % 0x7FFF; 788 pj_list_init(&dd->uas_state->tx_data_list); 789 dd->uas_state->retransmit_timer.user_data = dd; 790 dd->uas_state->retransmit_timer.cb = &on_retransmit; 791 } 792 793 /* Check that CSeq match */ 794 PJ_ASSERT_RETURN(cseq_hdr->cseq == dd->uas_state->cseq, 795 PJ_EINVALIDOP); 796 797 /* Add Require header */ 798 req_hdr = pjsip_require_hdr_create(tdata->pool); 799 req_hdr->count = 1; 800 req_hdr->values[0] = tag_100rel; 801 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)req_hdr); 802 803 /* Add RSeq header */ 804 pj_ansi_snprintf(rseq_str, sizeof(rseq_str), "%u", 805 dd->uas_state->rseq); 806 rseq = pj_str(rseq_str); 807 rseq_hdr = pjsip_generic_string_hdr_create(tdata->pool, 808 &RSEQ, &rseq); 809 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)rseq_hdr); 810 811 /* Create list entry for this response */ 812 tl = PJ_POOL_ZALLOC_T(tdata->pool, tx_data_list_t); 813 tl->tdata = tdata; 814 tl->rseq = dd->uas_state->rseq++; 815 816 /* Add to queue if there's pending response, otherwise 817 * transmit immediately. 818 */ 819 if (!pj_list_empty(&dd->uas_state->tx_data_list)) { 820 821 int code = tdata->msg->line.status.code; 822 823 /* Will send later */ 824 pj_list_push_back(&dd->uas_state->tx_data_list, tl); 825 status = PJ_SUCCESS; 826 827 PJ_LOG(4,(dd->inv->dlg->obj_name, 828 "Reliable %d response enqueued (%d pending)", 829 code, pj_list_size(&dd->uas_state->tx_data_list))); 830 831 } else { 832 pj_list_push_back(&dd->uas_state->tx_data_list, tl); 833 834 dd->uas_state->retransmit_count = 0; 835 on_retransmit(NULL, &dd->uas_state->retransmit_timer); 836 status = PJ_SUCCESS; 837 } 838 839 } 840 841 return status; 842 } 843 844 845 #endif /* PJSIP_HAS_100REL */ 855 856 } 857 858 return status; 859 } 860 861
Note: See TracChangeset
for help on using the changeset viewer.