init: be aware of abandoned any-child routes

Previously, init did not test if a service is abandoned on a new
configuration if the service was routed via an any-child route.

Fixes #2483
This commit is contained in:
Martin Stein 2017-08-15 14:42:20 +02:00 committed by Christian Helmuth
parent 9476f3f645
commit 96c7f8d53f
2 changed files with 47 additions and 44 deletions

View File

@ -463,21 +463,14 @@ Init::Child::Route Init::Child::resolve_session_request(Service::Name const &ser
Session::Diag const
target_diag { target.attribute_value("diag", false) };
auto no_filter = [] (Service &) -> bool { return false; };
if (target.has_type("parent")) {
Parent_service *service = nullptr;
if ((service = find_service(_parent_services, service_name)))
return Route { *service, target_label, target_diag };
if (service && service->abandoned())
throw Service_denied();
if (!service_wildcard) {
warning(name(), ": service lookup for "
"\"", service_name, "\" at parent failed");
throw Service_denied();
}
try {
return Route { find_service(_parent_services, service_name, no_filter),
target_label, target_diag };
} catch (Service_denied) { }
}
if (target.has_type("child")) {
@ -486,24 +479,14 @@ Init::Child::Route Init::Child::resolve_session_request(Service::Name const &ser
Name server_name = target.attribute_value("name", Name());
server_name = _name_registry.deref_alias(server_name);
Routed_service *service = nullptr;
auto filter_server_name = [&] (Routed_service &s) -> bool {
return s.child_name() != server_name; };
_child_services.for_each([&] (Routed_service &s) {
if (s.name() == Service::Name(service_name)
&& s.child_name() == server_name)
service = &s; });
try {
return Route { find_service(_child_services, service_name, filter_server_name),
target_label, target_diag };
if (service && service->abandoned())
throw Service_denied();
if (service)
return Route { *service, target_label, target_diag };
if (!service_wildcard) {
warning(name(), ": lookup to child "
"server \"", server_name, "\" failed");
throw Service_denied();
}
} catch (Service_denied) { }
}
if (target.has_type("any-child")) {
@ -513,17 +496,16 @@ Init::Child::Route Init::Child::resolve_session_request(Service::Name const &ser
"service \"", service_name, "\"");
throw Service_denied();
}
try {
return Route { find_service(_child_services, service_name, no_filter),
target_label, target_diag };
Routed_service *service = nullptr;
} catch (Service_denied) { }
}
if ((service = find_service(_child_services, service_name)))
return Route { *service, target_label, target_diag };
if (!service_wildcard) {
warning(name(), ": lookup for service "
"\"", service_name, "\" failed");
throw Service_denied();
}
if (!service_wildcard) {
warning(name(), ": lookup for service \"", service_name, "\" failed");
throw Service_denied();
}
if (target.last())

View File

@ -122,15 +122,36 @@ namespace Init {
return cnt > 1;
}
template <typename T>
inline T *find_service(Registry<T> &services, Service::Name const &name)
/**
* Find service with certain values in given registry
*
* \param services service registry
* \param name name of wanted service
* \param filter_fn function that applies additional filters
*
* \throw Service_denied
*/
template <typename T, typename FILTER_FN>
inline T &find_service(Registry<T> &services,
Service::Name const &name,
FILTER_FN const &filter_fn)
{
T *service = nullptr;
services.for_each([&] (T &s) {
if (!service && (s.name() == name))
service = &s; });
return service;
if (service || s.name() != name || filter_fn(s))
return;
service = &s;
});
if (!service)
throw Service_denied();
if (service->abandoned())
throw Service_denied();
return *service;
}