std::string JSONEnumService::lookup_uri_from_user(const std::string &user, SAS::TrailId trail) const { std::string uri; TRC_DEBUG("Translating URI via JSON ENUM lookup"); if (user.empty()) { TRC_INFO("No dial string supplied, so don't do ENUM lookup"); return std::string(); } std::string aus = user_to_aus(user); // Take a read lock on the mutex in RAII style boost::shared_lock<boost::shared_mutex> read_lock(_number_prefixes_rw_lock); const struct NumberPrefix* pfix = prefix_match(aus); if (pfix == NULL) { TRC_WARNING("No matching number range %s from ENUM lookup", user.c_str()); SAS::Event event(trail, SASEvent::ENUM_INCOMPLETE, 0); event.add_var_param(user); SAS::report_event(event); return uri; } // Apply the regular expression to the user string to generate a new // URI. try { uri = boost::regex_replace(aus, pfix->match, pfix->replace); } catch(...) // LCOV_EXCL_START Only throws if expression too complex or similar hard-to-hit conditions { TRC_ERROR("Failed to translate number with regex"); SAS::Event event(trail, SASEvent::ENUM_INCOMPLETE, 1); event.add_var_param(user); SAS::report_event(event); return uri; // LCOV_EXCL_STOP } TRC_INFO("Number %s found, translated URI = %s", user.c_str(), uri.c_str()); SAS::Event event(trail, SASEvent::ENUM_COMPLETE, 0); event.add_var_param(user); event.add_var_param(uri); SAS::report_event(event); return uri; }
std::string JSONEnumService::lookup_uri_from_user(const std::string &user, SAS::TrailId trail) const { std::string uri; TRC_DEBUG("Translating URI via JSON ENUM lookup"); if (user.empty()) { TRC_INFO("No dial string supplied, so don't do ENUM lookup"); return std::string(); } std::string aus = user_to_aus(user); struct NumberPrefix* pfix = prefix_match(aus); if (pfix == NULL) { TRC_INFO("No matching number range %s from ENUM lookup", user.c_str()); return uri; } // Apply the regular expression to the user string to generate a new // URI. try { uri = boost::regex_replace(aus, pfix->match, pfix->replace); } catch(...) // LCOV_EXCL_START Only throws if expression too complex or similar hard-to-hit conditions { TRC_ERROR("Failed to translate number with regex"); return uri; // LCOV_EXCL_STOP } TRC_INFO("Number %s found, translated URI = %s", user.c_str(), uri.c_str()); return uri; }
std::string DNSEnumService::lookup_uri_from_user(const std::string& user, SAS::TrailId trail) const { if (user.empty()) { TRC_INFO("No dial string supplied, so don't do ENUM lookup"); return std::string(); } // Log starting ENUM processing. SAS::Event event(trail, SASEvent::ENUM_START, 0); event.add_var_param(user); SAS::report_event(event); // Determine the Application Unique String (AUS) from the user. This is // used to form the first key, and also as the input into the regular // expressions. std::string aus = user_to_aus(user); std::string string = aus; // Get the resolver to use. This comes from thread-local data. DNSResolver* resolver = get_resolver(); // Spin round until we've finished (successfully or otherwise) or we've done // the maximum number of queries. bool complete = false; bool failed = false; bool server_failed = false; int dns_queries = 0; while ((!complete) && (!failed) && (dns_queries < MAX_DNS_QUERIES)) { // Translate the key into a domain and issue a query for it. std::string domain = key_to_domain(string); struct ares_naptr_reply* naptr_reply = NULL; int status = resolver->perform_naptr_query(domain, naptr_reply, trail); if (status == ARES_SUCCESS) { // Parse the reply into a sorted list of rules. std::vector<Rule> rules; parse_naptr_reply(naptr_reply, rules); // Now spin through the rules, looking for the first match. std::vector<DNSEnumService::Rule>::const_iterator rule; for (rule = rules.begin(); rule != rules.end(); ++rule) { if (rule->matches(string)) { // We found a match, so apply the regular expression to the AUS (not // the previous string - this is what ENUM mandates). If this was a // terminal rule, we now have a SIP URI and we're finished. // Otherwise, the output of the regular expression is used as the // next key. try { string = rule->replace(aus, trail); complete = rule->is_terminal(); } catch(...) // LCOV_EXCL_START Only throws if expression too complex or similar hard-to-hit conditions { TRC_ERROR("Failed to translate number with regex"); failed = true; // LCOV_EXCL_STOP } break; } } // If we didn't find a match (and so hit the end of the list), consider // this a failure. failed = failed || (rule == rules.end()); } else if (status == ARES_ENOTFOUND) { // Our DNS query failed, so give up, but this is not an ENUM server issue - // we just tried to look up an unknown name. failed = true; } else { // Our DNS query failed. Give up, and track an ENUM server failure. failed = true; server_failed = true; } // Free off the NAPTR reply if we have one. if (naptr_reply != NULL) { resolver->free_naptr_reply(naptr_reply); naptr_reply = NULL; } dns_queries++; } // Log that we've finished processing (and whether it was successful or not). if (complete) { TRC_DEBUG("Enum lookup completes: %s", string.c_str()); SAS::Event event(trail, SASEvent::ENUM_COMPLETE, 0); event.add_var_param(user); event.add_var_param(string); SAS::report_event(event); } else { TRC_WARNING("Enum lookup did not complete for user %s", user.c_str()); SAS::Event event(trail, SASEvent::ENUM_INCOMPLETE, 0); event.add_var_param(user); SAS::report_event(event); // On failure, we must return an empty (rather than incomplete) string. string = std::string(""); } // Report state of last communication attempt (which may potentially set/clear // an associated alarm). if (_comm_monitor) { if (server_failed) { _comm_monitor->inform_failure(); } else { _comm_monitor->inform_success(); } } return string; }