📄 sip_transaction.c
字号:
/* * Register transaction layer module to endpoint. */ status = pjsip_endpt_register_module( endpt, &mod_tsx_layer.mod ); if (status != PJ_SUCCESS) { pj_mutex_destroy(mod_tsx_layer.mutex); pjsip_endpt_release_pool(endpt, pool); return status; } /* Register mod_stateful_util module (sip_util_statefull.c) */ status = pjsip_endpt_register_module(endpt, &mod_stateful_util); if (status != PJ_SUCCESS) { return status; } return PJ_SUCCESS;}/* * Get the instance of transaction layer module. */PJ_DEF(pjsip_module*) pjsip_tsx_layer_instance(void){ return &mod_tsx_layer.mod;}/* * Unregister and destroy transaction layer module. */PJ_DEF(pj_status_t) pjsip_tsx_layer_destroy(void){ /* Are we registered? */ PJ_ASSERT_RETURN(mod_tsx_layer.endpt!=NULL, PJ_EINVALIDOP); /* Unregister from endpoint. * Clean-ups will be done in the unload() module callback. */ return pjsip_endpt_unregister_module( mod_tsx_layer.endpt, &mod_tsx_layer.mod);}/* * Register the transaction to the hash table. */static pj_status_t mod_tsx_layer_register_tsx( pjsip_transaction *tsx){ pj_assert(tsx->transaction_key.slen != 0); /* Lock hash table mutex. */ pj_mutex_lock(mod_tsx_layer.mutex); /* Check if no transaction with the same key exists. * Do not use PJ_ASSERT_RETURN since it evaluates the expression * twice! */ pj_assert(pj_hash_get( mod_tsx_layer.htable, &tsx->transaction_key.ptr, tsx->transaction_key.slen, NULL) == NULL); TSX_TRACE_((THIS_FILE, "Transaction %p registered with hkey=0x%p and key=%.*s", tsx, tsx->hashed_key, tsx->transaction_key.slen, tsx->transaction_key.ptr)); /* Register the transaction to the hash table. */#ifdef PRECALC_HASH pj_hash_set( tsx->pool, mod_tsx_layer.htable, tsx->transaction_key.ptr, tsx->transaction_key.slen, tsx->hashed_key, tsx);#else pj_hash_set( tsx->pool, mod_tsx_layer.htable, tsx->transaction_key.ptr, tsx->transaction_key.slen, 0, tsx);#endif /* Unlock mutex. */ pj_mutex_unlock(mod_tsx_layer.mutex); return PJ_SUCCESS;}/* * Unregister the transaction from the hash table. */static void mod_tsx_layer_unregister_tsx( pjsip_transaction *tsx){ pj_assert(tsx->transaction_key.slen != 0); //pj_assert(tsx->state != PJSIP_TSX_STATE_NULL); /* Lock hash table mutex. */ pj_mutex_lock(mod_tsx_layer.mutex); /* Register the transaction to the hash table. */#ifdef PRECALC_HASH pj_hash_set( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr, tsx->transaction_key.slen, tsx->hashed_key, NULL);#else pj_hash_set( NULL, mod_tsx_layer.htable, tsx->transaction_key.ptr, tsx->transaction_key.slen, 0, NULL);#endif TSX_TRACE_((THIS_FILE, "Transaction %p unregistered, hkey=0x%p and key=%.*s", tsx, tsx->hashed_key, tsx->transaction_key.slen, tsx->transaction_key.ptr)); /* Unlock mutex. */ pj_mutex_unlock(mod_tsx_layer.mutex);}/* * Find a transaction. */PJ_DEF(pjsip_transaction*) pjsip_tsx_layer_find_tsx( const pj_str_t *key, pj_bool_t lock ){ pjsip_transaction *tsx; pj_uint32_t hval = 0; pj_mutex_lock(mod_tsx_layer.mutex); tsx = pj_hash_get( mod_tsx_layer.htable, key->ptr, key->slen, &hval ); pj_mutex_unlock(mod_tsx_layer.mutex); TSX_TRACE_((THIS_FILE, "Finding tsx with hkey=0x%p and key=%.*s: found %p", hval, key->slen, key->ptr, tsx)); /* Race condition! * Transaction may gets deleted before we have chance to lock it. */ PJ_TODO(FIX_RACE_CONDITION_HERE); if (tsx && lock) pj_mutex_lock(tsx->mutex); return tsx;}/* This module callback is called when module is being loaded by * endpoint. It does nothing for this module. */static pj_status_t mod_tsx_layer_load(pjsip_endpoint *endpt){ PJ_UNUSED_ARG(endpt); return PJ_SUCCESS;}/* This module callback is called when module is being started by * endpoint. It does nothing for this module. */static pj_status_t mod_tsx_layer_start(void){ return PJ_SUCCESS;}/* This module callback is called when module is being stopped by * endpoint. */static pj_status_t mod_tsx_layer_stop(void){ pj_hash_iterator_t it_buf, *it; PJ_LOG(4,(THIS_FILE, "Stopping transaction layer module")); pj_mutex_lock(mod_tsx_layer.mutex); /* Destroy all transactions. */ it = pj_hash_first(mod_tsx_layer.htable, &it_buf); while (it) { pjsip_transaction *tsx = pj_hash_this(mod_tsx_layer.htable, it); pj_hash_iterator_t *next = pj_hash_next(mod_tsx_layer.htable, it); if (tsx) { mod_tsx_layer_unregister_tsx(tsx); tsx_destroy(tsx); } it = next; } pj_mutex_unlock(mod_tsx_layer.mutex); return PJ_SUCCESS;}/* This module callback is called when module is being unloaded by * endpoint. */static pj_status_t mod_tsx_layer_unload(void){ /* Only self destroy when there's no transaction in the table. * Transaction may refuse to destroy when it has pending * transmission. If we destroy the module now, application will * crash when the pending transaction finally got error response * from transport and when it tries to unregister itself. */ if (pj_hash_count(mod_tsx_layer.htable) != 0) return PJ_EBUSY; /* Destroy mutex. */ pj_mutex_destroy(mod_tsx_layer.mutex); /* Release pool. */ pjsip_endpt_release_pool(mod_tsx_layer.endpt, mod_tsx_layer.pool); /* Free TLS */ pj_thread_local_free(pjsip_tsx_lock_tls_id); /* Mark as unregistered. */ mod_tsx_layer.endpt = NULL; PJ_LOG(4,(THIS_FILE, "Transaction layer module destroyed")); return PJ_SUCCESS;}/* This module callback is called when endpoint has received an * incoming request message. */static pj_bool_t mod_tsx_layer_on_rx_request(pjsip_rx_data *rdata){ pj_str_t key; pj_uint32_t hval = 0; pjsip_transaction *tsx; pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAS, &rdata->msg_info.cseq->method, rdata); /* Find transaction. */ pj_mutex_lock( mod_tsx_layer.mutex ); tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, &hval ); TSX_TRACE_((THIS_FILE, "Finding tsx for request, hkey=0x%p and key=%.*s, found %p", hval, key.slen, key.ptr, tsx)); if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) { /* Transaction not found. * Reject the request so that endpoint passes the request to * upper layer modules. */ pj_mutex_unlock( mod_tsx_layer.mutex); return PJ_FALSE; } /* Unlock hash table. */ pj_mutex_unlock( mod_tsx_layer.mutex ); /* Race condition! * Transaction may gets deleted before we have chance to lock it * in pjsip_tsx_recv_msg(). */ PJ_TODO(FIX_RACE_CONDITION_HERE); /* Pass the message to the transaction. */ pjsip_tsx_recv_msg(tsx, rdata ); return PJ_TRUE;}/* This module callback is called when endpoint has received an * incoming response message. */static pj_bool_t mod_tsx_layer_on_rx_response(pjsip_rx_data *rdata){ pj_str_t key; pj_uint32_t hval = 0; pjsip_transaction *tsx; pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAC, &rdata->msg_info.cseq->method, rdata); /* Find transaction. */ pj_mutex_lock( mod_tsx_layer.mutex ); tsx = pj_hash_get( mod_tsx_layer.htable, key.ptr, key.slen, &hval ); TSX_TRACE_((THIS_FILE, "Finding tsx for response, hkey=0x%p and key=%.*s, found %p", hval, key.slen, key.ptr, tsx)); if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) { /* Transaction not found. * Reject the request so that endpoint passes the request to * upper layer modules. */ pj_mutex_unlock( mod_tsx_layer.mutex); return PJ_FALSE; } /* Unlock hash table. */ pj_mutex_unlock( mod_tsx_layer.mutex ); /* Race condition! * Transaction may gets deleted before we have chance to lock it * in pjsip_tsx_recv_msg(). */ PJ_TODO(FIX_RACE_CONDITION_HERE); /* Pass the message to the transaction. */ pjsip_tsx_recv_msg(tsx, rdata ); return PJ_TRUE;}/* * Get transaction instance in the rdata. */PJ_DEF(pjsip_transaction*) pjsip_rdata_get_tsx( pjsip_rx_data *rdata ){ return rdata->endpt_info.mod_data[mod_tsx_layer.mod.id];}/* * Dump transaction layer. */PJ_DEF(void) pjsip_tsx_layer_dump(pj_bool_t detail){#if PJ_LOG_MAX_LEVEL >= 3 pj_hash_iterator_t itbuf, *it; /* Lock mutex. */ pj_mutex_lock(mod_tsx_layer.mutex); PJ_LOG(3, (THIS_FILE, "Dumping transaction table:")); PJ_LOG(3, (THIS_FILE, " Total %d transactions", pj_hash_count(mod_tsx_layer.htable))); if (detail) { it = pj_hash_first(mod_tsx_layer.htable, &itbuf); if (it == NULL) { PJ_LOG(3, (THIS_FILE, " - none - ")); } else { while (it != NULL) { pjsip_transaction *tsx = pj_hash_this(mod_tsx_layer.htable,it); PJ_LOG(3, (THIS_FILE, " %s %s|%d|%s", tsx->obj_name, (tsx->last_tx? pjsip_tx_data_get_info(tsx->last_tx): "none"), tsx->status_code, pjsip_tsx_state_str(tsx->state))); it = pj_hash_next(mod_tsx_layer.htable, it); } } } /* Unlock mutex. */ pj_mutex_unlock(mod_tsx_layer.mutex);#endif}/***************************************************************************** ** ** Transaction ** ***************************************************************************** **//* * Lock transaction and set the value of Thread Local Storage. */static void lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck){ struct tsx_lock_data *prev_data; pj_mutex_lock(tsx->mutex); prev_data = (struct tsx_lock_data *) pj_thread_local_get(pjsip_tsx_lock_tls_id); lck->prev = prev_data; lck->tsx = tsx; lck->is_alive = 1; pj_thread_local_set(pjsip_tsx_lock_tls_id, lck);}/* * Unlock transaction. * This will selectively unlock the mutex ONLY IF the transaction has not been * destroyed. The function knows whether the transaction has been destroyed * because when transaction is destroyed the is_alive flag for the transaction * will be set to zero. */static pj_status_t unlock_tsx( pjsip_transaction *tsx, struct tsx_lock_data *lck){ pj_assert( (void*)pj_thread_local_get(pjsip_tsx_lock_tls_id) == lck); pj_assert( lck->tsx == tsx ); pj_thread_local_set(pjsip_tsx_lock_tls_id, lck->prev); if (lck->is_alive) pj_mutex_unlock(tsx->mutex); return lck->is_alive ? PJ_SUCCESS : PJSIP_ETSXDESTROYED;}/* Create and initialize basic transaction structure. * This function is called by both UAC and UAS creation. */static pj_status_t tsx_create( pjsip_module *tsx_user, pjsip_transaction **p_tsx){ pj_pool_t *pool; pjsip_transaction *tsx; pj_status_t status; pool = pjsip_endpt_create_pool( mod_tsx_layer.endpt, "tsx", PJSIP_POOL_TSX_LEN, PJSIP_POOL_TSX_INC ); if (!pool) return PJ_ENOMEM; tsx = pj_pool_zalloc(pool, sizeof(pjsip_transaction)); tsx->pool = pool; tsx->tsx_user = tsx_user; tsx->endpt = mod_tsx_layer.endpt; pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name), "tsx%p", tsx); tsx->handle_200resp = 1; tsx->retransmit_timer.id = TSX_TIMER_RETRANSMISSION; tsx->retransmit_timer._timer_id = -1; tsx->retransmit_timer.user_data = tsx; tsx->retransmit_timer.cb = &tsx_timer_callback; tsx->timeout_timer.id = TSX_TIMER_TIMEOUT; tsx->timeout_timer._timer_id = -1; tsx->timeout_timer.user_data = tsx; tsx->timeout_timer.cb = &tsx_timer_callback; status = pj_mutex_create_recursive(pool, tsx->obj_name, &tsx->mutex); if (status != PJ_SUCCESS) { pjsip_endpt_release_pool(mod_tsx_layer.endpt, pool); return status; } *p_tsx = tsx; return PJ_SUCCESS;}/* Destroy transaction. */static pj_status_t tsx_destroy( pjsip_transaction *tsx ){ struct tsx_lock_data *lck; /* Decrement transport reference counter. */ if (tsx->transport) { pjsip_transport_dec_ref( tsx->transport ); tsx->transport = NULL; } /* Decrement reference counter in transport selector */ pjsip_tpselector_dec_ref(&tsx->tp_sel); /* Free last transmitted message. */ if (tsx->last_tx) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -