Exemplo n.º 1
0
void process_subscription_request(pjsip_rx_data* rdata)
{
  pj_status_t status;
  int st_code = PJSIP_SC_OK;

  SAS::TrailId trail = get_trail(rdata);

  // Get the URI from the To header and check it is a SIP or SIPS URI.
  pjsip_uri* uri = (pjsip_uri*)pjsip_uri_get_uri(rdata->msg_info.to->uri);
  pjsip_msg *msg = rdata->msg_info.msg;
  pjsip_expires_hdr* expires = (pjsip_expires_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
  int expiry = (expires != NULL) ? expires->ivalue : DEFAULT_SUBSCRIPTION_EXPIRES;

  if (expiry > max_expires)
  {
    // Expiry is too long, set it to the maximum.
    expiry = max_expires;
  }

  if ((!PJSIP_URI_SCHEME_IS_SIP(uri)) && (!PJSIP_URI_SCHEME_IS_TEL(uri)))
  {
    // Reject a non-SIP/TEL URI with 404 Not Found (RFC3261 isn't clear
    // whether 404 is the right status code - it says 404 should be used if
    // the AoR isn't valid for the domain in the RequestURI).
    LOG_ERROR("Rejecting subscribe request using invalid URI scheme");

    SAS::Event event(trail, SASEvent::SUBSCRIBE_FAILED_EARLY_URLSCHEME, 0);
    // Can't log the public ID as the subscribe has failed too early
    SAS::report_event(event);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_NOT_FOUND,
                               NULL,
                               NULL,
                               NULL);
    return;
  }

  bool emergency_subscription = false;

  pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*)
                 pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);

  while (contact_hdr != NULL)
  {
    emergency_subscription = PJUtils::is_emergency_registration(contact_hdr);

    if (!emergency_subscription)
    {
      break;
    }

    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
                                                          PJSIP_H_CONTACT,
                                                          contact_hdr->next);
  }

  if (emergency_subscription)
  {
    // Reject a subscription with a Contact header containing a contact address
    // that's been registered for emergency service.
    LOG_ERROR("Rejecting subscribe request from emergency registration");

    SAS::Event event(trail, SASEvent::SUBSCRIBE_FAILED_EARLY_EMERGENCY, 0);
    // Can't log the public ID as the subscribe has failed too early
    SAS::report_event(event);

    // Allow-Events is a mandatory header on 489 responses.
    pjsip_generic_string_hdr* allow_events_hdr = pjsip_generic_string_hdr_create(rdata->tp_info.pool, &STR_ALLOW_EVENTS, &STR_REG);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_BAD_EVENT,
                               NULL,
                               (pjsip_hdr*)allow_events_hdr,
                               NULL);
    return;
  }

  ACR* acr = acr_factory->get_acr(get_trail(rdata),
                                  CALLING_PARTY,
                                  ACR::requested_node_role(rdata->msg_info.msg));
  acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp);

  // Canonicalize the public ID from the URI in the To header.
  std::string public_id = PJUtils::public_id_from_uri(uri);

  LOG_DEBUG("Process SUBSCRIBE for public ID %s", public_id.c_str());

  // Get the call identifier from the headers.
  std::string cid = PJUtils::pj_str_to_string((const pj_str_t*)&rdata->msg_info.cid->id);;

  // Add SAS markers to the trail attached to the message so the trail
  // becomes searchable.
  SAS::Event event(trail, SASEvent::SUBSCRIBE_START, 0);
  event.add_var_param(public_id);
  SAS::report_event(event);

  LOG_DEBUG("Report SAS start marker - trail (%llx)", trail);
  SAS::Marker start_marker(trail, MARKER_ID_START, 1u);
  SAS::report_marker(start_marker);

  PJUtils::report_sas_to_from_markers(trail, rdata->msg_info.msg);
  PJUtils::mark_sas_call_branch_ids(trail, NULL, rdata->msg_info.msg);

  // Query the HSS for the associated URIs.
  std::vector<std::string> uris;
  std::map<std::string, Ifcs> ifc_map;

  // Subscriber must have already registered to be making a subscribe
  std::string state;
  HTTPCode http_code = hss->get_registration_data(public_id, state, ifc_map, uris, trail);
  if ((http_code != HTTP_OK) || (state != "REGISTERED"))
  {
    // We failed to get the list of associated URIs.  This indicates that the
    // HSS is unavailable, the public identity doesn't exist or the public
    // identity doesn't belong to the private identity.

    // The client shouldn't retry when the subscriber isn't present in the
    // HSS; reject with a 403 in this case.
    //
    // The client should retry on timeout but no other Clearwater nodes should
    // (as Sprout will already have retried on timeout). Reject with a 504
    // (503 is used for overload).
    st_code = PJSIP_SC_SERVER_TIMEOUT;

    if (http_code == HTTP_NOT_FOUND)
    {
      st_code = PJSIP_SC_FORBIDDEN;
    }

    LOG_ERROR("Rejecting SUBSCRIBE request");

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               st_code,
                               NULL,
                               NULL,
                               NULL);
    delete acr;
    return;
  }

  // Determine the AOR from the first entry in the uris array.
  std::string aor = uris.front();

  LOG_DEBUG("aor = %s", aor.c_str());
  LOG_DEBUG("SUBSCRIBE for public ID %s uses AOR %s", public_id.c_str(), aor.c_str());

  // Get the system time in seconds for calculating absolute expiry times.
  int now = time(NULL);

  // Write to the local store, checking the remote store if there is no entry locally. If the write to the local store succeeds, then write to the remote store.
  pjsip_tx_data* tdata_notify = NULL;
  RegStore::AoR* aor_data = NULL;
  std::string subscription_id;
  pj_status_t notify_status = write_subscriptions_to_store(store, aor, rdata,
                                                           now, NULL, remote_store,
                                                           &tdata_notify, &aor_data,
                                                           true, subscription_id,
                                                           trail);

  if (aor_data != NULL)
  {
    // Log the subscriptions.
    log_subscriptions(aor, aor_data);

    // If we have a remote store, try to store this there too.  We don't worry
    // about failures in this case.
    if (remote_store != NULL)
    {
      RegStore::AoR* remote_aor_data = NULL;
      std::string ignore;
      write_subscriptions_to_store(remote_store, aor, rdata, now, aor_data, NULL,
                                   &tdata_notify, &remote_aor_data, false, ignore,
                                   trail);
      delete remote_aor_data;
    }
  }
  else
  {
    // Failed to connect to the local store.  Reject the subscribe with a 500
    // response.

    // LCOV_EXCL_START - the can't fail to connect to the store we use for UT
    st_code = PJSIP_SC_INTERNAL_SERVER_ERROR;
    // LCOV_EXCL_STOP
  }

  // Build and send the reply.
  pjsip_tx_data* tdata;
  status = PJUtils::create_response(stack_data.endpt, rdata, st_code, NULL, &tdata);
  if (status != PJ_SUCCESS)
  {
    // LCOV_EXCL_START - don't know how to get PJSIP to fail to create a response
    LOG_ERROR("Error building SUBSCRIBE %d response %s", st_code,
              PJUtils::pj_status_to_string(status).c_str());

    SAS::Event event(trail, SASEvent::SUBSCRIBE_FAILED, 0);
    event.add_var_param(public_id);
    std::string error_msg = "Error building SUBSCRIBE (" + std::to_string(st_code) + ") " + PJUtils::pj_status_to_string(status);
    event.add_var_param(error_msg);
    SAS::report_event(event);

    PJUtils::respond_stateless(stack_data.endpt,
                               rdata,
                               PJSIP_SC_INTERNAL_SERVER_ERROR,
                               NULL,
                               NULL,
                               NULL);
    delete acr;
    delete aor_data;
    return;
    // LCOV_EXCL_STOP
  }

  // Add expires headers
  pjsip_expires_hdr* expires_hdr = pjsip_expires_hdr_create(tdata->pool, expiry);
  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);

  // Add the to tag to the response
  pjsip_to_hdr *to = (pjsip_to_hdr*) pjsip_msg_find_hdr(tdata->msg,
                                                        PJSIP_H_TO,
                                                        NULL);
  pj_strdup2(tdata->pool, &to->tag, subscription_id.c_str());

  // Pass the response to the ACR.
  acr->tx_response(tdata->msg);

  // Send the response.
  status = pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL);

  // Send the ACR and delete it.
  acr->send_message();
  delete acr;

  // Send the Notify
  if (tdata_notify != NULL && notify_status == PJ_SUCCESS)
  {
    set_trail(tdata_notify, trail);
    status = PJUtils::send_request(tdata_notify, 0, NULL, NULL, true);

    if (status != PJ_SUCCESS)
    {
      // LCOV_EXCL_START
      SAS::Event event(trail, SASEvent::NOTIFICATION_FAILED, 0);
      std::string error_msg = "Failed to send NOTIFY - error code: " + std::to_string(status);
      event.add_var_param(error_msg);
      SAS::report_event(event);
      // LCOV_EXCL_STOP
    }
  }

  LOG_DEBUG("Report SAS end marker - trail (%llx)", trail);
  SAS::Marker end_marker(trail, MARKER_ID_END, 1u);
  SAS::report_marker(end_marker);

  delete aor_data;
}
Exemplo n.º 2
0
void SubscriberManager::handle_timer_pop_internal(const std::string& aor_id,
                                                  SAS::TrailId trail)
{
  TRC_DEBUG("Handling a timer pop for AoR %s", aor_id.c_str());

  // Get the original AoR from S4.
  AoR* orig_aor = NULL;
  uint64_t unused_version;
  HTTPCode rc = _s4->handle_get(aor_id,
                                &orig_aor,
                                unused_version,
                                trail);
  if (rc != HTTP_OK)
  {
    TRC_DEBUG("Handling timer pop for AoR %s failed during GET with return code %d",
              aor_id.c_str(),
              rc);
    delete orig_aor; orig_aor = NULL;
    return;
  }

  // Find any expired bindings in the original AoR.
  int now = time(NULL);
  std::vector<std::string> binding_ids_to_remove;
  for (BindingPair bp : orig_aor->bindings())
  {
    if (bp.second->_expires <= now)
    {
      binding_ids_to_remove.push_back(bp.first);
    }
  }

  // Find any expired subscriptions in the original AoR.
  std::vector<std::string> subscription_ids_to_remove;
  for (SubscriptionPair sp : orig_aor->subscriptions())
  {
    if (sp.second->_expires <= now)
    {
      subscription_ids_to_remove.push_back(sp.first);
    }
  }

  // We log removed bindings before writing to the store so that in the case
  // that the write fails, our estimate of how many active bindings we have will
  // be an underestimate, not an overestimate.
  log_removed_bindings(*orig_aor,
                       binding_ids_to_remove);

  // Send a PATCH to remove any expired bindings and subscriptions. We only do
  // this if there any bindings or subscriptions to remove.
  AoR* updated_aor = NULL;
  if ((!binding_ids_to_remove.empty()) ||
      (!subscription_ids_to_remove.empty()))
  {
    PatchObject patch_object;
    build_patch(patch_object,
                binding_ids_to_remove,
                subscription_ids_to_remove);

    // PATCH the existing AoR.
    rc = _s4->handle_patch(aor_id,
                           patch_object,
                           &updated_aor,
                           trail);

    if (rc != HTTP_OK)
    {
      TRC_DEBUG("Handling timer pop for AoR %s failed during PATCH with return code %d",
                aor_id.c_str(),
                rc);
      delete orig_aor; orig_aor = NULL;
      return;
    }
  }
  else
  {
    TRC_DEBUG("Timer pop for AoR %s didn't result in any removed bindings or subscriptions",
              aor_id.c_str());
    delete orig_aor; orig_aor = NULL;
    return;
  }

  log_subscriptions(aor_id,
                    *orig_aor,
                    *updated_aor,
                    subscription_ids_to_remove,
                    now);

  send_notifys(aor_id,
               orig_aor,
               updated_aor,
               SubscriberDataUtils::EventTrigger::TIMEOUT,
               now,
               trail);

  if ((updated_aor != NULL) &&
      (updated_aor->bindings().empty()))
  {
    SAS::Event event(trail, SASEvent::REGISTRATION_EXPIRED, 0);
    event.add_var_param(aor_id);
    SAS::report_event(event);

    HSSConnection::irs_info irs_info;
    rc = deregister_with_hss(aor_id,
                             HSSConnection::DEREG_TIMEOUT,
                             updated_aor->_scscf_uri,
                             irs_info,
                             trail);

    if (rc != HTTP_OK)
    {
      TRC_DEBUG("Failed to deregister subscriber %s with HSS",
                aor_id.c_str());
      delete orig_aor; orig_aor = NULL;
      delete updated_aor; updated_aor = NULL;
      return;
    }

    // Send 3rd party deREGISTERs.
    _registration_sender->deregister_with_application_servers(aor_id,
                                                              irs_info._service_profiles[aor_id],
                                                              trail);
  }

  delete orig_aor; orig_aor = NULL;
  delete updated_aor; updated_aor = NULL;
}
Exemplo n.º 3
0
HTTPCode SubscriberManager::remove_bindings(const std::string& public_id,
                                            const std::vector<std::string>& binding_ids,
                                            const SubscriberDataUtils::EventTrigger& event_trigger,
                                            Bindings& bindings,
                                            SAS::TrailId trail)
{
  TRC_DEBUG("Removing bindings from IMPU %s", public_id.c_str());

  int now = time(NULL);

  // Get cached subscriber information from the HSS.
  std::string aor_id;
  HSSConnection::irs_info irs_info;
  HTTPCode rc = get_cached_default_id(public_id,
                                      aor_id,
                                      irs_info,
                                      trail);
  if (rc != HTTP_OK)
  {
    return rc;
  }

  // Get the original AoR from S4.
  AoR* orig_aor = NULL;
  uint64_t unused_version;
  rc = _s4->handle_get(aor_id,
                       &orig_aor,
                       unused_version,
                       trail);

  if (rc != HTTP_OK)
  {
    delete orig_aor; orig_aor = NULL;
    if (rc == HTTP_NOT_FOUND)
    {
      // If there is no AoR, we still count that as a success.
      TRC_DEBUG("Removing bindings for AoR %s succeeded because no bindings are present in the store",
                aor_id.c_str());
      return HTTP_OK;
    }

    TRC_DEBUG("Removing bindings for AoR %s failed during GET with return code %d",
              aor_id.c_str(),
              rc);
    return rc;
  }

  // We log removed bindings before writing to the store so that in the case
  // that the write fails, our estimate of how many active bindings we have will
  // be an underestimate, not an overestimate.
  log_removed_bindings(*orig_aor,
                       binding_ids);

  // Check if there are any subscriptions that share the same contact as
  // the removed bindings, and delete them too.
  std::vector<std::string> subscription_ids_to_remove =
                             subscriptions_to_remove(orig_aor->bindings(),
                                                     orig_aor->subscriptions(),
                                                     Bindings(),
                                                     binding_ids);

  PatchObject patch_object;
  build_patch(patch_object,
              binding_ids,
              subscription_ids_to_remove,
              irs_info._associated_uris);

  // PATCH the existing AoR.
  AoR* updated_aor = NULL;
  rc = _s4->handle_patch(aor_id,
                         patch_object,
                         &updated_aor,
                         trail);

  if (rc != HTTP_OK)
  {
    TRC_DEBUG("Removing bindings for AoR %s failed during PATCH with return code %d",
              aor_id.c_str(),
              rc);
    delete orig_aor; orig_aor = NULL;
    delete updated_aor; updated_aor = NULL;
    return rc;
  }

  log_subscriptions(aor_id,
                    *orig_aor,
                    *updated_aor,
                    subscription_ids_to_remove,
                    now);

  // Get all bindings to return to the caller
  bindings = SubscriberDataUtils::copy_active_bindings(updated_aor->bindings(),
                                                       now,
                                                       trail);

  send_notifys(aor_id,
               orig_aor,
               updated_aor,
               event_trigger,
               now,
               trail);

  // Update HSS if all bindings expired.
  if (bindings.empty())
  {
    // If this action was not triggered by the HSS e.g. because of an RTR, we
    // should dergister with the HSS.
    if (event_trigger != SubscriberDataUtils::EventTrigger::HSS)
    {
      std::string dereg_reason = (event_trigger == SubscriberDataUtils::EventTrigger::USER) ?
                                   HSSConnection::DEREG_USER : HSSConnection::DEREG_ADMIN;
      rc = deregister_with_hss(aor_id,
                               dereg_reason,
                               updated_aor->_scscf_uri,
                               irs_info,
                               trail);
      if (rc != HTTP_OK)
      {
        TRC_DEBUG("Failed to deregister subscriber %s with HSS",
                  aor_id.c_str());
        delete orig_aor; orig_aor = NULL;
        delete updated_aor; updated_aor = NULL;
        return rc;
      }
    }

    // Send 3rd party deREGISTERs.
    _registration_sender->deregister_with_application_servers(public_id,
                                                              irs_info._service_profiles[public_id],
                                                              trail);
  }

  delete orig_aor; orig_aor = NULL;
  delete updated_aor; updated_aor = NULL;

  return HTTP_OK;
}
Exemplo n.º 4
0
HTTPCode SubscriberManager::modify_subscriptions(
                                    const std::string& public_id,
                                    const Subscriptions& update_subscriptions,
                                    const std::vector<std::string>& remove_subscriptions,
                                    HSSConnection::irs_info& irs_info,
                                    SAS::TrailId trail)
{
  int now = time(NULL);

  // Get cached subscriber information from the HSS.
  std::string aor_id;
  HTTPCode rc = get_cached_default_id(public_id,
                                      aor_id,
                                      irs_info,
                                      trail);
  if (rc != HTTP_OK)
  {
    TRC_DEBUG("Unable to modify subscription for %s - HSS lookup failed with "
              " return code %d",
              public_id.c_str(), rc);
    return rc;
  }

  AoR* orig_aor = NULL;
  uint64_t unused_version;
  rc = _s4->handle_get(aor_id,
                       &orig_aor,
                       unused_version,
                       trail);

  // There must be an existing AoR since there must be bindings to subscribe to.
  if (rc != HTTP_OK)
  {
    TRC_DEBUG("Modifying subscription for AoR %s failed during S4 lookup "
              "with return code %d",
              aor_id.c_str(),
              rc);
    return rc;
  }

  PatchObject patch_object;
  build_patch(patch_object,
              update_subscriptions,
              remove_subscriptions,
              irs_info._associated_uris);

  // PATCH the existing AoR.
  AoR* updated_aor = NULL;
  rc = _s4->handle_patch(aor_id,
                         patch_object,
                         &updated_aor,
                         trail);

  if (rc != HTTP_OK)
  {
    TRC_DEBUG("Modifying subscription for AoR %s failed during S4 update with "
              "return code %d",
              aor_id.c_str(),
              rc);
  }
  else
  {
    // At this point modifying the subscription has been successful - we'll return
    // OK to the client.

    // Write an analytics log for the modified subscription.
    std::string subscription_id = (remove_subscriptions.empty()) ?
                                    update_subscriptions.begin()->first :
                                    remove_subscriptions[0];
    log_subscriptions(aor_id,
                      *orig_aor,
                      *updated_aor,
                      {subscription_id},
                      now);

    // Finally, send any NOTIFYs.
    send_notifys(aor_id,
                 orig_aor,
                 updated_aor,
                 SubscriberDataUtils::EventTrigger::USER,
                 now,
                 trail);
  }

  // Delete both AoRs - the client doesn't need either of these.
  delete orig_aor; orig_aor = NULL;
  delete updated_aor; updated_aor = NULL;

  return rc;
}
Exemplo n.º 5
0
HTTPCode SubscriberManager::reregister_subscriber_internal(const std::string& aor_id,
                                                           const std::string& server_name,
                                                           const AssociatedURIs& associated_uris,
                                                           const Bindings& updated_bindings,
                                                           const std::vector<std::string>& binding_ids_to_remove,
                                                           Bindings& all_bindings,
                                                           HSSConnection::irs_info& irs_info,
                                                           bool retry,
                                                           SAS::TrailId trail)
{
  TRC_DEBUG("Reregistering AoR %s", aor_id.c_str());

  int now = time(NULL);

  AoR* orig_aor = NULL;
  uint64_t unused_version;
  HTTPCode rc = _s4->handle_get(aor_id,
                                &orig_aor,
                                unused_version,
                                trail);

  // We are reregistering a subscriber, so there must be an existing AoR in the
  // store.
  AoR* updated_aor = NULL;
  if ((rc == HTTP_NOT_FOUND) && (retry))
  {
    TRC_DEBUG("Reregistering AoR %s failed with 404 NOT FOUND - retry with register",
              aor_id.c_str());
    return register_subscriber_internal(aor_id,
                                        server_name,
                                        associated_uris,
                                        updated_bindings,
                                        all_bindings,
                                        irs_info,
                                        false,
                                        trail);
  }
  else if (rc != HTTP_OK)
  {
    TRC_DEBUG("Reregistering AoR %s failed during GET with return code %d",
              aor_id.c_str(),
              rc);
    delete orig_aor; orig_aor = NULL;
    return rc;
  }

  // Check if there are any subscriptions that share the same contact as
  // the removed bindings, and delete them too.
  std::vector<std::string> subscription_ids_to_remove =
                             subscriptions_to_remove(orig_aor->bindings(),
                                                     orig_aor->subscriptions(),
                                                     updated_bindings,
                                                     binding_ids_to_remove);

  // We log removed bindings before writing to the store so that in the case
  // that the write fails, our estimate of how many active bindings we have will
  // be an underestimate, not an overestimate.
  log_removed_bindings(*orig_aor,
                       binding_ids_to_remove);

  PatchObject patch_object;
  build_patch(patch_object,
              updated_bindings,
              binding_ids_to_remove,
              subscription_ids_to_remove,
              associated_uris);

  // PATCH the existing AoR.
  rc = _s4->handle_patch(aor_id,
                         patch_object,
                         &updated_aor,
                         trail);

  // If we didn't find an existing AoR, that means the subscriber does not
  // currently exist. We might want to retry by registering the subscriber
  // afresh.
  if ((rc == HTTP_NOT_FOUND) && (retry))
  {
    TRC_DEBUG("Reregistering AoR %s failed with 404 NOT FOUND - retry with register",
              aor_id.c_str());
    delete orig_aor; orig_aor = NULL;
    return register_subscriber_internal(aor_id,
                                        server_name,
                                        associated_uris,
                                        updated_bindings,
                                        all_bindings,
                                        irs_info,
                                        false,
                                        trail);
  }
  else if (rc != HTTP_OK)
  {
    TRC_DEBUG("Reregistering AoR %s failed during PATCH with return code %d",
              aor_id.c_str(),
              rc);
    delete orig_aor; orig_aor = NULL;
    delete updated_aor; updated_aor = NULL;
    return rc;
  }

  log_updated_bindings(*updated_aor, updated_bindings, now);

  log_subscriptions(aor_id,
                    *orig_aor,
                    *updated_aor,
                    subscription_ids_to_remove,
                    now);

  // Get all bindings to return to the caller
  all_bindings = SubscriberDataUtils::copy_active_bindings(updated_aor->bindings(),
                                                           now,
                                                           trail);

  send_notifys(aor_id,
               orig_aor,
               updated_aor,
               SubscriberDataUtils::EventTrigger::USER,
               now,
               trail);

  // Update HSS if all bindings expired.
  if (all_bindings.empty())
  {
    rc = deregister_with_hss(aor_id,
                             HSSConnection::DEREG_USER,
                             updated_aor->_scscf_uri,
                             irs_info,
                             trail);
    if (rc != HTTP_OK)
    {
      TRC_DEBUG("Failed to deregister subscriber %s with HSS",
                aor_id.c_str());
      delete orig_aor; orig_aor = NULL;
      delete updated_aor; updated_aor = NULL;
      return rc;
    }
  }

  delete orig_aor; orig_aor = NULL;
  delete updated_aor; updated_aor = NULL;

  return HTTP_OK;
}