Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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);
  }
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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);
}