Beispiel #1
0
void RegistrationUtils::remove_bindings(RegStore* store,
                                        HSSConnection* hss,
                                        const std::string& aor,
                                        const std::string& binding_id,
                                        const std::string& dereg_type,
                                        SAS::TrailId trail)
{
  LOG_INFO("Remove binding(s) %s from IMPU %s", binding_id.c_str(), aor.c_str());

  if (expire_bindings(store, aor, binding_id, trail))
  {
    // All bindings have been expired, so do deregistration processing for the
    // IMPU.
    LOG_INFO("All bindings for %s expired, so deregister at HSS and ASs", aor.c_str());
    std::vector<std::string> uris;
    std::map<std::string, Ifcs> ifc_map;
    HTTPCode http_code = hss->update_registration_state(aor,
                                                        "",
                                                        dereg_type,
                                                        ifc_map,
                                                        uris,
                                                        trail);

    if (http_code == HTTP_OK)
    {
      // Note that 3GPP TS 24.229 V12.0.0 (2013-03) 5.4.1.7 doesn't specify that any binding information
      // should be passed on the REGISTER message, so we don't need the binding ID.
      deregister_with_application_servers(ifc_map[aor], store, aor, trail);
      notify_application_servers();
    }
  }
};
Beispiel #2
0
/// Retrieve the registration data for a given SIP Address of Record, creating
/// an empty record if no data exists for the AoR.
///
/// @param aor_id       The SIP Address of Record for the registration
RegStore::AoR* RegStore::get_aor_data(const std::string& aor_id, SAS::TrailId trail)
{
  AoR* aor_data = _connector->get_aor_data(aor_id, trail);

  if (aor_data != NULL)
  {
    int now = time(NULL);
    expire_bindings(aor_data, now, trail);
    expire_subscriptions(aor_data, now);
  }

  return aor_data;
}
Beispiel #3
0
  /// Update the data for a particular address of record.  Writes the data
  /// atomically.  If the underlying data has changed since it was last
  /// read, the update is rejected and this returns false; if the update
  /// succeeds, this returns true.
  ///
  /// If a connection cannot be obtained, returns a random boolean based on
  /// data found on the call stack at the point of entry.
  bool MemcachedStore::set_aor_data(const std::string& aor_id,
                                    ///< the SIP URI
                                    AoR* data)
                                    ///< the data to store
  {
    memcached_return_t rc;
    MemcachedAoR* aor_data = (MemcachedAoR*)data;

    // Try to get a connection.
    struct timespec wait_time;
    wait_time.tv_sec = 0;
    wait_time.tv_nsec = 100 * 1000 * 1000;
    memcached_st* st = memcached_pool_fetch(_pool, &wait_time, &rc);

    if (st != NULL)
    {
      // Got one: use it.
      //
      // Expire any old bindings before writing to the server.  In theory,
      // if there are no bindings left we could delete the entry, but this
      // may cause concurrency problems because memcached does not support
      // cas on delete operations.  In this case we do a memcached_cas with
      // an effectively immediate expiry time.
      int now = time(NULL);
      int max_expires = expire_bindings(aor_data, now);
      std::string value = serialize_aor(aor_data);
      if (aor_data->get_cas() == 0)
      {
        // New record, so attempt to add.  This will fail if someone else
        // gets there first.
        rc = memcached_add(st, aor_id.data(), aor_id.length(), value.data(), value.length(), max_expires, 0);
      }
      else
      {
        // This is an update to an existing record, so use memcached_cas
        // to make sure it is atomic.
        rc = memcached_cas(st, aor_id.data(), aor_id.length(), value.data(), value.length(), max_expires, 0, aor_data->get_cas());
      }

      memcached_pool_release(_pool, st);
    }

    return memcached_success(rc);
  }
