Changeset 106 for pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
- Timestamp:
- Dec 30, 2005 11:50:15 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
r105 r106 30 30 #include <pj/pool.h> 31 31 #include <pj/assert.h> 32 33 #if 0 // XXX JUNK 34 /* Initialize TLS ID for transaction lock. */ 35 status = pj_thread_local_alloc(&pjsip_tsx_lock_tls_id); 36 if (status != PJ_SUCCESS) { 37 goto on_error; 38 } 39 pj_thread_local_set(pjsip_tsx_lock_tls_id, NULL); 40 41 42 /* Create hash table for transaction. */ 43 endpt->tsx_table = pj_hash_create( endpt->pool, PJSIP_MAX_TSX_COUNT ); 44 if (!endpt->tsx_table) { 45 status = PJ_ENOMEM; 46 goto on_error; 47 } 48 49 50 /* 51 * Create a new transaction. 52 * Endpoint must then initialize the new transaction as either UAS or UAC, and 53 * register it to the hash table. 54 */ 55 PJ_DEF(pj_status_t) pjsip_endpt_create_tsx(pjsip_endpoint *endpt, 56 pjsip_transaction **p_tsx) 57 { 58 pj_pool_t *pool; 59 60 PJ_ASSERT_RETURN(endpt && p_tsx, PJ_EINVAL); 61 62 PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_tsx()")); 63 64 /* Request one pool for the transaction. Mutex is locked there. */ 65 pool = pjsip_endpt_create_pool(endpt, "ptsx%p", 66 PJSIP_POOL_LEN_TSX, PJSIP_POOL_INC_TSX); 67 if (pool == NULL) { 68 return PJ_ENOMEM; 69 } 70 71 /* Create the transaction. */ 72 return pjsip_tsx_create(pool, endpt, p_tsx); 73 } 74 75 76 /* 77 * Register the transaction to the endpoint. 78 * This will put the transaction to the transaction hash table. Before calling 79 * this function, the transaction must be INITIALIZED as either UAS or UAC, so 80 * that the transaction key is built. 81 */ 82 PJ_DEF(void) pjsip_endpt_register_tsx( pjsip_endpoint *endpt, 83 pjsip_transaction *tsx) 84 { 85 PJ_LOG(5, (THIS_FILE, "pjsip_endpt_register_tsx(%s)", tsx->obj_name)); 86 87 pj_assert(tsx->transaction_key.slen != 0); 88 //pj_assert(tsx->state != PJSIP_TSX_STATE_NULL); 89 90 /* Lock hash table mutex. */ 91 pj_mutex_lock(endpt->tsx_table_mutex); 92 93 /* Register the transaction to the hash table. */ 94 pj_hash_set( tsx->pool, endpt->tsx_table, tsx->transaction_key.ptr, 95 tsx->transaction_key.slen, tsx); 96 97 /* Unlock mutex. */ 98 pj_mutex_unlock(endpt->tsx_table_mutex); 99 } 100 101 /* 102 * Find transaction by the key. 103 */ 104 PJ_DEF(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt, 105 const pj_str_t *key ) 106 { 107 pjsip_transaction *tsx; 108 109 PJ_LOG(5, (THIS_FILE, "pjsip_endpt_find_tsx()")); 110 111 /* Start lock mutex in the endpoint. */ 112 pj_mutex_lock(endpt->tsx_table_mutex); 113 114 /* Find the transaction in the hash table. */ 115 tsx = pj_hash_get( endpt->tsx_table, key->ptr, key->slen ); 116 117 /* Unlock mutex. */ 118 pj_mutex_unlock(endpt->tsx_table_mutex); 119 120 return tsx; 121 } 122 123 /* 124 * Create key. 125 */ 126 static void rdata_create_key( pjsip_rx_data *rdata) 127 { 128 pjsip_role_e role; 129 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) { 130 role = PJSIP_ROLE_UAS; 131 } else { 132 role = PJSIP_ROLE_UAC; 133 } 134 pjsip_tsx_create_key(rdata->tp_info.pool, &rdata->endpt_info.key, role, 135 &rdata->msg_info.cseq->method, rdata); 136 } 137 138 139 /* 140 * This is the callback that is called by the transport manager when it 141 * receives a message from the network. 142 */ 143 static void endpt_transport_callback( pjsip_endpoint *endpt, 144 pj_status_t status, 145 pjsip_rx_data *rdata ) 146 { 147 pjsip_msg *msg = rdata->msg_info.msg; 148 pjsip_transaction *tsx; 149 pj_bool_t a_new_transaction_just_been_created = PJ_FALSE; 150 151 PJ_LOG(5, (THIS_FILE, "endpt_transport_callback(rdata=%p)", rdata)); 152 153 if (status != PJ_SUCCESS) { 154 const char *src_addr = rdata->pkt_info.src_name; 155 int port = rdata->pkt_info.src_port; 156 PJSIP_ENDPT_LOG_ERROR((endpt, "transport", status, 157 "Src.addr=%s:%d, packet:--\n" 158 "%s\n" 159 "-- end of packet. Error", 160 src_addr, port, rdata->msg_info.msg_buf)); 161 return; 162 } 163 164 /* For response, check that the value in Via sent-by match the transport. 165 * If not matched, silently drop the response. 166 * Ref: RFC3261 Section 18.1.2 Receiving Response 167 */ 168 if (msg->type == PJSIP_RESPONSE_MSG) { 169 const pj_str_t *addr_addr; 170 int port = rdata->msg_info.via->sent_by.port; 171 pj_bool_t mismatch = PJ_FALSE; 172 if (port == 0) { 173 int type; 174 type = rdata->tp_info.transport->key.type; 175 port = pjsip_transport_get_default_port_for_type(type); 176 } 177 addr_addr = &rdata->tp_info.transport->local_name.host; 178 if (pj_strcmp(&rdata->msg_info.via->sent_by.host, addr_addr) != 0) 179 mismatch = PJ_TRUE; 180 else if (port != rdata->tp_info.transport->local_name.port) { 181 /* Port or address mismatch, we should discard response */ 182 /* But we saw one implementation (we don't want to name it to 183 * protect the innocence) which put wrong sent-by port although 184 * the "rport" parameter is correct. 185 * So we discard the response only if the port doesn't match 186 * both the port in sent-by and rport. We try to be lenient here! 187 */ 188 if (rdata->msg_info.via->rport_param != rdata->tp_info.transport->local_name.port) 189 mismatch = PJ_TRUE; 190 else { 191 PJ_LOG(4,(THIS_FILE, "Response %p has mismatch port in sent-by" 192 " but the rport parameter is correct", 193 rdata)); 194 } 195 } 196 197 if (mismatch) { 198 pjsip_event e; 199 200 PJSIP_EVENT_INIT_DISCARD_MSG(e, rdata, PJSIP_EINVALIDVIA); 201 endpt_do_event( endpt, &e ); 202 return; 203 } 204 } 205 206 /* Create key for transaction lookup. */ 207 rdata_create_key( rdata); 208 209 /* Find the transaction for the received message. */ 210 PJ_LOG(5, (THIS_FILE, "finding tsx with key=%.*s", 211 rdata->endpt_info.key.slen, rdata->endpt_info.key.ptr)); 212 213 /* Start lock mutex in the endpoint. */ 214 pj_mutex_lock(endpt->tsx_table_mutex); 215 216 /* Find the transaction in the hash table. */ 217 tsx = pj_hash_get( endpt->tsx_table, rdata->endpt_info.key.ptr, rdata->endpt_info.key.slen ); 218 219 /* Unlock mutex. */ 220 pj_mutex_unlock(endpt->tsx_table_mutex); 221 222 /* If the transaction is not found... */ 223 if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) { 224 225 /* 226 * For response message, discard the message, except if the response is 227 * an 2xx class response to INVITE, which in this case it must be 228 * passed to TU to be acked. 229 */ 230 if (msg->type == PJSIP_RESPONSE_MSG) { 231 232 /* Inform TU about the 200 message, only if it's INVITE. */ 233 if (PJSIP_IS_STATUS_IN_CLASS(msg->line.status.code, 200) && 234 rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD) 235 { 236 pjsip_event e; 237 238 /* Should not happen for UA. Tsx theoritically lives until 239 * all responses are absorbed. 240 */ 241 pj_assert(0); 242 243 PJSIP_EVENT_INIT_RX_200_MSG(e, rdata); 244 endpt_do_event( endpt, &e ); 245 246 } else { 247 /* Just discard the response, inform TU. */ 248 pjsip_event e; 249 250 PJSIP_EVENT_INIT_DISCARD_MSG(e, rdata, 251 PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_CALL_TSX_DOES_NOT_EXIST)); 252 endpt_do_event( endpt, &e ); 253 } 254 255 /* 256 * For non-ACK request message, create a new transaction. 257 */ 258 } else if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) { 259 260 pj_status_t status; 261 262 /* Create transaction, mutex is locked there. */ 263 status = pjsip_endpt_create_tsx(endpt, &tsx); 264 if (status != PJ_SUCCESS) { 265 PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status, 266 "Unable to create transaction")); 267 return; 268 } 269 270 /* Initialize transaction as UAS. */ 271 pjsip_tsx_init_uas( tsx, rdata ); 272 273 /* Register transaction, mutex is locked there. */ 274 pjsip_endpt_register_tsx( endpt, tsx ); 275 276 a_new_transaction_just_been_created = PJ_TRUE; 277 } 278 } 279 280 /* If transaction is found (or newly created), pass the message. 281 * Otherwise if it's an ACK request, pass directly to TU. 282 */ 283 if (tsx && tsx->state != PJSIP_TSX_STATE_TERMINATED) { 284 /* Dispatch message to transaction. */ 285 pjsip_tsx_on_rx_msg( tsx, rdata ); 286 287 } else if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) { 288 /* 289 * This is an ACK message, but the INVITE transaction could not 290 * be found (possibly because the branch parameter in Via in ACK msg 291 * is different than the branch in original INVITE). This happens with 292 * SER! 293 */ 294 pjsip_event event; 295 296 PJSIP_EVENT_INIT_RX_ACK_MSG(event,rdata); 297 endpt_do_event( endpt, &event ); 298 } 299 300 /* 301 * If a new request message has just been receieved, but no modules 302 * seem to be able to handle the request message, then terminate the 303 * transaction. 304 * 305 * Ideally for cases like "unsupported method", we should be able to 306 * answer the request statelessly. But we can not do that since the 307 * endpoint shoule be able to be used as both user agent and proxy stack, 308 * and a proxy stack should be able to handle arbitrary methods. 309 */ 310 if (a_new_transaction_just_been_created && tsx->status_code < 100) { 311 /* Certainly no modules has sent any response message. 312 * Check that any modules has attached a module data. 313 */ 314 int i; 315 for (i=0; i<PJSIP_MAX_MODULE; ++i) { 316 if (tsx->module_data[i] != NULL) { 317 break; 318 } 319 } 320 if (i == PJSIP_MAX_MODULE) { 321 /* No modules have attached itself to the transaction. 322 * Terminate the transaction with 501/Not Implemented. 323 */ 324 pjsip_tx_data *tdata; 325 pj_status_t status; 326 327 if (tsx->method.id == PJSIP_OPTIONS_METHOD) { 328 status = pjsip_endpt_create_response(endpt, rdata, 200, 329 &tdata); 330 } else { 331 status = pjsip_endpt_create_response(endpt, rdata, 332 PJSIP_SC_METHOD_NOT_ALLOWED, 333 &tdata); 334 } 335 336 if (status != PJ_SUCCESS) { 337 PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status, 338 "Unable to create response")); 339 return; 340 } 341 342 if (endpt->allow_hdr) { 343 pjsip_msg_add_hdr( tdata->msg, 344 pjsip_hdr_shallow_clone(tdata->pool, endpt->allow_hdr)); 345 } 346 pjsip_tsx_on_tx_msg( tsx, tdata ); 347 348 } else { 349 /* 350 * If a module has registered itself in the transaction but it 351 * hasn't responded the request, chances are the module wouldn't 352 * respond to the request at all. We terminate the request here 353 * with 500/Internal Server Error, to be safe. 354 */ 355 pjsip_tx_data *tdata; 356 pj_status_t status; 357 358 status = pjsip_endpt_create_response(endpt, rdata, 500, &tdata); 359 if (status != PJ_SUCCESS) { 360 PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status, 361 "Unable to create response")); 362 return; 363 } 364 365 pjsip_tsx_on_tx_msg(tsx, tdata); 366 } 367 } 368 } 369 370 371 372 /* Transaction tables. */ 373 count = pj_hash_count(endpt->tsx_table); 374 PJ_LOG(3, (THIS_FILE, " Number of transactions: %u", count)); 375 376 if (count && detail) { 377 pj_hash_iterator_t it_val; 378 pj_hash_iterator_t *it; 379 pj_time_val now; 380 381 PJ_LOG(3, (THIS_FILE, " Dumping transaction tables:")); 382 383 pj_gettimeofday(&now); 384 it = pj_hash_first(endpt->tsx_table, &it_val); 385 386 while (it != NULL) { 387 int timeout_diff; 388 389 /* Get the transaction. No need to lock transaction's mutex 390 * since we already hold endpoint mutex, so that no transactions 391 * will be deleted. 392 */ 393 pjsip_transaction *tsx = pj_hash_this(endpt->tsx_table, it); 394 395 const char *role = (tsx->role == PJSIP_ROLE_UAS ? "UAS" : "UAC"); 396 397 if (tsx->timeout_timer._timer_id != -1) { 398 if (tsx->timeout_timer._timer_value.sec > now.sec) { 399 timeout_diff = tsx->timeout_timer._timer_value.sec - now.sec; 400 } else { 401 timeout_diff = now.sec - tsx->timeout_timer._timer_value.sec; 402 timeout_diff = 0 - timeout_diff; 403 } 404 } else { 405 timeout_diff = -1; 406 } 407 408 PJ_LOG(3, (THIS_FILE, " %s %s %10.*s %.9u %s t=%ds", 409 tsx->obj_name, role, 410 tsx->method.name.slen, tsx->method.name.ptr, 411 tsx->cseq, 412 pjsip_tsx_state_str(tsx->state), 413 timeout_diff)); 414 415 it = pj_hash_next(endpt->tsx_table, it); 416 } 417 } 418 419 420 421 #endif // XXX JUNK 32 422 33 423 /* Thread Local Storage ID for transaction lock (initialized by endpoint) */ … … 153 543 return role_name[role]; 154 544 } 545 546 547 548 /* 549 * Unregister the transaction from the hash table, and destroy the resources 550 * from the transaction. 551 */ 552 PJ_DEF(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt, 553 pjsip_transaction *tsx) 554 { 555 PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy_tsx(%s)", tsx->obj_name)); 556 557 pj_assert(tsx->state == PJSIP_TSX_STATE_DESTROYED); 558 559 /* No need to lock transaction. 560 * This function typically is called from the transaction callback, which 561 * means that transaction mutex is being held. 562 */ 563 pj_assert( pj_mutex_is_locked(tsx->mutex) ); 564 565 /* Lock endpoint. */ 566 pj_mutex_lock( endpt->tsx_table_mutex ); 567 568 /* Unregister from the hash table. */ 569 pj_hash_set( NULL, endpt->tsx_table, tsx->transaction_key.ptr, 570 tsx->transaction_key.slen, NULL); 571 572 /* Unlock endpoint mutex. */ 573 pj_mutex_unlock( endpt->tsx_table_mutex ); 574 575 /* Destroy transaction mutex. */ 576 pj_mutex_destroy( tsx->mutex ); 577 578 /* Release the pool for the transaction. */ 579 pj_pool_release(tsx->pool); 580 581 PJ_LOG(4, (THIS_FILE, "tsx%p destroyed", tsx)); 582 } 583 155 584 156 585 … … 501 930 pjsip_host_info *send_addr ) 502 931 { 503 const pjsip_uri *new_request_uri, *target_uri; 504 const pjsip_name_addr *topmost_route_uri; 505 pjsip_route_hdr *first_route_hdr, *last_route_hdr; 932 pjsip_route_hdr *route_hdr; 506 933 507 934 pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG); … … 511 938 * headers from the endpoint first. 512 939 */ 513 last_route_hdr = first_route_hdr = 514 pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL); 515 if (first_route_hdr) { 516 topmost_route_uri = &first_route_hdr->name_addr; 517 while (last_route_hdr->next != (void*)&tdata->msg->hdr) { 518 pjsip_route_hdr *hdr; 519 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, 520 last_route_hdr->next); 521 if (!hdr) 522 break; 523 last_route_hdr = hdr; 524 } 525 } else { 940 route_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL); 941 if (!route_hdr) { 526 942 const pjsip_route_hdr *hdr_list; 527 hdr_list = (pjsip_route_hdr*)pjsip_endpt_get_routing(tsx->endpt); 528 if (hdr_list->next != hdr_list) { 529 const pjsip_route_hdr *hdr = (pjsip_route_hdr*)hdr_list->next; 530 first_route_hdr = NULL; 531 topmost_route_uri = &hdr->name_addr; 532 do { 533 last_route_hdr = pjsip_hdr_shallow_clone(tdata->pool, hdr); 534 if (first_route_hdr == NULL) 535 first_route_hdr = last_route_hdr; 536 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)last_route_hdr); 537 hdr = hdr->next; 538 } while (hdr != hdr_list); 539 } else { 540 topmost_route_uri = NULL; 541 } 542 } 543 544 /* If Route headers exist, and the first element indicates loose-route, 545 * the URI is taken from the Request-URI, and we keep all existing Route 546 * headers intact. 547 * If Route headers exist, and the first element DOESN'T indicate loose 548 * route, the URI is taken from the first Route header, and remove the 549 * first Route header from the message. 550 * Otherwise if there's no Route headers, the URI is taken from the 551 * Request-URI. 552 */ 553 if (topmost_route_uri) { 554 pj_bool_t has_lr_param; 555 556 if (PJSIP_URI_SCHEME_IS_SIP(topmost_route_uri) || 557 PJSIP_URI_SCHEME_IS_SIPS(topmost_route_uri)) 558 { 559 const pjsip_url *url = pjsip_uri_get_uri((void*)topmost_route_uri); 560 has_lr_param = url->lr_param; 561 } else { 562 has_lr_param = 0; 563 } 564 565 if (has_lr_param) { 566 new_request_uri = tdata->msg->line.req.uri; 567 /* We shouldn't need to delete topmost Route if it has lr param. 568 * But seems like it breaks some proxy implementation, so we 569 * delete it anyway. 570 */ 571 /* 572 pj_list_erase(first_route_hdr); 573 if (first_route_hdr == last_route_hdr) 574 last_route_hdr = NULL; 575 */ 576 } else { 577 new_request_uri = pjsip_uri_get_uri((void*)topmost_route_uri); 578 pj_list_erase(first_route_hdr); 579 if (first_route_hdr == last_route_hdr) 580 last_route_hdr = NULL; 581 } 582 583 target_uri = (pjsip_uri*)topmost_route_uri; 584 585 } else { 586 target_uri = new_request_uri = tdata->msg->line.req.uri; 587 } 588 589 /* The target URI must be a SIP/SIPS URL so we can resolve it's address. 590 * Otherwise we're in trouble (i.e. there's no host part in tel: URL). 591 */ 592 pj_memset(send_addr, 0, sizeof(*send_addr)); 593 594 if (PJSIP_URI_SCHEME_IS_SIPS(target_uri)) { 595 pjsip_uri *uri = (pjsip_uri*) target_uri; 596 const pjsip_url *url = (const pjsip_url*)pjsip_uri_get_uri(uri); 597 send_addr->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE); 598 pj_strdup(tdata->pool, &send_addr->addr.host, &url->host); 599 send_addr->addr.port = url->port; 600 send_addr->type = 601 pjsip_transport_get_type_from_name(&url->transport_param); 602 603 } else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) { 604 pjsip_uri *uri = (pjsip_uri*) target_uri; 605 const pjsip_url *url = (const pjsip_url*)pjsip_uri_get_uri(uri); 606 pj_strdup(tdata->pool, &send_addr->addr.host, &url->host); 607 send_addr->addr.port = url->port; 608 send_addr->type = 609 pjsip_transport_get_type_from_name(&url->transport_param); 610 #if PJ_HAS_TCP 611 if (send_addr->type == PJSIP_TRANSPORT_TCP || 612 send_addr->type == PJSIP_TRANSPORT_SCTP) 613 { 614 send_addr->flag |= PJSIP_TRANSPORT_RELIABLE; 615 } 616 #endif 617 } else { 618 pj_assert(!"Unsupported URI scheme!"); 619 return PJSIP_EINVALIDSCHEME; 620 } 621 622 /* If target URI is different than request URI, replace 623 * request URI add put the original URI in the last Route header. 624 */ 625 if (new_request_uri && new_request_uri!=tdata->msg->line.req.uri) { 626 pjsip_route_hdr *route = pjsip_route_hdr_create(tdata->pool); 627 route->name_addr.uri = tdata->msg->line.req.uri; 628 if (last_route_hdr) 629 pj_list_insert_after(last_route_hdr, route); 630 else 631 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route); 632 tdata->msg->line.req.uri = (pjsip_uri*)new_request_uri; 633 } 634 635 /* Success. */ 636 return PJ_SUCCESS; 943 const pjsip_route_hdr *hdr; 944 hdr_list = (const pjsip_route_hdr*)pjsip_endpt_get_routing(tsx->endpt); 945 hdr = hdr_list->next; 946 while (hdr != hdr_list { 947 route_hdr = pjsip_hdr_shallow_clone(tdata->pool, hdr); 948 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route_hdr); 949 hdr = hdr->next; 950 } 951 } 952 953 return pjsip_get_request_addr(tdata, send_addr); 637 954 } 638 955
Note: See TracChangeset
for help on using the changeset viewer.