Exemple #1
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].state == PJSIP_TP_STATE_DISCONNECTED))
    {
      // New connection has connected successfully, so update the statistics.
      LOG_DEBUG("Transport %s in slot %d has connected", tp->obj_name, hash_slot);
      _tp_hash[hash_slot].state = state;
      ++_active_connections;
      increment_connection_count(tp);
    }
    else if (state == PJSIP_TP_STATE_DISCONNECTED)
    {
      // Either a connection has failed, or a new connection failed to
      // connect.
      LOG_DEBUG("Transport %s in slot %d has failed", tp->obj_name, hash_slot);

      if (_tp_hash[hash_slot].state == PJSIP_TP_STATE_CONNECTED) 
      {
        // A connection has failed, so update the statistics.
        --_active_connections;
        decrement_connection_count(tp);
      }

      // Remove the transport from the hash and the map.
      _tp_hash[hash_slot].tp = NULL;
      _tp_hash[hash_slot].state = PJSIP_TP_STATE_DISCONNECTED;
      _tp_map.erase(tp);

      // Remove our reference to the transport.
      pjsip_transport_dec_ref(tp);
    }
  }

  pthread_mutex_unlock(&_tp_hash_lock);
}
Exemple #2
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);
}
Exemple #3
0
        /// Try to get a connection to \a l from the cache, or reserve space for
        /// a new connection to \a l. This function may evict entries from the
        /// cache.
        ///
        /// \returns If a connection was found in the cache, its value is
        ///          assigned to \a conn and this function returns true. If a
        ///          connection was not found but space was reserved, \a conn is
        ///          set such that conn.get() == 0, and this function returns
        ///          true. If a connection could not be found and space could
        ///          not be returned, \a conn is unmodified and this function
        ///          returns false.
        ///          If force_nsert is true, a new connection entry will be
        ///          created even if that means the cache limits will be
        ///          exceeded.
        ///
        /// \note    The connection must be returned to the cache by calling
        ///          \a reclaim().
        bool get_or_reserve(key_type const& l, connection_type& conn,
            bool force_insert = false)
        {
            std::lock_guard<mutex_type> lock(mtx_);

            typename cache_type::iterator const it = cache_.find(l);

            // Check if this key already exists in the cache.
            if (it != cache_.end())
            {
                // Key exists in cache.

                // Update LRU meta data.
                key_tracker_.splice(
                    key_tracker_.end()
                  , key_tracker_
                  , lru_reference(it->second)
                );

                // If connections to the locality are available in the cache,
                // remove the oldest one and return it.
                if (!cached_connections(it->second).empty())
                {
                    value_type& connections = cached_connections(it->second);
                    conn = connections.front();
                    connections.pop_front();

#if defined(HPX_TRACK_STATE_OF_OUTGOING_TCP_CONNECTION)
                    conn->set_state(Connection::state_reinitialized);
#endif
                    ++hits_;
                    check_invariants();
                    return true;
                }

                // Otherwise, if we have less connections for this locality
                // than the maximum, try to reserve space in the cache for a new
                // connection.
                if (num_existing_connections(it->second) <
                    max_num_connections(it->second) ||
                    force_insert)
                {
                    // See if we have enough space or can make space available.

                    // Note that if we don't have any space and there are no
                    // outstanding connections for this locality, we grow the
                    // cache size beyond its limit (hoping that it will be
                    // reduced in size next time some connection is handed back
                    // to the cache).

                    if (!free_space() &&
                        num_existing_connections(it->second) != 0 &&
                        !force_insert)
                    {
                        // If we can't find or make space, give up.
                        ++misses_;
                        check_invariants();
                        return false;
                    }

                    // Make sure the input connection shared_ptr doesn't hold
                    // anything.
                    conn.reset();

                    // Increase the per-locality and overall connection counts.
                    increment_connection_count(it->second);

                    // Statistics
                    ++insertions_;
                    check_invariants();
                    return true;
                }

                // We've reached the maximum number of connections for this
                // locality, and none of them are checked into the cache, so
                // we have to give up.
                ++misses_;
                check_invariants();
                return false;
            }

            // Key (locality) isn't in cache.

            // See if we have enough space or can make space available.

            // Note that we ignore the outcome of free_space() here as we have
            // to guarantee to have space for the new connection as there are
            // no connections outstanding for this locality. If free_space
            // fails we grow the cache size beyond its limit (hoping that it
            // will be reduced in size next time some connection is handed back
            // to the cache).
            free_space();

            // Update LRU meta data.
            typename key_tracker_type::iterator kt =
                key_tracker_.insert(key_tracker_.end(), l);

            cache_.insert(std::make_pair(
                l, util::make_tuple(
                    value_type(), 1, max_connections_per_locality_, kt
                ))
            );

            // Make sure the input connection shared_ptr doesn't hold anything.
            conn.reset();

            // Increase the overall connection counts.
            ++connections_;

            ++insertions_;
            check_invariants();
            return true;
        }