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; }
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; }
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; }
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; }
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; }