Beispiel #4
0
  /// Retrieve the AoR data for a given SIP URI, creating it if there isn't
  /// any already, and returning NULL if we can't get a connection.
  AoR* MemcachedStore::get_aor_data(const std::string& aor_id)
                                    ///< the SIP URI
  {
    memcached_return_t rc;
    MemcachedAoR* aor_data = NULL;

    // Try to get a connection
    struct timespec wait_time;
    wait_time.tv_sec = 0;
    wait_time.tv_nsec = 100 * 1000 * 1000;
    memcached_st* st = memcached_pool_fetch(_pool, &wait_time, &rc);

    if (st != NULL)
    {
      // Got one: use it.
      const char* key_ptr = aor_id.data();
      const size_t key_len = aor_id.length();
      rc = memcached_mget(st, &key_ptr, &key_len, 1);
      if (memcached_success(rc))
      {
        memcached_result_st result;
        memcached_result_create(st, &result);
        memcached_fetch_result(st, &result, &rc);

        if (memcached_success(rc))
        {
          aor_data = deserialize_aor(std::string(memcached_result_value(&result), memcached_result_length(&result)));
          aor_data->set_cas(memcached_result_cas(&result));
          int now = time(NULL);
          expire_bindings(aor_data, now);
        }
        else
        {
          // AoR does not exist, so create it.
          aor_data = new MemcachedAoR();
        }
      }
      memcached_pool_release(_pool, st);
    }

    return (AoR*)aor_data;
  }
Beispiel #5
0
bool RegStore::set_aor_data(const std::string& aor_id,
                            AoR* aor_data,
                            bool set_chronos,
                            SAS::TrailId trail,
                            bool& all_bindings_expired)
{
  all_bindings_expired = false;
  // Expire any old bindings before writing to the server.  In theory, if
  // there are no bindings left we could delete the entry, but this may
  // cause concurrency problems because memcached does not support
  // cas on delete operations.  In this case we do a memcached_cas with
  // an effectively immediate expiry time.
  int now = time(NULL);

  // Set the max expires to be greater than the longest binding expiry time.
  // This prevents a window condition where Chronos can return a binding to
  // expire, but memcached has already deleted the aor data (meaning that
  // no NOTIFYs could be sent)
  int orig_max_expires = expire_bindings(aor_data, now, trail);
  int max_expires = orig_max_expires + 10;

  // expire_bindings returns "now" if there are no remaining bindings,
  // so test for that.
  if (orig_max_expires == now)
  {
    LOG_DEBUG("All bindings have expired, so this is a deregistration for AOR %s", aor_id.c_str());
    all_bindings_expired = true;
  }

  // Expire any old subscriptions as well.  This doesn't get factored in to
  // the expiry time on the store record because, according to 5.4.2.1.2 /
  // TS 24.229, all subscriptions automatically expire when the last binding
  // expires.
  expire_subscriptions(aor_data, now);

  LOG_DEBUG("Set AoR data for %s, CAS=%ld, expiry = %d",
            aor_id.c_str(), aor_data->_cas, max_expires);

  // Set the chronos timers
  if (set_chronos)
  {
    for (AoR::Bindings::iterator i = aor_data->_bindings.begin();
         i != aor_data->_bindings.end();
         ++i)
    {
      AoR::Binding* b = i->second;
      std::string b_id = i->first;

      HTTPCode status;
      std::string timer_id = "";
      std::string opaque = "{\"aor_id\": \"" + aor_id + "\", \"binding_id\": \"" + b_id +"\"}";
      std::string callback_uri = "/timers";

      int now = time(NULL);
      int expiry = b->_expires - now;

      // If a timer has been previously set for this binding, send a PUT. Otherwise sent a POST.
      if (b->_timer_id == "")
      {
        status = _chronos->send_post(timer_id, expiry, callback_uri, opaque, 0);
      }
      else
      {
        timer_id = b->_timer_id;
        status = _chronos->send_put(timer_id, expiry, callback_uri, opaque, 0);
      }

      // Update the timer id. If the update to Chronos failed, that's OK, don't reject the register
      // or update the stored timer id.
      if (status == HTTP_OK)
      {
        b->_timer_id = timer_id;
      }
    }
  }

  return _connector->set_aor_data(aor_id, aor_data, max_expires - now, trail);
}