ConnectionTracker::~ConnectionTracker() { for (std::map<pjsip_transport *, pjsip_tp_state_listener_key *>::iterator it = _connection_listeners.begin(); it != _connection_listeners.end(); ++it) { TRC_DEBUG("Stop listening on connection %p", it->first); pjsip_transport_remove_state_listener(it->first, it->second, (void *)this); } pthread_mutex_destroy(&_lock); }
void ConnectionPool::quiesce_connection(int hash_slot) { pthread_mutex_lock(&_tp_hash_lock); pjsip_transport* tp = _tp_hash[hash_slot].tp; if (tp != NULL) { if (_tp_hash[hash_slot].connected) { // Connection was established, so update statistics. --_active_connections; decrement_connection_count(tp); } // Don't listen for any more state changes on this connection. pjsip_transport_remove_state_listener(tp, _tp_hash[hash_slot].listener_key, (void *)this); // Remove the transport from the hash and the map. _tp_hash[hash_slot].tp = NULL; _tp_hash[hash_slot].listener_key = NULL; _tp_hash[hash_slot].connected = PJ_FALSE; _tp_map.erase(tp); // Release the lock now so we don't have a deadlock if pjsip_transport_shutdown // calls the transport state listener. pthread_mutex_unlock(&_tp_hash_lock); // Quiesce the transport. PJSIP will destroy the transport when there // are no further references to it. pjsip_transport_shutdown(tp); // Remove our reference to the transport. pjsip_transport_dec_ref(tp); } else { pthread_mutex_unlock(&_tp_hash_lock); } }
Flow::~Flow() { if (PJSIP_TRANSPORT_IS_RELIABLE(_transport)) { // Remove the state listener to ensure it doesn't get called after the // flow is destroyed. pjsip_transport_remove_state_listener(_transport, _tp_state_listener_key, this); // We incremented the ref count when we put it in the map. pjsip_transport_dec_ref(_transport); } if (_timer.id) { // Stop the keepalive timer. pjsip_endpt_cancel_timer(stack_data.endpt, &_timer); _timer.id = 0; } pthread_mutex_destroy(&_flow_lock); }
void ConnectionPool::transport_state_update(pjsip_transport* tp, pjsip_transport_state state) { // Transport state has changed. pthread_mutex_lock(&_tp_hash_lock); std::map<pjsip_transport*, int>::const_iterator i = _tp_map.find(tp); if (i != _tp_map.end()) { int hash_slot = i->second; if ((state == PJSIP_TP_STATE_CONNECTED) && (!_tp_hash[hash_slot].connected)) { // New connection has connected successfully, so update the statistics. TRC_DEBUG("Transport %s in slot %d has connected", tp->obj_name, hash_slot); _tp_hash[hash_slot].connected = PJ_TRUE; ++_active_connections; increment_connection_count(tp); if (_recycle_period > 0) { // Compute a TTL for the connection. To avoid all the recycling being // synchronized we set the TTL to the specified average recycle time // perturbed by a random factor. int ttl = _recycle_period + (rand() % (2 * _recycle_margin)) - _recycle_margin; _tp_hash[hash_slot].recycle_time = time(NULL) + ttl; } else { // Connection recycling is disabled. _tp_hash[hash_slot].recycle_time = 0; } } else if ((state == PJSIP_TP_STATE_DISCONNECTED) || (state == PJSIP_TP_STATE_DESTROYED)) { // Either a connection has failed or been shutdown, or a new connection // failed to connect. TRC_DEBUG("Transport %s in slot %d has failed", tp->obj_name, hash_slot); if (_tp_hash[hash_slot].connected) { // A connection has failed, so update the statistics. --_active_connections; decrement_connection_count(tp); } else { // Failed to establish a connection to this server, so blacklist // it so we steer clear of it for a while. We don't blacklist // if an existing connection fails as this may be a transient error // or even a disconnect triggered by an inactivity timeout . AddrInfo server; server.transport = IPPROTO_TCP; server.port = pj_sockaddr_get_port(&tp->key.rem_addr); server.address.af = tp->key.rem_addr.addr.sa_family; if (server.address.af == AF_INET) { server.address.addr.ipv4.s_addr = tp->key.rem_addr.ipv4.sin_addr.s_addr; } else { memcpy((char*)&server.address.addr.ipv6, (char*)&tp->key.rem_addr.ipv6.sin6_addr, sizeof(struct in6_addr)); } PJUtils::blacklist_server(server); } // Don't listen for any more state changes on this connection (but note // it's illegal to call any methods on the transport once it's entered the // `destroyed` state). if (state != PJSIP_TP_STATE_DESTROYED) { pjsip_transport_remove_state_listener(tp, _tp_hash[hash_slot].listener_key, (void *)this); } // Remove the transport from the hash and the map. _tp_hash[hash_slot].tp = NULL; _tp_hash[hash_slot].listener_key = NULL; _tp_hash[hash_slot].connected = PJ_FALSE; _tp_map.erase(tp); // Remove our reference to the transport. pjsip_transport_dec_ref(tp); } } pthread_mutex_unlock(&_tp_hash_lock); }