diff --git a/bundles/remote_services/CMakeLists.txt b/bundles/remote_services/CMakeLists.txt index 1d069192f..9525549f7 100644 --- a/bundles/remote_services/CMakeLists.txt +++ b/bundles/remote_services/CMakeLists.txt @@ -127,7 +127,9 @@ if (REMOTE_SERVICE_ADMIN) calculator USE_CONFIG PROPERTIES - CELIX_RSA_BIND_ON_ALL_INTERFACES=false + CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT=true + RSA_PORT=19999 + CELIX_RSA_INTERFACES_OF_PORT_19999=lo ) add_celix_container(remote-services-zeroconf-client @@ -147,7 +149,9 @@ if (REMOTE_SERVICE_ADMIN) calculator_shell USE_CONFIG PROPERTIES - CELIX_RSA_BIND_ON_ALL_INTERFACES=false + CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT=true + RSA_PORT=29999 + CELIX_RSA_INTERFACES_OF_PORT_29999=lo ) endif() diff --git a/bundles/remote_services/discovery_common/src/discovery.c b/bundles/remote_services/discovery_common/src/discovery.c index 2387cb768..1ef701f6b 100644 --- a/bundles/remote_services/discovery_common/src/discovery.c +++ b/bundles/remote_services/discovery_common/src/discovery.c @@ -89,7 +89,7 @@ celix_status_t discovery_endpointListenerAdded(void* handle, service_reference_p const char *discoveryListener = NULL; serviceReference_getProperty(reference, "DISCOVERY", &discoveryListener); const char *scope = NULL; - serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + serviceReference_getProperty(reference, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, &scope); celix_autoptr(celix_filter_t) filter = celix_filter_create(scope); @@ -166,7 +166,7 @@ celix_status_t discovery_informEndpointListeners(discovery_t *discovery, endpoin endpoint_listener_t *listener = NULL; const char* scope = NULL; - serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + serviceReference_getProperty(reference, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, &scope); celix_autoptr(celix_filter_t) filter = celix_filter_create(scope); bool matchResult = celix_filter_match(filter, endpoint->properties); diff --git a/bundles/remote_services/discovery_common/src/discovery_activator.c b/bundles/remote_services/discovery_common/src/discovery_activator.c index 0b6b591f5..0179c50f1 100644 --- a/bundles/remote_services/discovery_common/src/discovery_activator.c +++ b/bundles/remote_services/discovery_common/src/discovery_activator.c @@ -56,7 +56,7 @@ celix_status_t bundleActivator_createEPLTracker(struct activator *activator, ser discovery_endpointListenerRemoved, &customizer); if (status == CELIX_SUCCESS) { - status = serviceTracker_create(activator->context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, customizer, tracker); + status = serviceTracker_create(activator->context, (char *) CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, customizer, tracker); } return status; @@ -103,7 +103,7 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context } char* scope = NULL; - int rc = asprintf(&scope, "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + int rc = asprintf(&scope, "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); status = rc < 0 ? CELIX_ENOMEM : CELIX_SUCCESS; celix_autoptr(celix_properties_t) props = NULL; @@ -112,7 +112,7 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context props = celix_properties_create(); celix_properties_set(props, "DISCOVERY", "true"); - celix_properties_set(props, (char *) OSGI_ENDPOINT_LISTENER_SCOPE, scope); + celix_properties_set(props, (char *) CELIX_RSA_ENDPOINT_LISTENER_SCOPE, scope); } if (status == CELIX_SUCCESS) { @@ -131,8 +131,8 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context endpointListener->endpointAdded = discovery_endpointAdded; endpointListener->endpointRemoved = discovery_endpointRemoved; - status = bundleContext_registerService(context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, endpointListener, - celix_steal_ptr(props), &activator->endpointListenerService); + status = bundleContext_registerService(context, (char *) CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, endpointListener, + celix_steal_ptr(props), &activator->endpointListenerService); if (status == CELIX_SUCCESS) { activator->endpointListener = endpointListener; diff --git a/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c b/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c index b816c8498..b4a7ce404 100644 --- a/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c +++ b/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c @@ -147,7 +147,7 @@ static celix_status_t endpointDescriptorWriter_writeEndpoint(endpoint_descriptor if (strcmp(CELIX_FRAMEWORK_SERVICE_NAME, (char*) iter.key) == 0) { // objectClass *must* be represented as array of string values... endpointDescriptorWriter_writeArrayValue(writer->writer, propertyValue); - } else if (strcmp(OSGI_RSA_ENDPOINT_SERVICE_ID, (char*) iter.key) == 0) { + } else if (strcmp(CELIX_RSA_ENDPOINT_SERVICE_ID, (char*) iter.key) == 0) { // endpoint.service.id *must* be represented as long value... endpointDescriptorWriter_writeTypedValue(writer->writer, VALUE_TYPE_LONG, propertyValue); } else { diff --git a/bundles/remote_services/discovery_configured/CMakeLists.txt b/bundles/remote_services/discovery_configured/CMakeLists.txt index 176cb680b..0c72e64ad 100644 --- a/bundles/remote_services/discovery_configured/CMakeLists.txt +++ b/bundles/remote_services/discovery_configured/CMakeLists.txt @@ -21,6 +21,7 @@ if (RSA_DISCOVERY_CONFIGURED) VERSION 0.9.0 SYMBOLIC_NAME "apache_celix_rsa_discovery" NAME "Apache Celix RSA Configured Discovery" + FILENAME celix_rsa_discovery_configured SOURCES src/discovery_impl.c ) diff --git a/bundles/remote_services/discovery_etcd/CMakeLists.txt b/bundles/remote_services/discovery_etcd/CMakeLists.txt index 67de75131..35346ca07 100644 --- a/bundles/remote_services/discovery_etcd/CMakeLists.txt +++ b/bundles/remote_services/discovery_etcd/CMakeLists.txt @@ -22,6 +22,7 @@ if (RSA_DISCOVERY_ETCD) SYMBOLIC_NAME "apache_celix_rsa_discovery_etcd" NAME "Apache Celix RSA Discovery ETCD" GROUP "Celix/RSA" + FILENAME celix_rsa_discovery_etcd SOURCES src/discovery_impl.c src/etcd_watcher.c diff --git a/bundles/remote_services/discovery_zeroconf/CMakeLists.txt b/bundles/remote_services/discovery_zeroconf/CMakeLists.txt index 990c55237..4d7e0b4d1 100644 --- a/bundles/remote_services/discovery_zeroconf/CMakeLists.txt +++ b/bundles/remote_services/discovery_zeroconf/CMakeLists.txt @@ -37,14 +37,16 @@ if (RSA_DISCOVERY_ZEROCONF) add_celix_bundle(rsa_discovery_zeroconf SYMBOLIC_NAME "apache_celix_rsa_discovery_zeroconf" - VERSION "1.0.0" + VERSION "2.0.0" NAME "Apache Celix Multicast zeroconf service discovery" GROUP "Celix/RSA" + FILENAME celix_rsa_discovery_zeroconf SOURCES ${RSA_DISCOVERY_ZEROCONF_SRC} ) celix_deprecated_utils_headers(rsa_discovery_zeroconf) + celix_deprecated_framework_headers(rsa_discovery_zeroconf) target_link_libraries(rsa_discovery_zeroconf PRIVATE ${RSA_DISCOVERY_ZEROCONF_DEPS}) @@ -58,6 +60,7 @@ if (RSA_DISCOVERY_ZEROCONF) if (ENABLE_TESTING) add_library(rsa_discovery_zeroconf_cut STATIC ${RSA_DISCOVERY_ZEROCONF_SRC}) celix_deprecated_utils_headers(rsa_discovery_zeroconf_cut) + celix_deprecated_framework_headers(rsa_discovery_zeroconf_cut) target_include_directories(rsa_discovery_zeroconf_cut PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src) target_link_libraries(rsa_discovery_zeroconf_cut PUBLIC ${RSA_DISCOVERY_ZEROCONF_DEPS}) add_subdirectory(gtest) diff --git a/bundles/remote_services/discovery_zeroconf/gtest/CMakeLists.txt b/bundles/remote_services/discovery_zeroconf/gtest/CMakeLists.txt index fe911954c..6581e573e 100644 --- a/bundles/remote_services/discovery_zeroconf/gtest/CMakeLists.txt +++ b/bundles/remote_services/discovery_zeroconf/gtest/CMakeLists.txt @@ -49,6 +49,7 @@ if (EI_TESTS) ) celix_deprecated_utils_headers(unit_test_discovery_zeroconf) + celix_deprecated_framework_headers(unit_test_discovery_zeroconf) target_link_libraries(unit_test_discovery_zeroconf PRIVATE rsa_discovery_zeroconf_cut @@ -58,6 +59,14 @@ if (EI_TESTS) Celix::threads_ei Celix::eventfd_ei Celix::bundle_ctx_ei + Celix::string_hash_map_ei + Celix::long_hash_map_ei + Celix::array_list_ei + Celix::properties_ei + Celix::utils_ei + Celix::dm_component_ei + Celix::bundle_ctx_ei + Celix::log_helper_ei Celix::mdnsresponder_ei Celix::malloc_ei GTest::gtest diff --git a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfActivatorTestSuite.cc b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfActivatorTestSuite.cc index 2dbb1bfc0..1ef6a94b2 100644 --- a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfActivatorTestSuite.cc +++ b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfActivatorTestSuite.cc @@ -19,6 +19,10 @@ #include "discovery_zeroconf_announcer.h" #include "discovery_zeroconf_watcher.h" +#include "celix_dm_component_ei.h" +#include "celix_bundle_context_ei.h" +#include "celix_properties_ei.h" +#include "celix_log_helper_ei.h" #include "eventfd_ei.h" #include "celix_framework.h" #include "celix_framework_factory.h" @@ -41,6 +45,13 @@ class DiscoveryZeroconfActivatorTestSuite : public ::testing::Test { ~DiscoveryZeroconfActivatorTestSuite() override { celix_ei_expect_eventfd(nullptr, 0, 0); + celix_ei_expect_celix_bundleContext_getProperty(nullptr, 0, nullptr); + celix_ei_expect_celix_bundleContext_getDependencyManager(nullptr, 0, nullptr); + celix_ei_expect_celix_dmComponent_create(nullptr, 0, nullptr); + celix_ei_expect_celix_dmServiceDependency_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_create(nullptr, 0, nullptr); + celix_ei_expect_celix_logHelper_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_set(nullptr, 0, 0); } std::shared_ptr fw{}; @@ -84,6 +95,134 @@ TEST_F(DiscoveryZeroconfActivatorTestSuite, DiscoveryZeroconfWatcherCreateFailed status = celix_bundleActivator_start(act, ctx.get()); EXPECT_EQ(CELIX_ENOMEM, status); + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, GetFrameworkUuidFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_bundleContext_getProperty(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_BUNDLE_EXCEPTION, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, CreateLogHelperFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_logHelper_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, CreateAnnouncerDmComponentFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_dmComponent_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, CreateAnnouncerEndpointListenerPropertiesFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_properties_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, SetEndpointListenerSocpePropertyFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_properties_set((void*)&celix_bundleActivator_start, 1, CELIX_ENOMEM); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, SetEndpointListenerInterfaceSpecificEndpointsPropertyFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_properties_set((void*)&celix_bundleActivator_start, 1, CELIX_ENOMEM, 3); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, CreateWatcherDmComponentFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_dmComponent_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 2); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, CreateEndpointListenerDependencyFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_dmServiceDependency_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, CreateRsaDependencyFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_ei_expect_celix_dmServiceDependency_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 2); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = celix_bundleActivator_destroy(act, ctx.get()); + EXPECT_EQ(CELIX_SUCCESS, status); +} + +TEST_F(DiscoveryZeroconfActivatorTestSuite, GetDependencyManagerFailed) { + void *act{nullptr}; + auto status = celix_bundleActivator_create(ctx.get(), &act); + EXPECT_EQ(CELIX_SUCCESS, status); + celix_ei_expect_celix_bundleContext_getDependencyManager(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = celix_bundleActivator_start(act, ctx.get()); + EXPECT_EQ(CELIX_ENOMEM, status); status = celix_bundleActivator_destroy(act, ctx.get()); EXPECT_EQ(CELIX_SUCCESS, status); } \ No newline at end of file diff --git a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfAnnouncerTestSuite.cc b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfAnnouncerTestSuite.cc index 66caf1fbf..2f322a782 100644 --- a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfAnnouncerTestSuite.cc +++ b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfAnnouncerTestSuite.cc @@ -23,7 +23,6 @@ extern "C" { #include "endpoint_description.h" } -#include "endpoint_listener.h" #include "celix_log_helper.h" #include "celix_bundle_context.h" #include "celix_framework_factory.h" @@ -32,17 +31,22 @@ extern "C" { #include "eventfd_ei.h" #include "celix_threads_ei.h" #include "celix_bundle_context_ei.h" +#include "celix_string_hash_map_ei.h" +#include "celix_array_list_ei.h" +#include "celix_properties_ei.h" +#include "celix_utils_ei.h" #include "mdnsresponder_ei.h" #include "malloc_ei.h" #include #include #include -#include #include #include #include #include -#include +#include + +#define DZC_TEST_CONFIG_TYPE "celix.config_type.test" static int GetLoopBackIfIndex(void); @@ -77,6 +81,10 @@ class DiscoveryZeroconfAnnouncerTestSuite : public ::testing::Test { celix_ei_expect_DNSServiceProcessResult(nullptr, 0, 0); celix_ei_expect_TXTRecordSetValue(nullptr, 0, 0); celix_ei_expect_calloc(nullptr, 0, nullptr); + celix_ei_expect_celix_stringHashMap_create(nullptr, 0, nullptr); + celix_ei_expect_celix_arrayList_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_copy(nullptr, 0, nullptr); + celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); } std::shared_ptr fw{}; @@ -106,30 +114,37 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed2) { EXPECT_EQ(status, EINVAL); } -TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed3) { +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed5) { discovery_zeroconf_announcer_t *announcer{nullptr}; - celix_ei_expect_celix_bundleContext_getProperty((void*)&discoveryZeroconfAnnouncer_create, 0, nullptr); + celix_ei_expect_celixThread_create((void*)&discoveryZeroconfAnnouncer_create, 0, CELIX_ENOMEM); auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); - EXPECT_EQ(status, CELIX_BUNDLE_EXCEPTION); + EXPECT_EQ(status, CELIX_ENOMEM); } -TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed4) { +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed6) { discovery_zeroconf_announcer_t *announcer{nullptr}; - celix_ei_expect_celix_bundleContext_registerServiceWithOptionsAsync((void*)&discoveryZeroconfAnnouncer_create, 0, -1); + celix_ei_expect_calloc((void*)&discoveryZeroconfAnnouncer_create, 0, nullptr); auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); - EXPECT_EQ(status, CELIX_BUNDLE_EXCEPTION); + EXPECT_EQ(status, CELIX_ENOMEM); } -TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed5) { +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed7) { discovery_zeroconf_announcer_t *announcer{nullptr}; - celix_ei_expect_celixThread_create((void*)&discoveryZeroconfAnnouncer_create, 0, CELIX_ENOMEM); + celix_ei_expect_celix_stringHashMap_create((void*)&discoveryZeroconfAnnouncer_create, 0, nullptr); auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_ENOMEM); } -TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed6) { +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed8) { discovery_zeroconf_announcer_t *announcer{nullptr}; - celix_ei_expect_calloc((void*)&discoveryZeroconfAnnouncer_create, 0, nullptr); + celix_ei_expect_celix_arrayList_create((void*)&discoveryZeroconfAnnouncer_create, 0, nullptr); + auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); + EXPECT_EQ(status, CELIX_ENOMEM); +} + +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, CreateAnnouncerFailed9) { + discovery_zeroconf_announcer_t *announcer{nullptr}; + celix_ei_expect_celix_stringHashMap_create((void*)&discoveryZeroconfAnnouncer_create, 0, nullptr, 2); auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_ENOMEM); } @@ -150,7 +165,11 @@ static void OnServiceResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, (void)context; EXPECT_EQ(errorCode, kDNSServiceErr_NoError); - EXPECT_STREQ(host, DZC_HOST_DEFAULT); + char hostname[UINT8_MAX+1] = {0}; + gethostname(hostname, UINT8_MAX); + char expectHost[NI_MAXHOST]= {0}; + (void)snprintf(expectHost, NI_MAXHOST, "%s.local.", hostname); + EXPECT_STREQ(host, expectHost); EXPECT_EQ(port, ntohs(DZC_PORT_DEFAULT)); celix_properties_t *prop = (celix_properties_t *)context; int cnt = TXTRecordGetCount(txtLen, txtRecord); @@ -168,58 +187,58 @@ static void OnServiceResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, static void OnServiceBrowseCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *instanceName, const char *regtype, const char *replyDomain, void *context) { EXPECT_NE(nullptr, sdRef); - DiscoveryZeroconfAnnouncerTestSuite *t = (DiscoveryZeroconfAnnouncerTestSuite *)context; + (void)context; EXPECT_EQ(errorCode, kDNSServiceErr_NoError); - if ((flags & kDNSServiceFlagsAdd) && (strstr(instanceName, "dzc_test_service") != nullptr) && (int)interfaceIndex == t->ifIndex) { + if ((flags & kDNSServiceFlagsAdd) && (strstr(instanceName, "dzc_test_service") != nullptr)) { DNSServiceRef dsRef{}; celix_properties_t *prop = celix_properties_create(); DNSServiceErrorType dnsErr = DNSServiceResolve(&dsRef, 0, interfaceIndex, instanceName, regtype, replyDomain, OnServiceResolveCallback, prop); EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); DNSServiceProcessResult(dsRef); - EXPECT_TRUE(celix_properties_getAsLong(prop, DZC_SERVICE_PROPERTIES_SIZE_KEY, 0) > 0); - //The txt record should not include DZC_SERVICE_ANNOUNCED_IF_INDEX_KEY,DZC_SERVICE_TYPE_KEY - EXPECT_EQ(nullptr, celix_properties_get(prop, CELIX_RSA_NETWORK_INTERFACES, nullptr)); - EXPECT_EQ(nullptr, celix_properties_get(prop, DZC_SERVICE_TYPE_KEY, nullptr)); + //The txt record should not include ifname and port key + EXPECT_EQ(nullptr, celix_properties_get(prop, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, nullptr)); + EXPECT_EQ(nullptr, celix_properties_get(prop, CELIX_RSA_PORT, nullptr)); DNSServiceRefDeallocate(dsRef); celix_properties_destroy(prop); } } -static void OnUseServiceCallback(void *handle, void *svc) { - DiscoveryZeroconfAnnouncerTestSuite *t = (DiscoveryZeroconfAnnouncerTestSuite *)handle; - endpoint_listener_t *epl = (endpoint_listener_t *)svc; - const char *fwUuid = celix_bundleContext_getProperty(t->ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); +static void TestAddEndpoint(celix_bundle_context *ctx, discovery_zeroconf_announcer_t *announcer, int ifIndex) { + const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, nullptr); celix_properties_t *properties = celix_properties_create(); - if (t->ifIndex == kDNSServiceInterfaceIndexAny) { - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, "all"); - } else if (t->ifIndex > 0) { + if (ifIndex == kDNSServiceInterfaceIndexAny) { + celix_properties_set(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, "all"); + } else if (ifIndex > 0) { char ifName[IF_NAMESIZE] = {0}; - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, if_indextoname(t->ifIndex, ifName)); + celix_properties_set(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, if_indextoname(ifIndex, ifName)); } - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, "100"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "dzc_test_config_type"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, "100"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, DZC_TEST_CONFIG_TYPE); endpoint_description_t *endpoint{}; auto status = endpointDescription_create(properties,&endpoint); EXPECT_EQ(status, CELIX_SUCCESS); - epl->endpointAdded(epl->handle, endpoint, nullptr); - int ifIndex = t->ifIndex; + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_SUCCESS); + int loopbackIfIndex = GetLoopBackIfIndex(); if (loopbackIfIndex != 0 && ifIndex == loopbackIfIndex) { // If it is a loopback interface,we will announce the service on the local only interface. ifIndex = kDNSServiceInterfaceIndexLocalOnly; } DNSServiceRef dsRef{nullptr}; - DNSServiceErrorType dnsErr = DNSServiceBrowse(&dsRef, 0, ifIndex, DZC_SERVICE_PRIMARY_TYPE, "local.", OnServiceBrowseCallback, t); + DNSServiceErrorType dnsErr = DNSServiceBrowse(&dsRef, 0, ifIndex, DZC_SERVICE_PRIMARY_TYPE, "local.", OnServiceBrowseCallback, + nullptr); EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); DNSServiceProcessResult(dsRef); DNSServiceRefDeallocate(dsRef); - epl->endpointRemoved(epl->handle, endpoint, nullptr); + status = discoveryZeroconfAnnouncer_endpointRemoved(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_SUCCESS); endpointDescription_destroy(endpoint); } @@ -228,9 +247,7 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddAndRemoveEndpoint) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - ifIndex = kDNSServiceInterfaceIndexAny; - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallback); - EXPECT_TRUE(found); + TestAddEndpoint(ctx.get(), announcer, kDNSServiceInterfaceIndexAny); discoveryZeroconfAnnouncer_destroy(announcer); } @@ -238,99 +255,122 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddAndRemoveLocalOnlyEndpoint) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - ifIndex = kDNSServiceInterfaceIndexLocalOnly; - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallback); - EXPECT_TRUE(found); + TestAddEndpoint(ctx.get(), announcer, kDNSServiceInterfaceIndexLocalOnly); discoveryZeroconfAnnouncer_destroy(announcer); } - - -static void OnUseServiceCallbackForRegisterServiceFailure(void *handle, void *svc) { - DiscoveryZeroconfAnnouncerTestSuite *t = (DiscoveryZeroconfAnnouncerTestSuite *)handle; - endpoint_listener_t *epl = (endpoint_listener_t *)svc; - const char *fwUuid = celix_bundleContext_getProperty(t->ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); - celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); - celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, "100"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "dzc_test_config_type"); - endpoint_description_t *endpoint{}; - auto status = endpointDescription_create(properties,&endpoint); +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddAndRemoveEndpointOnSpecificInterface) { + discovery_zeroconf_announcer_t *announcer{}; + auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); + int ifIndex = 0; + struct ifaddrs *ifaddr, *ifa; + if (getifaddrs(&ifaddr) != -1) + { + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == nullptr) + continue; - epl->endpointAdded(epl->handle, endpoint, nullptr); - sleep(1); - epl->endpointRemoved(epl->handle, endpoint, nullptr); + ifIndex = (int)if_nametoindex(ifa->ifa_name);// use non-loopback interface first, if not exist, use loopback interface + if (!(ifa->ifa_flags & IFF_LOOPBACK)) { + break; + } + } + freeifaddrs(ifaddr); + } - endpointDescription_destroy(endpoint); -} + TestAddEndpoint(ctx.get(), announcer, ifIndex); -TEST_F(DiscoveryZeroconfAnnouncerTestSuite, SetTxtRecordFailed) { - discovery_zeroconf_announcer_t *announcer{}; - auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); - EXPECT_EQ(status, CELIX_SUCCESS); - celix_ei_expect_TXTRecordSetValue(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_NoMemory, 2); - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallbackForRegisterServiceFailure); - EXPECT_TRUE(found); discoveryZeroconfAnnouncer_destroy(announcer); } -TEST_F(DiscoveryZeroconfAnnouncerTestSuite, FailedToRegisterService) { +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddAndRemoveSameNameService) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - celix_ei_expect_DNSServiceRegister(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallbackForRegisterServiceFailure); - EXPECT_TRUE(found); - discoveryZeroconfAnnouncer_destroy(announcer); -} -static void OnUseServiceCallbackForNameConflict(void *handle, void *svc) { - DiscoveryZeroconfAnnouncerTestSuite *t = (DiscoveryZeroconfAnnouncerTestSuite *)handle; - endpoint_listener_t *epl = (endpoint_listener_t *)svc; - const char *fwUuid = celix_bundleContext_getProperty(t->ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); - celix_properties_t *properties = celix_properties_create(); - if (t->ifIndex == kDNSServiceInterfaceIndexAny) { - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, "all"); - } else if (t->ifIndex > 0) { - char ifName[IF_NAMESIZE] = {0}; - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, if_indextoname(t->ifIndex, ifName)); - } - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); - celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, "100"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "dzc_test_config_type"); - endpoint_description_t *endpoint{}; - auto status = endpointDescription_create(properties,&endpoint); + const char *fwUuid = celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); + celix_properties_t *properties1 = celix_properties_create(); + celix_properties_set(properties1, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(properties1, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); + celix_properties_set(properties1, CELIX_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); + celix_properties_setLong(properties1, CELIX_RSA_ENDPOINT_SERVICE_ID, 100); + celix_properties_set(properties1, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties1, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, DZC_TEST_CONFIG_TYPE); + endpoint_description_t *endpoint1{}; + status = endpointDescription_create(properties1,&endpoint1); + EXPECT_EQ(status, CELIX_SUCCESS); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint1, nullptr); EXPECT_EQ(status, CELIX_SUCCESS); - celix_ei_expect_DNSServiceRegister(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_NameConflict); + celix_properties_t *properties2 = celix_properties_copy(properties1); + celix_properties_set(properties2, CELIX_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d20"); + endpoint_description_t *endpoint2{}; + status = endpointDescription_create(properties2,&endpoint2); + EXPECT_EQ(status, CELIX_SUCCESS); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint2, nullptr); + EXPECT_EQ(status, CELIX_SUCCESS); + + status = discoveryZeroconfAnnouncer_endpointRemoved(announcer, endpoint2, nullptr); + EXPECT_EQ(status, CELIX_SUCCESS); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint2, nullptr); + EXPECT_EQ(status, CELIX_SUCCESS); - epl->endpointAdded(epl->handle, endpoint, nullptr); + status = discoveryZeroconfAnnouncer_endpointRemoved(announcer, endpoint1, nullptr); + EXPECT_EQ(status, CELIX_SUCCESS); DNSServiceRef dsRef{nullptr}; - DNSServiceErrorType dnsErr = DNSServiceBrowse(&dsRef, 0, t->ifIndex, DZC_SERVICE_PRIMARY_TYPE, "local.", OnServiceBrowseCallback, t); + DNSServiceErrorType dnsErr = DNSServiceBrowse(&dsRef, 0, 0, DZC_SERVICE_PRIMARY_TYPE, "local.", [](DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, const char *, void *){}, + nullptr); EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); DNSServiceProcessResult(dsRef); DNSServiceRefDeallocate(dsRef); - epl->endpointRemoved(epl->handle, endpoint, nullptr); + status = discoveryZeroconfAnnouncer_endpointRemoved(announcer, endpoint2, nullptr); + EXPECT_EQ(status, CELIX_SUCCESS); + + endpointDescription_destroy(endpoint1); + endpointDescription_destroy(endpoint2); + + discoveryZeroconfAnnouncer_destroy(announcer); +} + +static void TestAddEndPointForRegisterServiceFailure(celix_bundle_context *ctx, discovery_zeroconf_announcer_t *announcer) { + const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, nullptr); + celix_properties_t *properties = celix_properties_create(); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, "100"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, DZC_TEST_CONFIG_TYPE); + endpoint_description_t *endpoint{}; + auto status = endpointDescription_create(properties,&endpoint); + EXPECT_EQ(status, CELIX_SUCCESS); + + discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + sleep(1); + discoveryZeroconfAnnouncer_endpointRemoved(announcer, endpoint, nullptr); endpointDescription_destroy(endpoint); } -TEST_F(DiscoveryZeroconfAnnouncerTestSuite, RegisterServiceNameConflict) { +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, SetTxtRecordFailed) { + discovery_zeroconf_announcer_t *announcer{}; + auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); + EXPECT_EQ(status, CELIX_SUCCESS); + celix_ei_expect_TXTRecordSetValue(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_NoMemory, 3); + TestAddEndPointForRegisterServiceFailure(ctx.get(), announcer); + discoveryZeroconfAnnouncer_destroy(announcer); +} + +TEST_F(DiscoveryZeroconfAnnouncerTestSuite, FailedToRegisterService) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - ifIndex = kDNSServiceInterfaceIndexLocalOnly; - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallbackForNameConflict); - EXPECT_TRUE(found); + celix_ei_expect_DNSServiceRegister(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); + TestAddEndPointForRegisterServiceFailure(ctx.get(), announcer); discoveryZeroconfAnnouncer_destroy(announcer); } @@ -338,10 +378,8 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, HandleMDNSEventFailed1) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - ifIndex = kDNSServiceInterfaceIndexLocalOnly; celix_ei_expect_DNSServiceProcessResult(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_ServiceNotRunning); - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallback); - EXPECT_TRUE(found); + TestAddEndpoint(ctx.get(), announcer, kDNSServiceInterfaceIndexLocalOnly); discoveryZeroconfAnnouncer_destroy(announcer); } @@ -349,10 +387,8 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, HandleMDNSEventFailed2) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - ifIndex = kDNSServiceInterfaceIndexLocalOnly; celix_ei_expect_DNSServiceProcessResult(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallback); - EXPECT_TRUE(found); + TestAddEndpoint(ctx.get(), announcer, kDNSServiceInterfaceIndexLocalOnly); discoveryZeroconfAnnouncer_destroy(announcer); } @@ -388,28 +424,22 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddAndRemoveLoopBackEndpoint) { auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); ifIndex = GetLoopBackIfIndex(); - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceCallback); - EXPECT_TRUE(found); + TestAddEndpoint(ctx.get(), announcer, ifIndex); discoveryZeroconfAnnouncer_destroy(announcer); } -static void OnUseServiceWithJumboEndpointCallback(void *handle, void *svc) { - DiscoveryZeroconfAnnouncerTestSuite *t = (DiscoveryZeroconfAnnouncerTestSuite *)handle; - endpoint_listener_t *epl = (endpoint_listener_t *)svc; - const char *fwUuid = celix_bundleContext_getProperty(t->ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); +static void TestAddJumboEndpoint(celix_bundle_context *ctx, discovery_zeroconf_announcer_t *announcer, int ifIndex) { + const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, nullptr); celix_properties_t *properties = celix_properties_create(); - if (t->ifIndex == kDNSServiceInterfaceIndexAny) { - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, "all"); - } else if (t->ifIndex > 0) { - char ifName[IF_NAMESIZE] = {0}; - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, if_indextoname(t->ifIndex, ifName)); + if (ifIndex == kDNSServiceInterfaceIndexAny) { + celix_properties_set(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, "all"); } - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, "100"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "dzc_test_config_type"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, "100"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, DZC_TEST_CONFIG_TYPE); for (int i = 0; i < 500; ++i) { char key[20]{}; sprintf(key,"custom_key%d", i); @@ -419,15 +449,15 @@ static void OnUseServiceWithJumboEndpointCallback(void *handle, void *svc) { auto status = endpointDescription_create(properties,&endpoint); EXPECT_EQ(status, CELIX_SUCCESS); - epl->endpointAdded(epl->handle, endpoint, nullptr); + discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); DNSServiceRef dsRef{}; - DNSServiceErrorType dnsErr = DNSServiceBrowse(&dsRef, 0, 0, DZC_SERVICE_PRIMARY_TYPE, "local.", OnServiceBrowseCallback, t); + DNSServiceErrorType dnsErr = DNSServiceBrowse(&dsRef, 0, 0, DZC_SERVICE_PRIMARY_TYPE, "local.", [](DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char*, const char*, const char*, void* ){}, NULL); EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); DNSServiceProcessResult(dsRef); DNSServiceRefDeallocate(dsRef); - epl->endpointRemoved(epl->handle, endpoint, nullptr); + discoveryZeroconfAnnouncer_endpointRemoved(announcer, endpoint, nullptr); endpointDescription_destroy(endpoint); } @@ -436,9 +466,7 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddJumboEndpoint) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - ifIndex = kDNSServiceInterfaceIndexAny; - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceWithJumboEndpointCallback); - EXPECT_TRUE(found); + TestAddJumboEndpoint(ctx.get(), announcer, kDNSServiceInterfaceIndexAny); discoveryZeroconfAnnouncer_destroy(announcer); } @@ -446,43 +474,66 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddLocalOnlyJumboEndpoint) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - ifIndex = kDNSServiceInterfaceIndexLocalOnly; - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceWithJumboEndpointCallback); - EXPECT_TRUE(found); + TestAddJumboEndpoint(ctx.get(), announcer, kDNSServiceInterfaceIndexLocalOnly); discoveryZeroconfAnnouncer_destroy(announcer); } -static void OnUseServiceWithInvalidEndpointCallback(void *handle, void *svc) { - DiscoveryZeroconfAnnouncerTestSuite *t = (DiscoveryZeroconfAnnouncerTestSuite *)handle; - endpoint_listener_t *epl = (endpoint_listener_t *)svc; +static void TestAddInvalidEndpoint(celix_bundle_context *ctx, discovery_zeroconf_announcer_t *announcer) { celix_status_t status; - status = epl->endpointAdded(epl->handle, nullptr, nullptr); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, nullptr, nullptr); EXPECT_EQ(status, CELIX_ILLEGAL_ARGUMENT); - status = epl->endpointRemoved(epl->handle, nullptr, nullptr); + status = discoveryZeroconfAnnouncer_endpointRemoved(announcer, nullptr, nullptr); EXPECT_EQ(status, CELIX_ILLEGAL_ARGUMENT); - const char *fwUuid = celix_bundleContext_getProperty(t->ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); + const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, nullptr); celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, "100"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "dzc_test_config_type"); - celix_properties_set(properties, DZC_SERVICE_TYPE_KEY, "invalid_service_type_because_the_size_large_than_48"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, "100"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, "celix.invalid_service_type_because_the_size_large_than_64_----------------"); endpoint_description_t *endpoint{}; status = endpointDescription_create(properties,&endpoint); EXPECT_EQ(status, CELIX_SUCCESS); //Invalid service type - status = epl->endpointAdded(epl->handle, endpoint, nullptr); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + + //ifname not exist + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, DZC_TEST_CONFIG_TYPE); + celix_properties_set(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, "if_not_exist"); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ILLEGAL_ARGUMENT); + + //ifname too long + celix_properties_set(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, "ifname__too__long"); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ILLEGAL_ARGUMENT); + + //too many imported configs + char configTypes[256] = "config_type"; + auto offset = strlen(configTypes); + int i = 0; + while (offset < 256) { + offset += snprintf(configTypes + offset, 256 - offset, ",config_type-%d", ++i); + } + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, configTypes); + celix_properties_unset(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + + //lost imported config + celix_properties_unset(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); EXPECT_EQ(status, CELIX_ILLEGAL_ARGUMENT); //lost service name - celix_properties_unset(properties, DZC_SERVICE_TYPE_KEY); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, DZC_TEST_CONFIG_TYPE); celix_properties_unset(properties, CELIX_FRAMEWORK_SERVICE_NAME); - status = epl->endpointAdded(epl->handle, endpoint, nullptr); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); EXPECT_EQ(status, CELIX_ILLEGAL_ARGUMENT); endpointDescription_destroy(endpoint); @@ -492,37 +543,63 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddInvalidEndpoint) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceWithInvalidEndpointCallback); - EXPECT_TRUE(found); + TestAddInvalidEndpoint(ctx.get(), announcer); discoveryZeroconfAnnouncer_destroy(announcer); } -static void OnUseServiceForAddEndpointENOMEM(void *handle, void *svc) { - DiscoveryZeroconfAnnouncerTestSuite *t = (DiscoveryZeroconfAnnouncerTestSuite *)handle; - endpoint_listener_t *epl = (endpoint_listener_t *)svc; - const char *fwUuid = celix_bundleContext_getProperty(t->ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); +static void TestAddEndpointWithENOMEM(celix_bundle_context *ctx, discovery_zeroconf_announcer_t *announcer) { + const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, nullptr); celix_properties_t *properties = celix_properties_create(); - if (t->ifIndex == kDNSServiceInterfaceIndexAny) { - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, "all"); - } else if (t->ifIndex > 0) { - char ifName[IF_NAMESIZE] = {0}; - celix_properties_set(properties, CELIX_RSA_NETWORK_INTERFACES, if_indextoname(t->ifIndex, ifName)); - } - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, "dzc_test_service"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, "100"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "dzc_test_config_type"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "60f49d89-d105-430c-b12b-93fbb54b1d19"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, "100"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, DZC_TEST_CONFIG_TYPE); endpoint_description_t *endpoint{}; auto status = endpointDescription_create(properties,&endpoint); EXPECT_EQ(status, CELIX_SUCCESS); + celix_ei_expect_celix_properties_copy(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + celix_ei_expect_celix_properties_copy(nullptr, 0, nullptr); + + celix_ei_expect_celix_stringHashMap_createWithOptions(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + celix_ei_expect_celix_stringHashMap_createWithOptions(nullptr, 0, nullptr); + + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); + + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + celix_ei_expect_celix_stringHashMap_put(nullptr, 0, 0); + celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); - status = epl->endpointAdded(epl->handle, endpoint, nullptr); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 2); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); + + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM, 2); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); + EXPECT_EQ(status, CELIX_ENOMEM); + celix_ei_expect_celix_stringHashMap_put(nullptr, 0, 0); + + celix_ei_expect_celix_stringHashMap_putLong(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM); + status = discoveryZeroconfAnnouncer_endpointAdded(announcer, endpoint, nullptr); EXPECT_EQ(status, CELIX_ENOMEM); + celix_ei_expect_celix_stringHashMap_putLong(nullptr, 0, 0); - epl->endpointRemoved(epl->handle, endpoint, nullptr); + discoveryZeroconfAnnouncer_endpointRemoved(announcer, endpoint, nullptr); endpointDescription_destroy(endpoint); } @@ -531,7 +608,6 @@ TEST_F(DiscoveryZeroconfAnnouncerTestSuite, AddEndpointENOMEM) { discovery_zeroconf_announcer_t *announcer{}; auto status = discoveryZeroconfAnnouncer_create(ctx.get(), logHelper.get(), &announcer); EXPECT_EQ(status, CELIX_SUCCESS); - auto found = celix_bundleContext_useService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE, this, OnUseServiceForAddEndpointENOMEM); - EXPECT_TRUE(found); + TestAddEndpointWithENOMEM(ctx.get(), announcer); discoveryZeroconfAnnouncer_destroy(announcer); } diff --git a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfIntegrationTestSuite.cc b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfIntegrationTestSuite.cc index 704b28cce..c91b571f0 100644 --- a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfIntegrationTestSuite.cc +++ b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfIntegrationTestSuite.cc @@ -44,6 +44,6 @@ class DiscoveryZeroconfIntegrationTestSuite : public ::testing::Test { }; TEST_F(DiscoveryZeroconfIntegrationTestSuite, FindEndpointListener) { - auto found = celix_bundleContext_findService(ctx.get(), OSGI_ENDPOINT_LISTENER_SERVICE); + auto found = celix_bundleContext_findService(ctx.get(), CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME); EXPECT_TRUE(found); } diff --git a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfWatcherTestSuite.cc b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfWatcherTestSuite.cc index 677d7c8bd..ebf332c0a 100644 --- a/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfWatcherTestSuite.cc +++ b/bundles/remote_services/discovery_zeroconf/gtest/src/DiscoveryZeroconfWatcherTestSuite.cc @@ -18,11 +18,15 @@ */ #include "discovery_zeroconf_watcher.h" #include "discovery_zeroconf_constants.h" +#include "remote_service_admin.h" #include "endpoint_listener.h" -#include #include "remote_constants.h" #include "celix_threads_ei.h" #include "celix_bundle_context_ei.h" +#include "celix_string_hash_map_ei.h" +#include "celix_long_hash_map_ei.h" +#include "celix_properties_ei.h" +#include "celix_utils_ei.h" #include "mdnsresponder_ei.h" #include "malloc_ei.h" #include "celix_framework.h" @@ -31,44 +35,95 @@ #include "celix_properties.h" #include "celix_constants.h" #include "celix_errno.h" +#include "celix_log_service.h" +#include "celix_log_utils.h" +#include "celix_log_constants.h" +#include #include #include #include -#include +#include #include +#include +#include +#include + +#define DZC_TEST_CONFIG_TYPE "celix.config_type.test" +#define DZC_TEST_SERVICE_TYPE DZC_SERVICE_PRIMARY_TYPE",test" //use the last word of config type as service subtype +#define DZC_TEST_SERVICE_PORT 60001 static const char *DZC_TEST_ENDPOINT_FW_UUID = "61EC83D5-A808-DA12-3615-B68376C35357"; -static sem_t syncSem; -static bool waitSyncSemTimeout(int s) { +static void OnDNSServiceRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *instanceName, const char *serviceType, const char *domain, void *data); +static DNSServiceRef RegisterTestService(int ifIndex = kDNSServiceInterfaceIndexLocalOnly, const char *endpointId = "60f49d89-d105-430c-b12b-93fbb54b1d19", const char *serviceId = "100"); + +static const char *expectErrMsg = nullptr; +static sem_t msgSyncSem; +static void vlogDetails(void *handle, + celix_log_level_e level, + const char* file, + const char* function, + int line, + const char* format, + va_list formatArgs) { + (void)handle; + if (expectErrMsg != nullptr && strcmp(expectErrMsg, format) == 0) { + sem_post(&msgSyncSem); + } + celix_logUtils_vLogToStdoutDetails("DiscoveryZeroconf", level, file, function, line, format, formatArgs); +} + +static void ExpectMsgOutPut(const char *msg) { + expectErrMsg = msg; +} +static bool CheckMsgWithTimeOutInS(int secs) { struct timespec ts{}; clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += s; + ts.tv_sec += secs; errno = 0; - while ((sem_timedwait(&syncSem, &ts)) == -1 && errno == EINTR) + while ((sem_timedwait(&msgSyncSem, &ts)) == -1 && errno == EINTR) continue; return errno == ETIMEDOUT; } static celix_status_t discoveryZeroconfWatcherTest_endpointAdded(void *handle, endpoint_description_t *endpoint, char *matchedFilter) { - (void)handle; + auto logHelper = static_cast(handle); (void)matchedFilter; - EXPECT_STREQ("60f49d89-d105-430c-b12b-93fbb54b1d19", endpoint->id); EXPECT_STREQ("dzc_test_service", endpoint->serviceName); - EXPECT_EQ(100, endpoint->serviceId); - sem_post(&syncSem); + celix_logHelper_info(logHelper, "Endpoint added: %s.", endpoint->id); return CELIX_SUCCESS; } static celix_status_t discoveryZeroconfWatcherTest_endpointRemoved(void *handle, endpoint_description_t *endpoint, char *matchedFilter) { - (void)handle; + auto logHelper = static_cast(handle); (void)endpoint; (void)matchedFilter; - + celix_logHelper_info(logHelper, "Endpoint removed: %s.", endpoint->id); return CELIX_SUCCESS; } +static int GetTestNetInterfaceIndex() { + int ifIndex = 0; + struct ifaddrs *ifaddr, *ifa; + if (getifaddrs(&ifaddr) != -1) + { + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == nullptr) + continue; + + ifIndex = (int)if_nametoindex(ifa->ifa_name);// use non-loopback interface first, if not exist, use loopback interface + if (!(ifa->ifa_flags & IFF_LOOPBACK)) { + break; + } + } + freeifaddrs(ifaddr); + } + return ifIndex; +} + + class DiscoveryZeroconfWatcherTestSuite : public ::testing::Test { public: static void SetUpTestCase() { @@ -83,15 +138,32 @@ class DiscoveryZeroconfWatcherTestSuite : public ::testing::Test { auto* props = celix_properties_create(); celix_properties_set(props, CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"); celix_properties_set(props, CELIX_FRAMEWORK_CACHE_DIR, ".dzc_watcher_test_cache"); + celix_properties_set(props, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME, "trace"); auto* fwPtr = celix_frameworkFactory_createFramework(props); auto* ctxPtr = celix_framework_getFrameworkContext(fwPtr); fw = std::shared_ptr{fwPtr, [](auto* f) {celix_frameworkFactory_destroyFramework(f);}}; ctx = std::shared_ptr{ctxPtr, [](auto*){/*nop*/}}; auto* logHelperPtr = celix_logHelper_create(ctxPtr,"DiscoveryZeroconf"); logHelper = std::shared_ptr{logHelperPtr, [](auto*l){ celix_logHelper_destroy(l);}}; - eplId = celix_bundleContext_registerService(ctxPtr, &epListener, OSGI_ENDPOINT_LISTENER_SERVICE, nullptr); + epListener.handle = logHelperPtr; + eplId = celix_bundleContext_registerService(ctxPtr, &epListener, CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, nullptr); EXPECT_LE(0, eplId); - sem_init(&syncSem, 0, 0); + auto rsaSvcProps = celix_properties_create(); + celix_properties_set(rsaSvcProps, CELIX_RSA_REMOTE_CONFIGS_SUPPORTED, DZC_TEST_CONFIG_TYPE); + rsaSvcId = celix_bundleContext_registerService(ctx.get(), (void*)"dummy_service", CELIX_RSA_REMOTE_SERVICE_ADMIN, rsaSvcProps); + EXPECT_LE(0, rsaSvcId); + logService.handle = nullptr; + logService.vlogDetails = vlogDetails; + celix_service_registration_options_t opts{}; + opts.svc = &logService; + opts.serviceName = CELIX_LOG_SERVICE_NAME; + opts.serviceVersion = CELIX_LOG_SERVICE_VERSION; + opts.properties = celix_properties_create(); + celix_properties_set(opts.properties, CELIX_LOG_SERVICE_PROPERTY_NAME, "DiscoveryZeroconf"); + lsId = celix_bundleContext_registerServiceWithOptions(ctxPtr, &opts); + EXPECT_LE(0, lsId); + + sem_init(&msgSyncSem, 0, 0); } ~DiscoveryZeroconfWatcherTestSuite() override { @@ -102,18 +174,211 @@ class DiscoveryZeroconfWatcherTestSuite : public ::testing::Test { celix_ei_expect_DNSServiceCreateConnection(nullptr, 0, 0); celix_ei_expect_DNSServiceBrowse(nullptr, 0, 0); celix_ei_expect_DNSServiceProcessResult(nullptr, 0, 0); + celix_ei_expect_DNSServiceResolve(nullptr, 0, 0, 0); + celix_ei_expect_DNSServiceGetAddrInfo(nullptr, 0, 0, 0); celix_ei_expect_calloc(nullptr, 0, nullptr); - - sem_destroy(&syncSem); + celix_ei_expect_celix_stringHashMap_create(nullptr, 0, nullptr); + celix_ei_expect_celix_stringHashMap_createWithOptions(nullptr, 0, nullptr); + celix_ei_expect_celix_longHashMap_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_copy(nullptr, 0, nullptr); + celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); + celix_ei_expect_celix_stringHashMap_put(nullptr, 0, 0); + + sem_destroy(&msgSyncSem); + celix_bundleContext_unregisterService(ctx.get(), lsId); + celix_bundleContext_unregisterService(ctx.get(), rsaSvcId); celix_bundleContext_unregisterService(ctx.get(), eplId); } + long TrackRsaService(discovery_zeroconf_watcher_t *watcher) { + celix_service_tracking_options_t opts{}; + opts.filter.serviceName = CELIX_RSA_REMOTE_SERVICE_ADMIN; + opts.filter.filter = "(remote.configs.supported=*)"; + opts.callbackHandle = watcher; + opts.addWithProperties = [](void *handle, void *svc, const celix_properties_t *props) { + discoveryZeroConfWatcher_addRSA(handle, svc, props); + }; + opts.removeWithProperties = [](void *handle, void *svc, const celix_properties_t *props) { + discoveryZeroConfWatcher_removeRSA(handle, svc, props); + }; + auto id = celix_bundleContext_trackServicesWithOptions(ctx.get(), &opts); + EXPECT_GT(id, 0); + return id; + } + + long TrackEndpointListenerService(discovery_zeroconf_watcher_t *watcher) { + celix_service_tracking_options_t opts{}; + opts.filter.serviceName = CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME; + opts.callbackHandle = watcher; + opts.addWithProperties = [](void *handle, void *svc, const celix_properties_t *props) { + discoveryZeroconfWatcher_addEPL(handle, svc, props); + }; + opts.removeWithProperties = [](void *handle, void *svc, const celix_properties_t *props) { + discoveryZeroconfWatcher_removeEPL(handle, svc, props); + }; + auto id = celix_bundleContext_trackServicesWithOptions(ctx.get(), &opts); + EXPECT_GT(id, 0); + return id; + } + + void TestRsaServiceAddAndRemove(void (*beforeAddRsaAction)(void), void (*afterAddRsaAction)(void), + void (*beforeRemoveRsaAction)(void) = nullptr, void (*afterRemoveRsaAction)(void) = nullptr, const char *remoteConfigsSupported = DZC_TEST_CONFIG_TYPE) { + celix_bundleContext_unregisterService(ctx.get(), rsaSvcId);//reset rsa service + rsaSvcId = -1; + discovery_zeroconf_watcher_t *watcher; + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + + beforeAddRsaAction(); + + auto rsaSvcProps = celix_properties_create(); + celix_properties_set(rsaSvcProps, CELIX_RSA_REMOTE_CONFIGS_SUPPORTED, remoteConfigsSupported); + auto rsaId = celix_bundleContext_registerService(ctx.get(), (void*)"dummy_service", CELIX_RSA_REMOTE_SERVICE_ADMIN, rsaSvcProps); + EXPECT_LE(0, rsaId); + auto trkId = TrackRsaService(watcher); + + afterAddRsaAction(); + + if (beforeRemoveRsaAction != nullptr) { + beforeRemoveRsaAction(); + } + + celix_bundleContext_stopTracker(ctx.get(), trkId); + celix_bundleContext_unregisterService(ctx.get(), rsaId); + + if (afterRemoveRsaAction != nullptr) { + afterRemoveRsaAction(); + } + + discoveryZeroconfWatcher_destroy(watcher); + + } + + void TestAddEndpoint(void (*beforeAddEndpoint)(void), void (*afterAddEndpoint)(void), int ifIndex = kDNSServiceInterfaceIndexLocalOnly) { + discovery_zeroconf_watcher_t *watcher; + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + auto eplTrkId = TrackEndpointListenerService(watcher); + + beforeAddEndpoint(); + + auto rsaTrkId = TrackRsaService(watcher); + + auto dsRef = RegisterTestService(ifIndex); + + afterAddEndpoint(); + + DNSServiceRefDeallocate(dsRef); + + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + discoveryZeroconfWatcher_destroy(watcher); + } + + void TestInvalidTxtRecord(void (*beforeAddTxt)(TXTRecordRef *txtRecord), void (*afterAddTxt)(void)) { + discovery_zeroconf_watcher_t *watcher; + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + + char txtBuf[1300] = {0}; + TXTRecordRef txtRecord; + TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); + + beforeAddTxt(&txtRecord); + + char propSizeStr[16]= {0}; + sprintf(propSizeStr, "%d", TXTRecordGetCount(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord)) + 1); + TXTRecordSetValue(&txtRecord, DZC_SERVICE_PROPERTIES_SIZE_KEY, strlen(propSizeStr), propSizeStr); + DNSServiceRef dsRef{}; + DNSServiceErrorType dnsErr; + dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexLocalOnly, "dzc_test_service", + DZC_TEST_SERVICE_TYPE, "local", nullptr, htons(DZC_TEST_SERVICE_PORT), + TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), + OnDNSServiceRegisterCallback, nullptr); + EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); + DNSServiceProcessResult(dsRef); + + afterAddTxt(); + + DNSServiceRefDeallocate(dsRef); + + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + discoveryZeroconfWatcher_destroy(watcher); + } + + void TestGetAddrInfo(void (*beforeRegServiceAction)(void), void (*afterRegServiceAction)(void)) { + discovery_zeroconf_watcher_t *watcher; + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + auto eplTrkId = TrackEndpointListenerService(watcher); + + beforeRegServiceAction(); + + DNSServiceRef dsRef = RegisterTestService(kDNSServiceInterfaceIndexAny); + + afterRegServiceAction(); + + DNSServiceRefDeallocate(dsRef); + + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + discoveryZeroconfWatcher_destroy(watcher); + } + std::shared_ptr fw{}; std::shared_ptr ctx{}; std::shared_ptr logHelper{}; endpoint_listener_t epListener{nullptr,discoveryZeroconfWatcherTest_endpointAdded, discoveryZeroconfWatcherTest_endpointRemoved}; + celix_log_service_t logService{}; long eplId{-1}; + long lsId{-1}; + long rsaSvcId{-1}; +}; + + +class DiscoveryZeroconfWatcherWatchServiceTestSuite : public DiscoveryZeroconfWatcherTestSuite { +public: + static void SetUpTestCase() { + (void)system(MDNSD); + sleep(3);//wait for mdnsd start + testServiceRef = RegisterTestService(GetTestNetInterfaceIndex()); + EXPECT_TRUE(testServiceRef != nullptr); + } + + static void TearDownTestCase() { + DNSServiceRefDeallocate(testServiceRef); + (void)system("kill -s 9 `ps -aux | grep mdnsd | awk '{print $2}'`"); + } + + DiscoveryZeroconfWatcherWatchServiceTestSuite() { + discovery_zeroconf_watcher_t *watcherPtr{}; + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcherPtr); + EXPECT_EQ(CELIX_SUCCESS, status); + (void)GetTestNetInterfaceIndex; + watcher = std::shared_ptr{watcherPtr, [](auto w){discoveryZeroconfWatcher_destroy(w);}}; + } + + ~DiscoveryZeroconfWatcherWatchServiceTestSuite() override = default; + + void TestWatchService(void (*beforeWatchServiceAction)(void), void (*afterWatchServiceAction)(void)) { + + beforeWatchServiceAction(); + + auto eplTrkId = TrackEndpointListenerService(watcher.get()); + auto rsaTrkId = TrackRsaService(watcher.get()); + + afterWatchServiceAction(); + + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + } + + std::shared_ptr watcher{}; + static DNSServiceRef testServiceRef; }; +DNSServiceRef DiscoveryZeroconfWatcherWatchServiceTestSuite::testServiceRef{nullptr}; TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateAndDestroyWatcher) { discovery_zeroconf_watcher_t *watcher; @@ -149,12 +414,6 @@ TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed2) { EXPECT_EQ(CELIX_ENOMEM, status); } -TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed3) { - discovery_zeroconf_watcher_t *watcher; - celix_ei_expect_celix_bundleContext_trackServicesWithOptionsAsync((void*)&discoveryZeroconfWatcher_create, 0, -1); - celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); - EXPECT_EQ(CELIX_BUNDLE_EXCEPTION, status); -} TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed4) { discovery_zeroconf_watcher_t *watcher; @@ -170,6 +429,109 @@ TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed5) { EXPECT_EQ(CELIX_ENOMEM, status); } +TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed6) { + discovery_zeroconf_watcher_t *watcher; + celix_ei_expect_celix_stringHashMap_create((void*)&discoveryZeroconfWatcher_create, 0, nullptr); + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed7) { + discovery_zeroconf_watcher_t *watcher; + celix_ei_expect_celix_stringHashMap_createWithOptions((void*)&discoveryZeroconfWatcher_create, 0, nullptr); + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed8) { + discovery_zeroconf_watcher_t *watcher; + celix_ei_expect_celix_stringHashMap_create((void*)&discoveryZeroconfWatcher_create, 0, nullptr, 2); + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed9) { + discovery_zeroconf_watcher_t *watcher; + celix_ei_expect_celix_stringHashMap_create((void*)&discoveryZeroconfWatcher_create, 0, nullptr, 3); + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateWatcherFailed10) { + discovery_zeroconf_watcher_t *watcher; + celix_ei_expect_celix_longHashMap_create((void*)&discoveryZeroconfWatcher_create, 0, nullptr); + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_ENOMEM, status); +} + + +TEST_F(DiscoveryZeroconfWatcherTestSuite, AddRsaServiceWithOutRemoteConfigsSupported) { + TestRsaServiceAddAndRemove([](){ + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + ExpectMsgOutPut("Watcher: Failed to dup remote configs supported."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(1); + EXPECT_FALSE(timeOut); + }, [](){ + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + ExpectMsgOutPut("Watcher: Failed to dup remote configs supported."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(1); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, AddRsaServiceWithInvalidRemoteConfigsSupported) { + TestRsaServiceAddAndRemove([](){ + ExpectMsgOutPut("Watcher: Invalid service type for %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(1); + EXPECT_FALSE(timeOut); + }, nullptr, nullptr, "celix.config_type_last_word_lager_than_63-----------------------------"); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToAllocMemoryForBrowserEntry) { + TestRsaServiceAddAndRemove([](){ + celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + ExpectMsgOutPut("Watcher: Failed to alloc service browser entry."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(1); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToCreateServiceMapForBrowserEntry) { + celix_ei_expect_DNSServiceCreateConnection(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); + ExpectMsgOutPut("Watcher: Failed to create connection for DNS service, %d.");//it is used for sync work thread + TestRsaServiceAddAndRemove([](){ + auto timeOut = CheckMsgWithTimeOutInS(1);//wait for work thread run + EXPECT_FALSE(timeOut); + celix_ei_expect_celix_stringHashMap_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + ExpectMsgOutPut("Watcher: Failed to create watched services map."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(1); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToPutBrowserEntryToCache) { + TestRsaServiceAddAndRemove([](){ + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM); + ExpectMsgOutPut("Watcher: Failed to put service browser entry."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(1); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, AddRsaServiceWithNoNameSpaceConfigType) { + TestRsaServiceAddAndRemove([](){}, [](){}, nullptr, nullptr, "config_type_without_namespace"); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, AddRsaServiceWithMultiConfigTypes) { + TestRsaServiceAddAndRemove([](){}, [](){}, nullptr, nullptr, "celix.test1.http,celix.test1.http-json,celix.test2.http,celix.test2.http-json"); +} + static void OnDNSServiceRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *instanceName, const char *serviceType, const char *domain, void *data) { (void)sdRef;//unused (void)data;//unused @@ -181,107 +543,358 @@ static void OnDNSServiceRegisterCallback(DNSServiceRef sdRef, DNSServiceFlags fl return; } -static DNSServiceRef RegisterTestService(void) { +static DNSServiceRef RegisterTestService(int ifIndex, const char *endpointId, const char *serviceId) { char txtBuf[1300] = {0}; TXTRecordRef txtRecord; TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, strlen(DZC_TEST_ENDPOINT_FW_UUID), DZC_TEST_ENDPOINT_FW_UUID); + TXTRecordSetValue(&txtRecord, DZC_TXT_RECORD_VERSION_KEY, sizeof(DZC_CURRENT_TXT_RECORD_VERSION)-1, DZC_CURRENT_TXT_RECORD_VERSION); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, strlen(DZC_TEST_ENDPOINT_FW_UUID), DZC_TEST_ENDPOINT_FW_UUID); TXTRecordSetValue(&txtRecord, CELIX_FRAMEWORK_SERVICE_NAME, strlen("dzc_test_service"), "dzc_test_service"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_ID, strlen("60f49d89-d105-430c-b12b-93fbb54b1d19"), "60f49d89-d105-430c-b12b-93fbb54b1d19"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_SERVICE_ID, strlen("100"), "100"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED, strlen("true"), "true"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, strlen("dzc_test_config_type"), "dzc_test_config_type"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_ID, strlen(endpointId), endpointId); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_SERVICE_ID, strlen(serviceId), serviceId); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED, strlen("true"), "true"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, sizeof(DZC_TEST_CONFIG_TYPE) - 1, DZC_TEST_CONFIG_TYPE); + TXTRecordSetValue(&txtRecord, CELIX_RSA_IP_ADDRESSES, 0, nullptr); char propSizeStr[16]= {0}; sprintf(propSizeStr, "%d", TXTRecordGetCount(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord)) + 1); TXTRecordSetValue(&txtRecord, DZC_SERVICE_PROPERTIES_SIZE_KEY, strlen(propSizeStr), propSizeStr); DNSServiceRef dsRef{}; - DNSServiceErrorType dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexLocalOnly, "dzc_test_service", DZC_SERVICE_PRIMARY_TYPE, "local", DZC_HOST_DEFAULT, htons(DZC_PORT_DEFAULT), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback,nullptr); - EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); - DNSServiceProcessResult(dsRef); + DNSServiceErrorType dnsErr; + static int conflictCount = 0; + conflictCount++;//avoid conflict + char name[32]={0}; + snprintf(name, sizeof(name), "dzc_test_service_%d", conflictCount); + dnsErr = DNSServiceRegister(&dsRef, 0, ifIndex, name, + DZC_TEST_SERVICE_TYPE, "local", nullptr, htons(DZC_TEST_SERVICE_PORT), + TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), + OnDNSServiceRegisterCallback, nullptr); + if (dnsErr == kDNSServiceErr_NoError) { + DNSServiceProcessResult(dsRef); + } + return dsRef; } TEST_F(DiscoveryZeroconfWatcherTestSuite, AddAndRemoveEndpoint) { + TestAddEndpoint([](){ + ExpectMsgOutPut("Endpoint added: %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToCopyEndpointProperties) { + TestAddEndpoint([](){ + celix_ei_expect_celix_properties_copy(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + ExpectMsgOutPut("Watcher: Failed to copy endpoint properties."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToAllocMemoryForEndpointEntry) { + TestAddEndpoint([](){ + //first calloc:service_browser_entry_t; second calloc:watched_service_entry_t; third calloc: endpointDescription_create + celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 4); + ExpectMsgOutPut("Watcher: Failed to alloc endpoint entry."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToCopyHostNameForEndpointEntry) { + TestAddEndpoint([](){ + //celix_utils_strdup call: first:addRsa; second:OnServiceResolveCallback; third: endpointDescription_create + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 4); + ExpectMsgOutPut("Watcher: Failed to dup hostname for endpoint %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToGetLocalHostIpAddressesWhenCreateEndpoint) { + TestAddEndpoint([](){ + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 5); + ExpectMsgOutPut("Watcher: Failed to create endpoint for %s. %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }, kDNSServiceInterfaceIndexLocalOnly); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToPutEndpointToCache) { + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM, 4); + TestAddEndpoint([](){ + ExpectMsgOutPut("Watcher: Failed to add endpoint for %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, InvalidEndpoint) { + TestInvalidTxtRecord([](TXTRecordRef *txtRecord){ + TXTRecordSetValue(txtRecord, DZC_TXT_RECORD_VERSION_KEY, sizeof(DZC_CURRENT_TXT_RECORD_VERSION)-1, DZC_CURRENT_TXT_RECORD_VERSION); + TXTRecordSetValue(txtRecord, CELIX_RSA_ENDPOINT_ID, sizeof("65d17a8c-f31b-478c-b13e-da743c96ab51")-1, "65d17a8c-f31b-478c-b13e-da743c96ab51"); + TXTRecordSetValue(txtRecord, CELIX_RSA_ENDPOINT_SERVICE_ID, sizeof("100")-1, "-1"); + TXTRecordSetValue(txtRecord, CELIX_RSA_SERVICE_IMPORTED, sizeof("true")-1, "true"); + TXTRecordSetValue(txtRecord, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, sizeof(DZC_TEST_CONFIG_TYPE)-1, DZC_TEST_CONFIG_TYPE); + //No endpoint framework uuid + ExpectMsgOutPut("Watcher: Failed to create endpoint description. %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateDNSServiceConnectionFailedOnce) { discovery_zeroconf_watcher_t *watcher; + + celix_ei_expect_DNSServiceCreateConnection(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); + ExpectMsgOutPut("Watcher: Failed to create connection for DNS service, %d."); + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); auto dsRef = RegisterTestService(); - auto timeOut = waitSyncSemTimeout(30); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); DNSServiceRefDeallocate(dsRef); - + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); discoveryZeroconfWatcher_destroy(watcher); } -TEST_F(DiscoveryZeroconfWatcherTestSuite, CreateDNSServiceConnectionFailedOnce) { +TEST_F(DiscoveryZeroconfWatcherTestSuite, DNSServiceBrowseFailedOnce) { discovery_zeroconf_watcher_t *watcher; - celix_ei_expect_DNSServiceCreateConnection(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); + celix_ei_expect_DNSServiceBrowse(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); + ExpectMsgOutPut("Watcher: Failed to browse DNS service, %d."); celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); auto dsRef = RegisterTestService(); - auto timeOut = waitSyncSemTimeout(30); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); DNSServiceRefDeallocate(dsRef); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); discoveryZeroconfWatcher_destroy(watcher); } -TEST_F(DiscoveryZeroconfWatcherTestSuite, DNSServiceBrowseFailedOnce) { +TEST_F(DiscoveryZeroconfWatcherTestSuite, BrowseServicesFailed1) { discovery_zeroconf_watcher_t *watcher; - celix_ei_expect_DNSServiceBrowse(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); + celix_ei_expect_celix_stringHashMap_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 4); + ExpectMsgOutPut("Watcher: Failed to create updated service browsers cache."); + + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + discoveryZeroconfWatcher_destroy(watcher); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, BrowseServicesFailed2) { + discovery_zeroconf_watcher_t *watcher; + + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM, 2); + ExpectMsgOutPut("Watcher: Failed to put browse entry, %d."); celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); auto dsRef = RegisterTestService(); - auto timeOut = waitSyncSemTimeout(30); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); DNSServiceRefDeallocate(dsRef); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); discoveryZeroconfWatcher_destroy(watcher); } -TEST_F(DiscoveryZeroconfWatcherTestSuite, DNSServiceResultProcessFailed1) { +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToDeleteServiceBrowser) { discovery_zeroconf_watcher_t *watcher; - celix_ei_expect_DNSServiceProcessResult(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_ServiceNotRunning, 2); + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + auto eplTrkId = TrackEndpointListenerService(watcher); + + ExpectMsgOutPut("Endpoint added: %s."); + + auto dsRef = RegisterTestService(); + + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM); + ExpectMsgOutPut("Watcher: Failed to put browse entry, %d."); + + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + + timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + DNSServiceRefDeallocate(dsRef); + + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); + discoveryZeroconfWatcher_destroy(watcher); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToPutWatchedServiceToCache) { + TestAddEndpoint([](){ + celix_ei_expect_celix_stringHashMap_putLong(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM); + ExpectMsgOutPut("Watcher: Failed to cache service instance name, %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToAllocMemoryForSvcEntry) { + TestAddEndpoint([](){ + celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 2);//first calloc:service_browser_entry_t + ExpectMsgOutPut("Watcher: Failed to alloc service entry."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToCreateTxtRecordForSvcEntry) { + TestAddEndpoint([](){ + celix_ei_expect_celix_properties_create(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + ExpectMsgOutPut("Watcher: Failed to create txt record for service entry."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToPutSvcEntryToCache) { + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM, 3); + TestAddEndpoint([](){ + ExpectMsgOutPut("Watcher: Failed to put service entry, %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToSetTxtRecordToSvcEntry) { + TestAddEndpoint([](){ + celix_ei_expect_celix_properties_set(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM); + ExpectMsgOutPut("Watcher: Failed to set txt record item(%s), %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToDupHostNameForSvcEntry) { + TestAddEndpoint([](){ + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 2); + ExpectMsgOutPut("Watcher: Failed to dup hostname."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, UnregisterRsaWhenBrowseServices) { + discovery_zeroconf_watcher_t *watcher; celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + auto eplTrkId = TrackEndpointListenerService(watcher); + + ExpectMsgOutPut("Endpoint added: %s."); auto dsRef = RegisterTestService(); - auto timeOut = waitSyncSemTimeout(30); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + DNSServiceRefDeallocate(dsRef); + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); + discoveryZeroconfWatcher_destroy(watcher); +} + +TEST_F(DiscoveryZeroconfWatcherTestSuite, DNSServiceResultProcessFailed1) { + discovery_zeroconf_watcher_t *watcher; + + auto dsRef = RegisterTestService(); + + celix_ei_expect_DNSServiceProcessResult(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_ServiceNotRunning); + ExpectMsgOutPut("Watcher: mDNS connection may be broken, %d."); + + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); discoveryZeroconfWatcher_destroy(watcher); + DNSServiceRefDeallocate(dsRef); } TEST_F(DiscoveryZeroconfWatcherTestSuite, DNSServiceResultProcessFailed2) { discovery_zeroconf_watcher_t *watcher; - celix_ei_expect_DNSServiceProcessResult(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown, 2); + auto dsRef = RegisterTestService(); + + celix_ei_expect_DNSServiceProcessResult(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_Unknown); + ExpectMsgOutPut("Watcher: Failed to process mDNS result, %d."); + + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + discoveryZeroconfWatcher_destroy(watcher); + DNSServiceRefDeallocate(dsRef); +} +TEST_F(DiscoveryZeroconfWatcherTestSuite, DNSServiceResolveFailedOnce) { + discovery_zeroconf_watcher_t *watcher; celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + celix_ei_expect_DNSServiceResolve(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_NoMemory); + ExpectMsgOutPut("Watcher: Failed to resolve %s on %d, %d."); auto dsRef = RegisterTestService(); - auto timeOut = waitSyncSemTimeout(30); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); DNSServiceRefDeallocate(dsRef); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); discoveryZeroconfWatcher_destroy(watcher); } @@ -289,28 +902,37 @@ TEST_F(DiscoveryZeroconfWatcherTestSuite, AddAndRemoveSelfFrameworkEndpoint) { discovery_zeroconf_watcher_t *watcher; celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); char txtBuf[1300] = {0}; TXTRecordRef txtRecord; TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); const char *fwUuid = celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid == nullptr ? 0 : strlen(fwUuid), fwUuid); + TXTRecordSetValue(&txtRecord, DZC_TXT_RECORD_VERSION_KEY, sizeof(DZC_CURRENT_TXT_RECORD_VERSION)-1, DZC_CURRENT_TXT_RECORD_VERSION); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid == nullptr ? 0 : strlen(fwUuid), fwUuid); TXTRecordSetValue(&txtRecord, CELIX_FRAMEWORK_SERVICE_NAME, strlen("dzc_test_self_fw_service"), "dzc_test_self_fw_service"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_ID, strlen("60f49d89-d105-430c-b12b-93fbb54b1d19"), "60f49d89-d105-430c-b12b-93fbb54b1d19"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_SERVICE_ID, strlen("100"), "100"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED, strlen("true"), "true"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, strlen("dzc_test_config_type"), "dzc_test_config_type"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_ID, strlen("60f49d89-d105-430c-b12b-93fbb54b1d19"), "60f49d89-d105-430c-b12b-93fbb54b1d19"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_SERVICE_ID, strlen("100"), "100"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED, strlen("true"), "true"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, sizeof(DZC_TEST_CONFIG_TYPE)-1, DZC_TEST_CONFIG_TYPE); char propSizeStr[16]= {0}; sprintf(propSizeStr, "%d", TXTRecordGetCount(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord)) + 1); TXTRecordSetValue(&txtRecord, DZC_SERVICE_PROPERTIES_SIZE_KEY, strlen(propSizeStr), propSizeStr); + ExpectMsgOutPut("Watcher: Ignore self endpoint for %s."); + DNSServiceRef dsRef{}; - DNSServiceErrorType dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexLocalOnly, "dzc_test_self_fw_service", DZC_SERVICE_PRIMARY_TYPE, "local", DZC_HOST_DEFAULT, htons(DZC_PORT_DEFAULT), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback, - nullptr); + DNSServiceErrorType dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexLocalOnly, + "dzc_test_self_fw_service", DZC_TEST_SERVICE_TYPE, "local", nullptr, htons(DZC_PORT_DEFAULT), + TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback,nullptr); EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); DNSServiceProcessResult(dsRef); + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + DNSServiceRefDeallocate(dsRef); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); discoveryZeroconfWatcher_destroy(watcher); } @@ -318,22 +940,29 @@ TEST_F(DiscoveryZeroconfWatcherTestSuite, AddTxtRecord) { discovery_zeroconf_watcher_t *watcher; celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); + auto eplTrkId = TrackEndpointListenerService(watcher); char txtBuf[1300] = {0}; TXTRecordRef txtRecord; TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, strlen(DZC_TEST_ENDPOINT_FW_UUID), DZC_TEST_ENDPOINT_FW_UUID); + TXTRecordSetValue(&txtRecord, DZC_TXT_RECORD_VERSION_KEY, sizeof(DZC_CURRENT_TXT_RECORD_VERSION)-1, DZC_CURRENT_TXT_RECORD_VERSION); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, strlen(DZC_TEST_ENDPOINT_FW_UUID), DZC_TEST_ENDPOINT_FW_UUID); TXTRecordSetValue(&txtRecord, CELIX_FRAMEWORK_SERVICE_NAME, strlen("dzc_test_service"), "dzc_test_service"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_ID, strlen("60f49d89-d105-430c-b12b-93fbb54b1d19"), "60f49d89-d105-430c-b12b-93fbb54b1d19"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_SERVICE_ID, strlen("100"), "100"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED, strlen("true"), "true"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, strlen("dzc_test_config_type"), "dzc_test_config_type"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_ID, strlen("60f49d89-d105-430c-b12b-93fbb54b1d18"), "60f49d89-d105-430c-b12b-93fbb54b1d18"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_SERVICE_ID, strlen("100"), "100"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED, strlen("true"), "true"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, sizeof(DZC_TEST_CONFIG_TYPE)-1, DZC_TEST_CONFIG_TYPE); char propSizeStr[16]= {0}; sprintf(propSizeStr, "%d", TXTRecordGetCount(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord)) + 1 + 5); TXTRecordSetValue(&txtRecord, DZC_SERVICE_PROPERTIES_SIZE_KEY, strlen(propSizeStr), propSizeStr); + ExpectMsgOutPut("Endpoint added: %s."); + DNSServiceRef dsRef{}; - DNSServiceErrorType dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexAny, "dzc_test_service", DZC_SERVICE_PRIMARY_TYPE, "local", DZC_HOST_DEFAULT, htons(DZC_PORT_DEFAULT), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback, nullptr); + DNSServiceErrorType dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexAny, "dzc_test_service", + DZC_TEST_SERVICE_TYPE, "local", nullptr, htons(DZC_PORT_DEFAULT), TXTRecordGetLength(&txtRecord), + TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback, nullptr); EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); DNSServiceProcessResult(dsRef); TXTRecordDeallocate(&txtRecord); @@ -353,10 +982,12 @@ TEST_F(DiscoveryZeroconfWatcherTestSuite, AddTxtRecord) { EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); TXTRecordDeallocate(&txtRecord); - auto timeOut = waitSyncSemTimeout(30); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); DNSServiceRefDeallocate(dsRef); + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); discoveryZeroconfWatcher_destroy(watcher); } @@ -364,38 +995,150 @@ TEST_F(DiscoveryZeroconfWatcherTestSuite, AddAndRemoveEndpointListener) { discovery_zeroconf_watcher_t *watcher; celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); EXPECT_EQ(CELIX_SUCCESS, status); + auto rsaTrkId = TrackRsaService(watcher); char txtBuf[1300] = {0}; TXTRecordRef txtRecord; TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, strlen(DZC_TEST_ENDPOINT_FW_UUID), DZC_TEST_ENDPOINT_FW_UUID); + TXTRecordSetValue(&txtRecord, DZC_TXT_RECORD_VERSION_KEY, sizeof(DZC_CURRENT_TXT_RECORD_VERSION)-1, DZC_CURRENT_TXT_RECORD_VERSION); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, strlen(DZC_TEST_ENDPOINT_FW_UUID), DZC_TEST_ENDPOINT_FW_UUID); TXTRecordSetValue(&txtRecord, CELIX_FRAMEWORK_SERVICE_NAME, strlen("dzc_test_service"), "dzc_test_service"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_ID, strlen("60f49d89-d105-430c-b12b-93fbb54b1d19"), "60f49d89-d105-430c-b12b-93fbb54b1d19"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_ENDPOINT_SERVICE_ID, strlen("100"), "100"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED, strlen("true"), "true"); - TXTRecordSetValue(&txtRecord, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, strlen("dzc_test_config_type"), "dzc_test_config_type"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_ID, strlen("60f49d89-d105-430c-b12b-93fbb54b1d19"), "60f49d89-d105-430c-b12b-93fbb54b1d19"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_ENDPOINT_SERVICE_ID, strlen("100"), "100"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED, strlen("true"), "true"); + TXTRecordSetValue(&txtRecord, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, sizeof(DZC_TEST_CONFIG_TYPE)-1, DZC_TEST_CONFIG_TYPE); char propSizeStr[16]= {0}; sprintf(propSizeStr, "%d", TXTRecordGetCount(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord)) + 1); TXTRecordSetValue(&txtRecord, DZC_SERVICE_PROPERTIES_SIZE_KEY, strlen(propSizeStr), propSizeStr); DNSServiceRef dsRef{}; - DNSServiceErrorType dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexLocalOnly, "dzc_test_service", DZC_SERVICE_PRIMARY_TYPE, "local", DZC_HOST_DEFAULT, htons(DZC_PORT_DEFAULT), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback,nullptr); + DNSServiceErrorType dnsErr = DNSServiceRegister(&dsRef, 0, kDNSServiceInterfaceIndexLocalOnly, "dzc_test_service", + DZC_TEST_SERVICE_TYPE, "local", nullptr, htons(DZC_PORT_DEFAULT), TXTRecordGetLength(&txtRecord), + TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback,nullptr); EXPECT_EQ(dnsErr, kDNSServiceErr_NoError); DNSServiceProcessResult(dsRef); - auto timeOut = waitSyncSemTimeout(30); + ExpectMsgOutPut("Endpoint added: %s."); + auto eplTrkId = TrackEndpointListenerService(watcher); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); - endpoint_listener_t epListener{nullptr,discoveryZeroconfWatcherTest_endpointAdded, discoveryZeroconfWatcherTest_endpointRemoved}; + ExpectMsgOutPut("Endpoint removed: %s."); + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); + timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + DNSServiceRefDeallocate(dsRef); + celix_bundleContext_stopTracker(ctx.get(), rsaTrkId); + discoveryZeroconfWatcher_destroy(watcher); +} - long listenerId = celix_bundleContext_registerService(ctx.get(), &epListener, OSGI_ENDPOINT_LISTENER_SERVICE, nullptr); - EXPECT_LE(0, listenerId); +TEST_F(DiscoveryZeroconfWatcherTestSuite, FailedToAllocMemoryForEPL) { + discovery_zeroconf_watcher_t *watcher; + celix_status_t status = discoveryZeroconfWatcher_create(ctx.get(), logHelper.get(), &watcher); + EXPECT_EQ(CELIX_SUCCESS, status); - timeOut = waitSyncSemTimeout(30); + ExpectMsgOutPut("Watcher: Failed to alloc endpoint listener entry."); + celix_ei_expect_calloc((void*)&discoveryZeroconfWatcher_addEPL, 0, nullptr); + auto eplTrkId = TrackEndpointListenerService(watcher); + auto timeOut = CheckMsgWithTimeOutInS(30); EXPECT_FALSE(timeOut); - celix_bundleContext_unregisterService(ctx.get(), listenerId); + celix_bundleContext_stopTracker(ctx.get(), eplTrkId); - DNSServiceRefDeallocate(dsRef); discoveryZeroconfWatcher_destroy(watcher); +} + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, FailedToGetHostIpAddressesWhenCreateEndpoint) { + TestWatchService([](){ + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 5); + ExpectMsgOutPut("Watcher: Failed to create endpoint for %s. %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30000); + EXPECT_FALSE(timeOut); + }); +} + + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, DNSServiceGetAddrInfoFailedOnce) { + TestWatchService([](){ + celix_ei_expect_DNSServiceGetAddrInfo(CELIX_EI_UNKNOWN_CALLER, 0, kDNSServiceErr_NoMemory); + ExpectMsgOutPut("Watcher: Failed to get address info for %s on %d, %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, FailedToAllocMemoryForHostEntry) { + TestWatchService([](){ + celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 4);//first calloc:watched_epl_entry_t; second calloc:service_browser_entry_t; third calloc:watched_service_entry_t + ExpectMsgOutPut("Watcher: Failed to alloc host entry for %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, FailedToDupHostNameForHostEntry) { + TestWatchService([](){ + celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 3); + ExpectMsgOutPut("Watcher: Failed to dup hostname for %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, FailedToPutHostEntryToCache) { + TestWatchService([](){ + celix_ei_expect_celix_stringHashMap_put(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM, 4); + ExpectMsgOutPut("Watcher: Failed to add host entry for %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, GetAddrInfo) { + TestWatchService([](){ + ExpectMsgOutPut("Endpoint added: %s."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, FailedToPutIpToHostEntry) { + TestWatchService([](){ + celix_ei_expect_celix_stringHashMap_putBool(CELIX_EI_UNKNOWN_CALLER, 0, CELIX_ENOMEM); + ExpectMsgOutPut("Watcher: Failed to add ip address(%s). %d."); + }, [](){ + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); +} + +TEST_F(DiscoveryZeroconfWatcherWatchServiceTestSuite, AddMultiEndpoint) { + TestWatchService([](){ + ExpectMsgOutPut("Endpoint added: %s."); + }, [](){ + //wait for endpoint1 added + auto timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + //register service2 + auto dsRef2 = RegisterTestService(kDNSServiceInterfaceIndexAny, "65d17a8c-f31b-478c-b13e-da743c96ab51", "101"); + + //wait for endpoint2 added + timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + + ExpectMsgOutPut("Endpoint removed: %s."); + DNSServiceRefDeallocate(dsRef2); + + //wait for endpoint2 added + timeOut = CheckMsgWithTimeOutInS(30); + EXPECT_FALSE(timeOut); + }); } \ No newline at end of file diff --git a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_activator.c b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_activator.c index 239f0b1da..70d0ac9ec 100644 --- a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_activator.c +++ b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_activator.c @@ -18,43 +18,123 @@ */ #include "discovery_zeroconf_announcer.h" #include "discovery_zeroconf_watcher.h" +#include "endpoint_listener.h" +#include "remote_constants.h" +#include "remote_service_admin.h" #include "celix_log_helper.h" #include "celix_bundle_activator.h" -#include "celix_types.h" +#include "celix_dm_component.h" +#include "celix_dm_service_dependency.h" +#include "celix_constants.h" #include "celix_errno.h" +#include +#include typedef struct discovery_zeroconf_activator { celix_log_helper_t *logHelper; discovery_zeroconf_announcer_t *announcer; discovery_zeroconf_watcher_t *watcher; + endpoint_listener_t endpointListener; }discovery_zeroconf_activator_t; celix_status_t discoveryZeroconfActivator_start(discovery_zeroconf_activator_t *act, celix_bundle_context_t *ctx) { celix_status_t status = CELIX_SUCCESS; - celix_autoptr(celix_log_helper_t) logger = celix_logHelper_create(ctx,"celix_rsa_zeroconf_discovery"); + const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, NULL); + if (fwUuid == NULL) { + return CELIX_BUNDLE_EXCEPTION; + } + celix_autoptr(celix_log_helper_t) logger = celix_logHelper_create(ctx, "celix_rsa_zeroconf_discovery"); if (logger == NULL) { return CELIX_ENOMEM; } - celix_autoptr(discovery_zeroconf_announcer_t) announcer = NULL; - status = discoveryZeroconfAnnouncer_create(ctx, logger, &announcer); + //init announcer + celix_autoptr(celix_dm_component_t) announcerCmp = celix_dmComponent_create(ctx, "DZC_ANNOUNCER_CMP"); + if (announcerCmp == NULL) { + return CELIX_ENOMEM; + } + status = discoveryZeroconfAnnouncer_create(ctx, logger, &act->announcer); + if (status != CELIX_SUCCESS) { + return status; + } + celix_dmComponent_setImplementation(announcerCmp, act->announcer); + CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(announcerCmp, discovery_zeroconf_announcer_t, discoveryZeroconfAnnouncer_destroy); + celix_autoptr(celix_properties_t) props = celix_properties_create(); + if (props == NULL) { + return CELIX_ENOMEM; + } + char scope[256] = {0}; + (void)snprintf(scope, sizeof(scope), "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, + CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + status = celix_properties_set(props, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, scope); + if (status != CELIX_SUCCESS) { + return status; + } + celix_properties_set(props, "DISCOVERY", "true");//Only use to avoid the discovery calls to unnecessary endpoint listener service. Endpoint should be filtered by the scope. + status = celix_properties_set(props, CELIX_RSA_DISCOVERY_INTERFACE_SPECIFIC_ENDPOINTS_SUPPORT, "true"); if (status != CELIX_SUCCESS) { return status; } - celix_autoptr(discovery_zeroconf_watcher_t) watcher = NULL; - status = discoveryZeroconfWatcher_create(ctx, logger, &watcher); + act->endpointListener.handle = act->announcer; + act->endpointListener.endpointAdded = discoveryZeroconfAnnouncer_endpointAdded; + act->endpointListener.endpointRemoved = discoveryZeroconfAnnouncer_endpointRemoved; + celix_dmComponent_addInterface(announcerCmp, CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, NULL, + &act->endpointListener, celix_steal_ptr(props)); + + //init watcher + celix_autoptr(celix_dm_component_t) watcherCmp = celix_dmComponent_create(ctx, "DZC_WATCHER_CMP"); + if (watcherCmp == NULL) { + return CELIX_ENOMEM; + } + status = discoveryZeroconfWatcher_create(ctx, logger, &act->watcher); if (status != CELIX_SUCCESS) { return status; } - act->watcher = celix_steal_ptr(watcher); - act->announcer = celix_steal_ptr(announcer); + celix_dmComponent_setImplementation(watcherCmp, act->watcher); + CELIX_DM_COMPONENT_SET_IMPLEMENTATION_DESTROY_FUNCTION(watcherCmp, discovery_zeroconf_watcher_t, discoveryZeroconfWatcher_destroy); + { + celix_dm_service_dependency_t *discoveredEplDep = celix_dmServiceDependency_create(); + if (discoveredEplDep == NULL) { + return CELIX_ENOMEM; + } + celix_dmServiceDependency_setService(discoveredEplDep, CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, NULL, "(!(DISCOVERY=true))"); + celix_dm_service_dependency_callback_options_t opts = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; + opts.addWithProps = discoveryZeroconfWatcher_addEPL; + opts.removeWithProps = discoveryZeroconfWatcher_removeEPL; + celix_dmServiceDependency_setCallbacksWithOptions(discoveredEplDep, &opts); + celix_dmServiceDependency_setStrategy(discoveredEplDep, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); + celix_dmComponent_addServiceDependency(watcherCmp, discoveredEplDep); + } + { + celix_dm_service_dependency_t *rsaDep = celix_dmServiceDependency_create(); + if (rsaDep == NULL) { + return CELIX_ENOMEM; + } + celix_dmServiceDependency_setService(rsaDep, CELIX_RSA_REMOTE_SERVICE_ADMIN, + NULL, "(remote.configs.supported=*)"); + celix_dm_service_dependency_callback_options_t opts = CELIX_EMPTY_DM_SERVICE_DEPENDENCY_CALLBACK_OPTIONS; + opts.addWithProps = discoveryZeroConfWatcher_addRSA; + opts.removeWithProps = discoveryZeroConfWatcher_removeRSA; + celix_dmServiceDependency_setCallbacksWithOptions(rsaDep, &opts); + celix_dmServiceDependency_setStrategy(rsaDep, DM_SERVICE_DEPENDENCY_STRATEGY_LOCKING); + celix_dmComponent_addServiceDependency(watcherCmp, rsaDep); + } + + celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(ctx); + if (mng == NULL) { + return CELIX_ENOMEM; + } + celix_dependencyManager_addAsync(mng, celix_steal_ptr(announcerCmp)); + celix_dependencyManager_addAsync(mng, celix_steal_ptr(watcherCmp)); + act->logHelper = celix_steal_ptr(logger); return CELIX_SUCCESS; } celix_status_t discoveryZeroconfActivator_stop(discovery_zeroconf_activator_t *act, celix_bundle_context_t *ctx) { - (void)ctx;//unused - discoveryZeroconfWatcher_destroy(act->watcher); - discoveryZeroconfAnnouncer_destroy(act->announcer); + celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(ctx); + assert(mng != NULL); + celix_dependencyManager_removeAllComponents(mng); + celix_bundleContext_waitForEvents(ctx); celix_logHelper_destroy(act->logHelper); return CELIX_SUCCESS; } diff --git a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.c b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.c index f0cf81eb1..154687663 100644 --- a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.c +++ b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.c @@ -24,11 +24,9 @@ #include "celix_properties.h" #include "celix_constants.h" #include "celix_threads.h" -#include "celix_bundle_context.h" #include "celix_string_hash_map.h" #include "celix_array_list.h" #include "celix_log_helper.h" -#include "celix_types.h" #include "celix_errno.h" #include "celix_build_assert.h" #include "celix_stdlib_cleanup.h" @@ -41,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -52,17 +51,16 @@ #include -#define DZC_MAX_CONFLICT_CNT 256 - //According to rfc6763, Using TXT records larger than 1300 bytes is NOT RECOMMENDED #define DZC_MAX_TXT_RECORD_SIZE 1300 +//It is enough to store three subtypes. +#define DZC_MAX_SERVICE_TYPE_LEN 256 + struct discovery_zeroconf_announcer { celix_bundle_context_t *ctx; celix_log_helper_t *logHelper; - char fwUuid[64]; - endpoint_listener_t epListener; - long epListenerSvcId; + pid_t pid; DNSServiceRef sharedRef; int eventFd; celix_thread_t refreshEPThread; @@ -70,22 +68,22 @@ struct discovery_zeroconf_announcer { bool running; celix_string_hash_map_t *endpoints;//key:endpoint id, val:announce_endpoint_entry_t* celix_array_list_t *revokedEndpoints; + celix_string_hash_map_t *conflictCntMap;//key:service name, val:conflictCnt. Use to resolve conflict service name in same host.Because the mDNSResponder does not automatically resolve service name conflicts in the same host. }; typedef struct announce_endpoint_entry { celix_properties_t *properties; DNSServiceRef registerRef; - unsigned int uid; int ifIndex; + int port; const char *serviceName; - char serviceType[64]; + char *serviceType; bool announced; + uint32_t conflictCnt; }announce_endpoint_entry_t; - +static void endpointEntry_destroy(announce_endpoint_entry_t *entry); static void discoveryZeroconfAnnouncer_eventNotify(discovery_zeroconf_announcer_t *announcer); -static celix_status_t discoveryZeroconfAnnouncer_endpointAdded(void *handle, endpoint_description_t *endpoint, char *matchedFilter); -static celix_status_t discoveryZeroconfAnnouncer_endpointRemoved(void *handle, endpoint_description_t *endpoint, char *matchedFilter); static void *discoveryZeroconfAnnouncer_refreshEndpointThread(void *data); @@ -93,69 +91,55 @@ celix_status_t discoveryZeroconfAnnouncer_create(celix_bundle_context_t *ctx, ce celix_status_t status = CELIX_SUCCESS; celix_autofree discovery_zeroconf_announcer_t *announcer = (discovery_zeroconf_announcer_t *)calloc(1, sizeof(*announcer)); if (announcer == NULL) { - celix_logHelper_fatal(logHelper, "Announcer: Failed to alloc announcer."); + celix_logHelper_error(logHelper, "Announcer: Failed to alloc announcer."); return CELIX_ENOMEM; } announcer->ctx = ctx; announcer->logHelper = logHelper; + announcer->pid = getpid(); announcer->sharedRef = NULL; announcer->eventFd = eventfd(0, 0); if (announcer->eventFd < 0) { - celix_logHelper_fatal(logHelper, "Announcer: Failed to open event fd, %d.", errno); + celix_logHelper_error(logHelper, "Announcer: Failed to open event fd, %d.", errno); return CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO, errno); } celix_auto(celix_fd_t) eventFd = announcer->eventFd; status = celixThreadMutex_create(&announcer->mutex, NULL); if (status != CELIX_SUCCESS) { - celix_logHelper_fatal(logHelper, "Announcer: Failed to create mutex, %d.", status); + celix_logHelper_error(logHelper, "Announcer: Failed to create mutex, %d.", status); return status; } celix_autoptr(celix_thread_mutex_t) mutex = &announcer->mutex; celix_autoptr(celix_string_hash_map_t) endpoints = announcer->endpoints = celix_stringHashMap_create(); - assert(announcer->endpoints != NULL); + if (endpoints == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "Announcer: Failed to create endpoints map."); + return CELIX_ENOMEM; + } celix_autoptr(celix_array_list_t) revokedEndpoints = announcer->revokedEndpoints = celix_arrayList_create(); - assert(announcer->revokedEndpoints != NULL); - - const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, NULL); - if (fwUuid == NULL || strlen(fwUuid) >= sizeof(announcer->fwUuid)) { - celix_logHelper_fatal(logHelper, "Announcer: Failed to get framework uuid."); - return CELIX_BUNDLE_EXCEPTION; - } - strcpy(announcer->fwUuid, fwUuid); - - announcer->epListener.handle = announcer; - announcer->epListener.endpointAdded = discoveryZeroconfAnnouncer_endpointAdded; - announcer->epListener.endpointRemoved = discoveryZeroconfAnnouncer_endpointRemoved; - char scope[256] = {0}; - (void)snprintf(scope, sizeof(scope), "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); - - celix_properties_t *props = celix_properties_create(); - assert(props != NULL); - celix_properties_set(props, "DISCOVERY", "true"); - celix_properties_set(props, (char *) OSGI_ENDPOINT_LISTENER_SCOPE, scope); - celix_service_registration_options_t opt = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; - opt.serviceName = OSGI_ENDPOINT_LISTENER_SERVICE; - opt.properties = props; - opt.svc = &announcer->epListener; - announcer->epListenerSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opt); - if (announcer->epListenerSvcId < 0) { - celix_logHelper_fatal(logHelper, "Announcer: Failed to register endpoint listener."); - return CELIX_BUNDLE_EXCEPTION; - } - celix_auto(celix_service_registration_guard_t) epListenerSvcReg - = celix_serviceRegistrationGuard_init(ctx, announcer->epListenerSvcId); + if (revokedEndpoints == NULL) { + celix_logHelper_error(logHelper, "Announcer: Failed to create revoked endpoints list."); + return CELIX_ENOMEM; + } + + celix_autoptr(celix_string_hash_map_t) conflictCntMap = announcer->conflictCntMap = celix_stringHashMap_create(); + if (conflictCntMap == NULL) { + celix_logHelper_error(logHelper, "Announcer: Failed to create conflict count map."); + return CELIX_ENOMEM; + } + announcer->running = true; status = celixThread_create(&announcer->refreshEPThread, NULL, discoveryZeroconfAnnouncer_refreshEndpointThread, announcer); if (status != CELIX_SUCCESS) { - celix_logHelper_fatal(logHelper, "Announcer: Failed to create refreshing endpoint thread, %d.", status); + celix_logHelper_error(logHelper, "Announcer: Failed to create refreshing endpoint thread, %d.", status); return status; } celixThread_setName(&announcer->refreshEPThread, "DiscAnnouncer"); - epListenerSvcReg.svcId = -1; + celix_steal_ptr(conflictCntMap); celix_steal_ptr(revokedEndpoints); celix_steal_ptr(endpoints); celix_steal_ptr(mutex); @@ -170,22 +154,19 @@ void discoveryZeroconfAnnouncer_destroy(discovery_zeroconf_announcer_t *announce celixThreadMutex_unlock(&announcer->mutex); discoveryZeroconfAnnouncer_eventNotify(announcer); celixThread_join(announcer->refreshEPThread, NULL); - celix_bundleContext_unregisterServiceAsync(announcer->ctx, announcer->epListenerSvcId, NULL, NULL); - celix_bundleContext_waitForAsyncUnregistration(announcer->ctx, announcer->epListenerSvcId); + celix_stringHashMap_destroy(announcer->conflictCntMap); announce_endpoint_entry_t *entry = NULL; int size = celix_arrayList_size(announcer->revokedEndpoints); for (int i = 0; i < size; ++i) { entry = (announce_endpoint_entry_t *)celix_arrayList_get(announcer->revokedEndpoints, i); - celix_properties_destroy(entry->properties); - free(entry); + endpointEntry_destroy(entry); } celix_arrayList_destroy(announcer->revokedEndpoints); CELIX_STRING_HASH_MAP_ITERATE(announcer->endpoints,iter) { entry = (announce_endpoint_entry_t *) iter.value.ptrValue; - celix_properties_destroy(entry->properties); - free(entry); + endpointEntry_destroy(entry); } celix_stringHashMap_destroy(announcer->endpoints); @@ -219,32 +200,93 @@ static bool isLoopBackNetInterface(const char *ifName) { return loopBack; } -static celix_status_t discoveryZeroconfAnnouncer_endpointAdded(void *handle, endpoint_description_t *endpoint, char *matchedFilter) { - (void)matchedFilter;//unused - discovery_zeroconf_announcer_t *announcer = (discovery_zeroconf_announcer_t *)handle; - assert(announcer != NULL); - if (endpointDescription_isInvalid(endpoint)) { - celix_logHelper_error(announcer->logHelper, "Announcer: Endpoint is invalid."); +static int discoveryZeroconfAnnouncer_setServiceSubTypeTo(discovery_zeroconf_announcer_t *announcer, const char *importedConfigType, celix_string_hash_map_t *svcSubTypes) { + //We use the last word of config type as mDNS service subtype(https://www.rfc-editor.org/rfc/rfc6763.html#section-7.1). so we can browse the service by the last word of config type. + const char *svcSubType = strrchr(importedConfigType, '.'); + if (svcSubType != NULL) { + svcSubType += 1;//skip '.' + } else { + svcSubType = importedConfigType; + } + size_t subTypeLen = strlen(svcSubType); + if (subTypeLen ==0 || subTypeLen > 63) {//the subtype identifier is allowed to be up to 63 bytes, see https://www.rfc-editor.org/rfc/rfc6763.html#section-7.2 + celix_logHelper_error(announcer->logHelper, "Announcer: Invalid service sub type for %s.", importedConfigType); return CELIX_ILLEGAL_ARGUMENT; } + int status = celix_stringHashMap_put(svcSubTypes, svcSubType, NULL); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(announcer->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to put service sub type for %s. %d", importedConfigType, status); + return status; + } + return CELIX_SUCCESS; +} - celix_logHelper_info(announcer->logHelper, "Announcer: Add endpoint for %s(%s).", endpoint->serviceName, endpoint->id); +static char* discoveryZeroconfAnnouncer_createServiceTypeAccordingToConfigTypes(discovery_zeroconf_announcer_t* announcer, const char* configTypes) { + celix_string_hash_map_create_options_t opts = CELIX_EMPTY_STRING_HASH_MAP_CREATE_OPTIONS; + opts.storeKeysWeakly = true; + celix_autoptr(celix_string_hash_map_t) svcSubTypes = celix_stringHashMap_createWithOptions(&opts); + if (svcSubTypes == NULL) { + celix_logHelper_logTssErrors(announcer->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to create svc sub types map."); + return NULL; + } + celix_autofree char *configTypesCopy = celix_utils_strdup(configTypes); + if (configTypesCopy == NULL) { + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to dup config types."); + return NULL; + } + char *savePtr = NULL; + char *token = strtok_r(configTypesCopy, ",", &savePtr); + while (token != NULL) { + token = celix_utils_trimInPlace(token); + int status = discoveryZeroconfAnnouncer_setServiceSubTypeTo(announcer, token, svcSubTypes); + if (status != CELIX_SUCCESS) { + return NULL; + } + token = strtok_r(NULL, ",", &savePtr); + } + char serviceType[DZC_MAX_SERVICE_TYPE_LEN] = {0}; + CELIX_BUILD_ASSERT(sizeof(serviceType) >= sizeof(DZC_SERVICE_PRIMARY_TYPE)); + strcpy(serviceType, DZC_SERVICE_PRIMARY_TYPE); + size_t offset = strlen(serviceType); + CELIX_STRING_HASH_MAP_ITERATE(svcSubTypes, iter) { + offset += snprintf(serviceType + offset, sizeof(serviceType) - offset, ",%s", iter.key); + if (offset >= sizeof(serviceType)) { + celix_logHelper_error(announcer->logHelper, "Announcer: Please reduce the length of imported configs for %s.", serviceType); + return NULL; + } + } + return celix_utils_strdup(serviceType); +} + +static int discoveryZeroconfAnnouncer_createEndpointEntry(discovery_zeroconf_announcer_t *announcer, endpoint_description_t *endpoint, announce_endpoint_entry_t **entryOut) { + celix_autoptr(celix_properties_t) properties = celix_properties_copy(endpoint->properties); + if (properties == NULL) { + celix_logHelper_logTssErrors(announcer->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to copy endpoint properties for %s.", endpoint->serviceName); + return CELIX_ENOMEM; + } + const char* serviceName = celix_properties_get(properties, CELIX_FRAMEWORK_SERVICE_NAME, NULL); + if (serviceName == NULL) { + celix_logHelper_error(announcer->logHelper,"Announcer: Invalid service."); + return CELIX_ILLEGAL_ARGUMENT; + } + const char *importedConfigs = celix_properties_get(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, NULL); + if (importedConfigs == NULL) { + celix_logHelper_error(announcer->logHelper, "Announcer: No imported configs for %s.", serviceName); + return CELIX_ILLEGAL_ARGUMENT; + } celix_autofree announce_endpoint_entry_t *entry = (announce_endpoint_entry_t *)calloc(1, sizeof(*entry)); if (entry == NULL) { - celix_logHelper_error(announcer->logHelper, "Announcer: Failed to alloc endpoint entry."); + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to alloc endpoint entry for %s.", serviceName); return CELIX_ENOMEM; } entry->registerRef = NULL; entry->announced = false; - // The entry->uid is used in mDNS instance name. - // To avoid instance name conflicts on localonly interface, - // in our code, the instance name consists of the service name and the UID. - // Because the maximum size of an mDNS instance name is 64 bytes, so we use the hash of endpoint->id. - // Don't worry about the uniqueness of the endpoint->id hash, it is only used to reduce the probability of instance name conflicts. - // If a conflict occurs, mDNS daemon will resolve it. - entry->uid = celix_utils_stringHash(endpoint->id); - const char *ifName = celix_properties_get(endpoint->properties, CELIX_RSA_NETWORK_INTERFACES, NULL); + entry->conflictCnt = 0; + const char *ifName = celix_properties_get(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, NULL); if (ifName != NULL) { if (strcmp(ifName, "all") == 0) { entry->ifIndex = kDNSServiceInterfaceIndexAny; @@ -253,43 +295,101 @@ static celix_status_t discoveryZeroconfAnnouncer_endpointAdded(void *handle, en // Because the mDNSResponder will skip the loopback interface,if it found a normal interface. entry->ifIndex = kDNSServiceInterfaceIndexLocalOnly; } else { - entry->ifIndex = if_nametoindex(ifName); - entry->ifIndex = entry->ifIndex == 0 ? DZC_SERVICE_ANNOUNCED_IF_INDEX_DEFAULT : entry->ifIndex; + entry->ifIndex = (int)if_nametoindex(ifName); + if (entry->ifIndex == 0) { + celix_logHelper_error(announcer->logHelper, "Announcer: Invalid network interface name %s.", ifName); + return CELIX_ILLEGAL_ARGUMENT; + } } } else { entry->ifIndex = DZC_SERVICE_ANNOUNCED_IF_INDEX_DEFAULT; } + entry->port = celix_properties_getAsLong(properties, CELIX_RSA_PORT, DZC_PORT_DEFAULT); + + entry->serviceType = discoveryZeroconfAnnouncer_createServiceTypeAccordingToConfigTypes(announcer, importedConfigs); + if (entry->serviceType == NULL) { + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to create service type for %s.", serviceName); + return CELIX_ENOMEM; + } + entry->serviceName = serviceName; + celix_properties_unset(properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE);//ifname should not set to mDNS TXT record, because service consumer will not use it. + celix_properties_unset(properties, CELIX_RSA_PORT);//port should not set to mDNS TXT record, because it will be set to SRV record. see https://www.rfc-editor.org/rfc/rfc6763.html#section-6.3 + entry->properties = celix_steal_ptr(properties); + *entryOut = celix_steal_ptr(entry); + return CELIX_SUCCESS; +} - const char *serviceSubType = celix_properties_get(endpoint->properties, DZC_SERVICE_TYPE_KEY, NULL); - if (serviceSubType != NULL) { - int bytes = snprintf(entry->serviceType, sizeof(entry->serviceType), DZC_SERVICE_PRIMARY_TYPE",%s", serviceSubType); - if (bytes >= sizeof(entry->serviceType)) { - celix_logHelper_error(announcer->logHelper, "Announcer: Please reduce the length of service type for %s.", serviceSubType); - return CELIX_ILLEGAL_ARGUMENT; +static void endpointEntry_destroy(announce_endpoint_entry_t *entry) { + celix_properties_destroy(entry->properties); + free(entry->serviceType); + free(entry); + return; +} +CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(announce_endpoint_entry_t, endpointEntry_destroy) + +static int discoveryZeroconfAnnouncer_generateServiceNameConflictCnt(discovery_zeroconf_announcer_t *announcer, const char *serviceName, uint32_t *conflictCntOut) { + uint32_t conflictCnt = (uint32_t)celix_stringHashMap_getLong(announcer->conflictCntMap, serviceName, 0); + bool conflicted; + do { + conflicted = false; + conflictCnt++; + CELIX_STRING_HASH_MAP_ITERATE(announcer->endpoints, iter) { + announce_endpoint_entry_t *entry = (announce_endpoint_entry_t *)iter.value.ptrValue; + if (strcmp(entry->serviceName, serviceName) == 0 && entry->conflictCnt == conflictCnt) { + conflicted = true; + break; + } } - } else { - CELIX_BUILD_ASSERT(sizeof(entry->serviceType) >= sizeof(DZC_SERVICE_PRIMARY_TYPE)); - strcpy(entry->serviceType, DZC_SERVICE_PRIMARY_TYPE); + }while(conflicted); + + int status = celix_stringHashMap_putLong(announcer->conflictCntMap, serviceName, conflictCnt); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(announcer->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to update conflict count for %s.", serviceName); + return status; } - celix_autoptr(celix_properties_t) properties = entry->properties = celix_properties_copy(endpoint->properties); + *conflictCntOut = conflictCnt; + return CELIX_SUCCESS; +} - //Remove properties that remote service does not need - celix_properties_unset(entry->properties, CELIX_RSA_NETWORK_INTERFACES); - celix_properties_unset(entry->properties, DZC_SERVICE_TYPE_KEY); - entry->serviceName = celix_properties_get(entry->properties, CELIX_FRAMEWORK_SERVICE_NAME, NULL); - if (entry->serviceName == NULL) { - celix_logHelper_error(announcer->logHelper,"Announcer: Invalid service."); +celix_status_t discoveryZeroconfAnnouncer_endpointAdded(void *handle, endpoint_description_t *endpoint, char *matchedFilter) { + (void)matchedFilter;//unused + int status = CELIX_SUCCESS; + discovery_zeroconf_announcer_t *announcer = (discovery_zeroconf_announcer_t *)handle; + assert(announcer != NULL); + if (endpointDescription_isInvalid(endpoint)) { + celix_logHelper_error(announcer->logHelper, "Announcer: Endpoint is invalid."); return CELIX_ILLEGAL_ARGUMENT; } - celixThreadMutex_lock(&announcer->mutex); - celix_stringHashMap_put(announcer->endpoints, endpoint->id, celix_steal_ptr(entry)); - celixThreadMutex_unlock(&announcer->mutex); + + celix_logHelper_info(announcer->logHelper, "Announcer: Add endpoint for %s(%s).", endpoint->serviceName, endpoint->id); + + celix_autoptr(announce_endpoint_entry_t) entry = NULL; + status = discoveryZeroconfAnnouncer_createEndpointEntry(announcer, endpoint, &entry); + if (status != CELIX_SUCCESS) { + return status; + } + + celix_auto(celix_mutex_lock_guard_t) lockGuard = celixMutexLockGuard_init(&announcer->mutex); + status = discoveryZeroconfAnnouncer_generateServiceNameConflictCnt(announcer, entry->serviceName, &entry->conflictCnt); + if (status != CELIX_SUCCESS) { + return status; + } + status = celix_stringHashMap_put(announcer->endpoints, endpoint->id, entry); + if (status == CELIX_SUCCESS) { + celix_steal_ptr(entry); + } else { + celix_logHelper_logTssErrors(announcer->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to put endpoint entry for %s.", endpoint->id); + return status; + } + discoveryZeroconfAnnouncer_eventNotify(announcer); - celix_steal_ptr(properties); + return CELIX_SUCCESS; } -static celix_status_t discoveryZeroconfAnnouncer_endpointRemoved(void *handle, endpoint_description_t *endpoint, char *matchedFilter) { +celix_status_t discoveryZeroconfAnnouncer_endpointRemoved(void *handle, endpoint_description_t *endpoint, char *matchedFilter) { (void)matchedFilter;//unused discovery_zeroconf_announcer_t *announcer = (discovery_zeroconf_announcer_t *)handle; assert(announcer != NULL); @@ -306,6 +406,7 @@ static celix_status_t discoveryZeroconfAnnouncer_endpointRemoved(void *handle, e (void)celix_stringHashMap_remove(announcer->endpoints, endpoint->id); celix_arrayList_add(announcer->revokedEndpoints, entry); } + celix_stringHashMap_putLong(announcer->conflictCntMap, endpoint->serviceName, 0);//reset conflict count celixThreadMutex_unlock(&announcer->mutex); discoveryZeroconfAnnouncer_eventNotify(announcer); return CELIX_SUCCESS; @@ -331,10 +432,10 @@ static void discoveryZeroconfAnnouncer_revokeEndpoints(discovery_zeroconf_announ for (int i = 0; i < size; ++i) { entry = celix_arrayList_get(endpoints, i); if (entry->registerRef != NULL) { + celix_logHelper_info(announcer->logHelper, "Announcer: Deregister service %s on interface %d.", entry->serviceName, entry->ifIndex); DNSServiceRefDeallocate(entry->registerRef); } - celix_properties_destroy(entry->properties); - free(entry); + endpointEntry_destroy(entry); } return; } @@ -377,8 +478,9 @@ static void discoveryZeroconfAnnouncer_announceEndpoints(discovery_zeroconf_anno celix_properties_iterator_t propIter = celix_properties_begin(entry->properties); TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); + (void)TXTRecordSetValue(&txtRecord, DZC_TXT_RECORD_VERSION_KEY, sizeof(DZC_CURRENT_TXT_RECORD_VERSION)-1, DZC_CURRENT_TXT_RECORD_VERSION); char propSizeStr[16]= {0}; - sprintf(propSizeStr, "%zu", celix_properties_size(entry->properties) + 1); + sprintf(propSizeStr, "%zu", celix_properties_size(entry->properties) + 2/*size and version*/); (void)TXTRecordSetValue(&txtRecord, DZC_SERVICE_PROPERTIES_SIZE_KEY, strlen(propSizeStr), propSizeStr); if (!discoveryZeroconfAnnouncer_copyPropertiesToTxtRecord(announcer, &propIter, &txtRecord, sizeof(txtBuf), splitTxtRecord)) { TXTRecordDeallocate(&txtRecord); @@ -387,45 +489,42 @@ static void discoveryZeroconfAnnouncer_announceEndpoints(discovery_zeroconf_anno DNSServiceErrorType dnsErr; char instanceName[64] = {0}; - bool registered = false; - int conflictCnt = 0; - DNSServiceRef dsRef; - do { - dsRef = announcer->sharedRef;//DNSServiceRegister will set a new value for dsRef - int bytes = snprintf(instanceName, sizeof(instanceName), "%s-%X", entry->serviceName, entry->uid + conflictCnt); - if (bytes >= sizeof(instanceName)) { - celix_logHelper_error(announcer->logHelper, "Announcer: Please reduce the length of service name for %s.", entry->serviceName); - break; - } - celix_logHelper_info(announcer->logHelper, "Announcer: Register service %s on interface %d.", instanceName, entry->ifIndex); - dnsErr = DNSServiceRegister(&dsRef, kDNSServiceFlagsShareConnection, entry->ifIndex, instanceName, entry->serviceType, "local", DZC_HOST_DEFAULT, htons(DZC_PORT_DEFAULT), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback, announcer); - if (dnsErr == kDNSServiceErr_NoError) { - registered = true; - } else { - celix_logHelper_error(announcer->logHelper, "Announcer: Failed to announce service, %s. %d", instanceName, dnsErr); - } - //LocalOnly service may be return kDNSServiceErr_NameConflict, but mDNS daemon will resolve the instance name conflicts for non-LocalOnly service - } while (dnsErr == kDNSServiceErr_NameConflict && conflictCnt++ < DZC_MAX_CONFLICT_CNT); - + DNSServiceRef dsRef = announcer->sharedRef;//DNSServiceRegister will set a new value for dsRef + int bytes = 0; + if (entry->conflictCnt <= 1) { + bytes = snprintf(instanceName, sizeof(instanceName), "%s-%ld", entry->serviceName, (long)announcer->pid); + } else { + bytes = snprintf(instanceName, sizeof(instanceName), "%s-%ld(%u)", entry->serviceName, (long)announcer->pid, entry->conflictCnt); + } + if (bytes >= sizeof(instanceName)) { + celix_logHelper_error(announcer->logHelper, "Announcer: Please reduce the length of service name for %s.", entry->serviceName); + TXTRecordDeallocate(&txtRecord); + continue; + } + celix_logHelper_info(announcer->logHelper, "Announcer: Register service %s on interface %d.", instanceName, entry->ifIndex); + dnsErr = DNSServiceRegister(&dsRef, kDNSServiceFlagsShareConnection, entry->ifIndex, instanceName, entry->serviceType, "local", NULL, htons(entry->port), TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), OnDNSServiceRegisterCallback, announcer); + if (dnsErr != kDNSServiceErr_NoError) { + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to announce service, %s. %d", instanceName, dnsErr); + TXTRecordDeallocate(&txtRecord); + continue; + } TXTRecordDeallocate(&txtRecord); - if (registered) { - entry->registerRef = dsRef; - while (!celix_propertiesIterator_isEnd(&propIter)) { - TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); - if (!discoveryZeroconfAnnouncer_copyPropertiesToTxtRecord(announcer, &propIter, &txtRecord, sizeof(txtBuf), true)) { - TXTRecordDeallocate(&txtRecord); - break; - } - DNSRecordRef rdRef;//It will be free when deallocate dsRef - dnsErr = DNSServiceAddRecord(dsRef, &rdRef, 0, kDNSServiceType_TXT, TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), 0); - if (dnsErr != kDNSServiceErr_NoError) { - celix_logHelper_error(announcer->logHelper, "Announcer: Failed to add record for %s. %d", instanceName, dnsErr); - TXTRecordDeallocate(&txtRecord); - break; - } + entry->registerRef = dsRef; + while (!celix_propertiesIterator_isEnd(&propIter)) { + TXTRecordCreate(&txtRecord, sizeof(txtBuf), txtBuf); + if (!discoveryZeroconfAnnouncer_copyPropertiesToTxtRecord(announcer, &propIter, &txtRecord, sizeof(txtBuf), true)) { + TXTRecordDeallocate(&txtRecord); + break; + } + DNSRecordRef rdRef;//It will be free when deallocate dsRef + dnsErr = DNSServiceAddRecord(dsRef, &rdRef, 0, kDNSServiceType_TXT, TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), 0); + if (dnsErr != kDNSServiceErr_NoError) { + celix_logHelper_error(announcer->logHelper, "Announcer: Failed to add record for %s. %d", instanceName, dnsErr); TXTRecordDeallocate(&txtRecord); + break; } + TXTRecordDeallocate(&txtRecord); } } return; @@ -444,13 +543,13 @@ static void discoveryZeroconfAnnouncer_handleMDNSEvent(discovery_zeroconf_announ celixThreadMutex_lock(&announcer->mutex); CELIX_STRING_HASH_MAP_ITERATE(announcer->endpoints, iter) { entry = (announce_endpoint_entry_t *) iter.value.ptrValue; - entry->registerRef = NULL;//no need free entry->registerRef, 'DNSServiceRefDeallocate(announcer->sharedRef)' has do it. + entry->registerRef = NULL;//no need free entry->registerRef, 'DNSServiceRefDeallocate(announcer->sharedRef)' has done it. entry->announced = false; } int size = celix_arrayList_size(announcer->revokedEndpoints); for (int i = 0; i < size; ++i) { entry = celix_arrayList_get(announcer->revokedEndpoints, i); - entry->registerRef = NULL;//no need free entry->registerRef, 'DNSServiceRefDeallocate(announcer->sharedRef)' has do it. + entry->registerRef = NULL;//no need free entry->registerRef, 'DNSServiceRefDeallocate(announcer->sharedRef)' has done it. } celixThreadMutex_unlock(&announcer->mutex); } else if (dnsErr != kDNSServiceErr_NoError) { @@ -519,7 +618,6 @@ static void *discoveryZeroconfAnnouncer_refreshEndpointThread(void *data) { } } } - running = announcer->running; celixThreadMutex_unlock(&announcer->mutex); discoveryZeroconfAnnouncer_revokeEndpoints(announcer, revokedEndpoints); @@ -532,8 +630,12 @@ static void *discoveryZeroconfAnnouncer_refreshEndpointThread(void *data) { discoveryZeroconfAnnouncer_handleMDNSEvent(announcer); } } else if (result == -1 && errno != EINTR) { - celix_logHelper_error(announcer->logHelper, "Announcer: Error Selecting event, %d.", errno); + celix_logHelper_error(announcer->logHelper, "Announcer: Error Selecting event, %d.", errno); + sleep(1);//avoid busy loop } + celixThreadMutex_lock(&announcer->mutex); + running = announcer->running; + celixThreadMutex_unlock(&announcer->mutex); } if (announcer->sharedRef) { DNSServiceRefDeallocate(announcer->sharedRef); diff --git a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.h b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.h index f8f85923e..a34c35973 100644 --- a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.h +++ b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_announcer.h @@ -22,7 +22,7 @@ #ifdef __cplusplus extern "C" { #endif - +#include "endpoint_description.h" #include "celix_cleanup.h" #include "celix_log_helper.h" #include "celix_types.h" @@ -36,6 +36,10 @@ void discoveryZeroconfAnnouncer_destroy(discovery_zeroconf_announcer_t *announce CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(discovery_zeroconf_announcer_t, discoveryZeroconfAnnouncer_destroy) +celix_status_t discoveryZeroconfAnnouncer_endpointAdded(void *handle, endpoint_description_t *endpoint, char *matchedFilter); + +celix_status_t discoveryZeroconfAnnouncer_endpointRemoved(void *handle, endpoint_description_t *endpoint, char *matchedFilter); + #ifdef __cplusplus } #endif diff --git a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_constants.h b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_constants.h index d061aee44..0a98ecb68 100644 --- a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_constants.h +++ b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_constants.h @@ -33,34 +33,16 @@ extern "C" { /** * mDNS service name for celix service. - * About mDNS service name, see rfc6363 section 4.1.2 and section 7 + * About mDNS service name, see rfc6763 section 4.1.2 and section 7 */ #define DZC_SERVICE_PRIMARY_TYPE "_celix-rpc._udp" /** - * mDNS service subtype for celix.service, it can be null. - * About mDNS service subtype, see rfc6363 section 7.1 - * The subtype mechanism can be illustrated with some examples using the dns-sd command-line tool: - * If we register the following three services: - * % dns-sd -R service1 _celix-rpc._udp local 1001 - * % dns-sd -R service2 _celix-rpc._udp,subtype1 local 1002 - * % dns-sd -R service3 _celix-rpc._udp,subtype1,subtype2 local 1003 - * Now: - * % dns-sd -B _celix-rpc._udp # will find all three services - * % dns-sd -B _celix-rpc._udp,subtype1 # will find "service2" and "service3" - * % dns-sd -B _celix-rpc._udp,subtype2 # will find only "service3" - */ -#define DZC_SERVICE_TYPE_KEY "DZC_SERVICE_TYPE_KEY" - -/** - * Host name and port for mDNS service. + * The default port for mDNS service. * - * To reduce the operation of conversion between host name and address info(ip and port). - * we set the address info to txt record, and set a dummy value("celix_rpc_dumb_host.local." - * and "50009") to the host name and port for mDNS service. + * It is a dummy value, it is used for the remote service that IPC is not network based(eg:shared memory). */ -#define DZC_HOST_DEFAULT "celix_rpc_dumb_host.local." -#define DZC_PORT_DEFAULT 50009 +#define DZC_PORT_DEFAULT 65535 /** * The size of celix service properties. @@ -71,6 +53,13 @@ extern "C" { */ #define DZC_SERVICE_PROPERTIES_SIZE_KEY "DZC_SVC_PROPS_SIZE_KEY" +/** + * The version of mDNS txt record. + * @ref https://www.rfc-editor.org/rfc/rfc6763.html#section-6.7 + */ +#define DZC_TXT_RECORD_VERSION_KEY "txtvers" +#define DZC_CURRENT_TXT_RECORD_VERSION "1" + #ifdef __cplusplus } #endif diff --git a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.c b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.c index f2380eff1..203cca0f8 100644 --- a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.c +++ b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,41 +43,53 @@ #include #include #include +#include -#define DZC_EP_JITTER_INTERVAL 10 -#define DZC_MAX_RESOLVED_TIMEOUT 5 -#define DZC_MAX_RESOLVED_CNT 10 +#define DZC_EP_JITTER_INTERVAL 5//The jitter interval for endpoint.Avoid updating endpoint description on all network interfaces when only one network interface is updated.The endpoint description will be removed when the service is removed for 5 seconds. +#define DZC_MAX_RESOLVED_CNT 10 //Max resolved count for each service when resolve service failed +#define DZC_MAX_RETRY_INTERVAL 5 //Max retry interval when resolve service failed + +#define DZC_MAX_HOSTNAME_LEN 255 //The fully qualified domain name of the host, eg: "MyComputer.local". RFC 1034 specifies that this name is limited to 255 bytes. + +#define DZC_MAX_SERVICE_INSTANCE_NAME_LEN 64 //The instanceName must be 1-63 bytes, + 1 for '\0' struct discovery_zeroconf_watcher { celix_bundle_context_t *ctx; celix_log_helper_t *logHelper; - long epListenerTrkId; char fwUuid[64]; DNSServiceRef sharedRef; - DNSServiceRef browseRef; int eventFd; celix_thread_t watchEPThread; - celix_string_hash_map_t *watchedServices;//key:instanceName+interfaceId, val:watched_service_entry_t* + celix_string_hash_map_t *watchedServices;//key:instanceName+'/'+interfaceIndex, val:watched_service_entry_t* + celix_string_hash_map_t *watchedHosts;//key:hostname+interfaceIndex, val:watched_host_entry_t* celix_thread_mutex_t mutex;//projects below bool running; celix_string_hash_map_t *watchedEndpoints;//key:endpoint id, val:watched_endpoint_entry_t* celix_long_hash_map_t *epls;//key:service id, val:endpoint listener + celix_string_hash_map_t *serviceBrowsers;//key:service subtype(https://www.rfc-editor.org/rfc/rfc6763.html#section-7.1), val:service_browser_entry_t* }; typedef struct watched_endpoint_entry { endpoint_description_t *endpoint; + char *hostname; + int ifIndex; + const char *ipAddressesStr; struct timespec expiredTime; }watched_endpoint_entry_t; typedef struct watched_service_entry { + celix_log_helper_t *logHelper; celix_properties_t *txtRecord; const char *endpointId; int ifIndex; - char instanceName[64];//The instanceName must be 1-63 bytes + char instanceName[DZC_MAX_SERVICE_INSTANCE_NAME_LEN]; + char *hostname; + int port; bool resolved; - struct timespec resolvedStartTime; int resolvedCnt; DNSServiceRef resolveRef; + bool reResolve; + bool markDeleted; }watched_service_entry_t; typedef struct watched_epl_entry { @@ -83,8 +97,26 @@ typedef struct watched_epl_entry { celix_filter_t *filter; }watched_epl_entry_t; -static void discoveryZeroconfWatcher_addEPL(void *handle, void *svc, const celix_properties_t *props); -static void discoveryZeroconfWatcher_removeEPL(void *handle, void *svc, const celix_properties_t *props); +typedef struct service_browser_entry { + DNSServiceRef browseRef; + celix_log_helper_t *logHelper; + celix_string_hash_map_t *watchedServices;//key:instanceName+'/'+interfaceIndex, val:interfaceIndex + int refCnt; + int resolvedCnt; + bool markDeleted; +}service_browser_entry_t; + +typedef struct watched_host_entry { + DNSServiceRef sdRef; + celix_log_helper_t *logHelper; + char *hostname; + int ifIndex; + celix_string_hash_map_t *ipAddresses;//key:ip address, val:true(ipv4)/false(ipv6) + bool resolved; + int resolvedCnt; + bool markDeleted; +}watched_host_entry_t; + static void OnServiceResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *host, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context); static void OnServiceBrowseCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *instanceName, const char *regtype, const char *replyDomain, void *context); static void *discoveryZeroconfWatcher_watchEPThread(void *data); @@ -93,70 +125,80 @@ celix_status_t discoveryZeroconfWatcher_create(celix_bundle_context_t *ctx, celi celix_status_t status = CELIX_SUCCESS; celix_autofree discovery_zeroconf_watcher_t *watcher = (discovery_zeroconf_watcher_t *)calloc(1, sizeof(*watcher)); if (watcher == NULL) { - celix_logHelper_fatal(logHelper, "Watcher: Failed to alloc watcher."); + celix_logHelper_error(logHelper, "Watcher: Failed to alloc watcher."); return CELIX_ENOMEM; } watcher->logHelper = logHelper; watcher->ctx = ctx; watcher->sharedRef = NULL; - watcher->browseRef = NULL; watcher->eventFd = eventfd(0, 0); if (watcher->eventFd < 0) { - celix_logHelper_fatal(logHelper, "Watcher: Failed to open event fd, %d.", errno); + celix_logHelper_error(logHelper, "Watcher: Failed to open event fd, %d.", errno); return CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO, errno); } celix_auto(celix_fd_t) eventFd = watcher->eventFd; const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, NULL); if (fwUuid == NULL || strlen(fwUuid) >= sizeof(watcher->fwUuid)) { - celix_logHelper_fatal(logHelper, "Watcher: Failed to get framework uuid."); + celix_logHelper_error(logHelper, "Watcher: Failed to get framework uuid."); return CELIX_BUNDLE_EXCEPTION; } strcpy(watcher->fwUuid, fwUuid); status = celixThreadMutex_create(&watcher->mutex, NULL); if (status != CELIX_SUCCESS) { - celix_logHelper_fatal(logHelper, "Watcher: Failed to create mutex, %d.", status); + celix_logHelper_error(logHelper, "Watcher: Failed to create mutex, %d.", status); return status; } celix_autoptr(celix_thread_mutex_t) mutex = &watcher->mutex; + celix_autoptr(celix_string_hash_map_t) serviceBrowsers = watcher->serviceBrowsers = celix_stringHashMap_create(); + if (serviceBrowsers == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "Watcher: Failed to create service browsers map."); + return CELIX_ENOMEM; + } celix_string_hash_map_create_options_t epOpts = CELIX_EMPTY_STRING_HASH_MAP_CREATE_OPTIONS; epOpts.storeKeysWeakly = true; celix_autoptr(celix_string_hash_map_t) watchedEndpoints = watcher->watchedEndpoints = celix_stringHashMap_createWithOptions(&epOpts); - assert(watcher->watchedEndpoints); - celix_string_hash_map_create_options_t svcOpts = CELIX_EMPTY_STRING_HASH_MAP_CREATE_OPTIONS; + if (watchedEndpoints == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "Watcher: Failed to create endpoints map."); + return CELIX_ENOMEM; + } + celix_autoptr(celix_string_hash_map_t) watchedHosts = watcher->watchedHosts = celix_stringHashMap_create(); + if (watchedHosts == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "Watcher: Failed to create hosts map."); + return CELIX_ENOMEM; + } celix_autoptr(celix_string_hash_map_t) watchedServices = - watcher->watchedServices = celix_stringHashMap_createWithOptions(&svcOpts); - assert(watcher->watchedServices != NULL); - + watcher->watchedServices = celix_stringHashMap_create(); + if (watchedServices == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "Watcher: Failed to create services map."); + return CELIX_ENOMEM; + } celix_autoptr(celix_long_hash_map_t) epls = watcher->epls = celix_longHashMap_create(); - assert(watcher->epls != NULL); - - celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; - opts.filter.serviceName = OSGI_ENDPOINT_LISTENER_SERVICE; - opts.filter.filter = "(!(DISCOVERY=true))"; - opts.callbackHandle = watcher; - opts.addWithProperties = discoveryZeroconfWatcher_addEPL; - opts.removeWithProperties = discoveryZeroconfWatcher_removeEPL; - watcher->epListenerTrkId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts); - if (watcher->epListenerTrkId < 0) { - celix_logHelper_fatal(logHelper, "Watcher: Failed to register endpoint listener service."); - return CELIX_BUNDLE_EXCEPTION; + if (epls == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "Watcher: Failed to create endpoint listener map."); + return CELIX_ENOMEM; } watcher->running = true; status = celixThread_create(&watcher->watchEPThread,NULL, discoveryZeroconfWatcher_watchEPThread, watcher); if (status != CELIX_SUCCESS) { - celix_bundleContext_stopTracker(ctx, watcher->epListenerTrkId); return status; } celixThread_setName(&watcher->watchEPThread, "DiscWatcher"); celix_steal_ptr(epls); celix_steal_ptr(watchedServices); + celix_steal_ptr(watchedHosts); celix_steal_ptr(watchedEndpoints); + celix_steal_ptr(serviceBrowsers); celix_steal_ptr(mutex); celix_steal_fd(&eventFd); *watcherOut = celix_steal_ptr(watcher); @@ -170,20 +212,26 @@ void discoveryZeroconfWatcher_destroy(discovery_zeroconf_watcher_t *watcher) { eventfd_t val = 1; eventfd_write(watcher->eventFd, val); celixThread_join(watcher->watchEPThread, NULL); - celix_bundleContext_stopTrackerAsync(watcher->ctx, watcher->epListenerTrkId, NULL, NULL); - celix_bundleContext_waitForAsyncStopTracker(watcher->ctx, watcher->epListenerTrkId); celix_longHashMap_destroy(watcher->epls); assert(celix_stringHashMap_size(watcher->watchedServices) == 0); celix_stringHashMap_destroy(watcher->watchedServices); + assert(celix_stringHashMap_size(watcher->watchedHosts) == 0); + celix_stringHashMap_destroy(watcher->watchedHosts); assert(celix_stringHashMap_size(watcher->watchedEndpoints) == 0); celix_stringHashMap_destroy(watcher->watchedEndpoints); + CELIX_STRING_HASH_MAP_ITERATE(watcher->serviceBrowsers, iter) { + service_browser_entry_t *browserEntry = (service_browser_entry_t *)iter.value.ptrValue; + celix_stringHashMap_destroy(browserEntry->watchedServices); + free(browserEntry); + } + celix_stringHashMap_destroy(watcher->serviceBrowsers); celixThreadMutex_destroy(&watcher->mutex); close(watcher->eventFd); free(watcher); return; } -static void discoveryZeroconfWatcher_addEPL(void *handle, void *svc, const celix_properties_t *props) { +int discoveryZeroconfWatcher_addEPL(void *handle, void *svc, const celix_properties_t *props) { assert(handle != NULL); assert(svc != NULL); assert(props != NULL); @@ -191,15 +239,16 @@ static void discoveryZeroconfWatcher_addEPL(void *handle, void *svc, const celix endpoint_listener_t *epl = (endpoint_listener_t *)svc; long serviceId = celix_properties_getAsLong(props, CELIX_FRAMEWORK_SERVICE_ID, -1); if (serviceId == -1) { - return; + return CELIX_ILLEGAL_ARGUMENT; } watched_epl_entry_t *eplEntry = (watched_epl_entry_t *)calloc(1, sizeof(*eplEntry)); if (eplEntry == NULL) { - return; + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to alloc endpoint listener entry."); + return CELIX_ENOMEM; } - const char *scope = celix_properties_get(props, OSGI_ENDPOINT_LISTENER_SCOPE, NULL);//matching on empty filter is always true + const char *scope = celix_properties_get(props, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, NULL);//matching on empty filter is always true celix_filter_t *filter = scope == NULL ? NULL : celix_filter_create(scope); celixThreadMutex_lock(&watcher->mutex); @@ -216,10 +265,10 @@ static void discoveryZeroconfWatcher_addEPL(void *handle, void *svc, const celix celix_longHashMap_put(watcher->epls, serviceId, eplEntry); celixThreadMutex_unlock(&watcher->mutex); - return; + return CELIX_SUCCESS; } -static void discoveryZeroconfWatcher_removeEPL(void *handle, void *svc, const celix_properties_t *props) { +int discoveryZeroconfWatcher_removeEPL(void *handle, void *svc, const celix_properties_t *props) { assert(handle != NULL); assert(svc != NULL); assert(props != NULL); @@ -227,7 +276,7 @@ static void discoveryZeroconfWatcher_removeEPL(void *handle, void *svc, const ce endpoint_listener_t *epl = (endpoint_listener_t *)svc; long serviceId = celix_properties_getAsLong(props, CELIX_FRAMEWORK_SERVICE_ID, -1); if (serviceId == -1) { - return; + return CELIX_ILLEGAL_ARGUMENT; } celixThreadMutex_lock(&watcher->mutex); @@ -246,21 +295,131 @@ static void discoveryZeroconfWatcher_removeEPL(void *handle, void *svc, const ce } celixThreadMutex_unlock(&watcher->mutex); - return; + return CELIX_SUCCESS; +} + +int discoveryZeroConfWatcher_addRSA(void *handle, void *svc, const celix_properties_t *props) { + assert(handle != NULL); + assert(svc != NULL); + assert(props != NULL); + discovery_zeroconf_watcher_t *watcher = (discovery_zeroconf_watcher_t *)handle; + const char *configsSupported = celix_properties_get(props, CELIX_RSA_REMOTE_CONFIGS_SUPPORTED, NULL); + celix_autofree char *configsSupportedCopy = celix_utils_strdup(configsSupported); + if (configsSupportedCopy == NULL) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to dup remote configs supported."); + return CELIX_ENOMEM; + } + bool refreshBrowsers = false; + char *token = strtok(configsSupportedCopy, ","); + while (token != NULL) { + token = celix_utils_trimInPlace(token); + const char *svcSubType = strrchr(token, '.');//We use the last word of config type as mDNS service subtype + if (svcSubType != NULL) { + svcSubType += 1;//skip '.' + } else { + svcSubType = token; + } + do { + size_t subTypeLen = strlen(svcSubType); + if (subTypeLen > 63) {//the subtype identifier is allowed to be up to 63 bytes,https://www.rfc-editor.org/rfc/rfc6763.txt#section-7.2 + celix_logHelper_error(watcher->logHelper, "Watcher: Invalid service type for %s.", token); + break; + } + celix_auto(celix_mutex_lock_guard_t) lockGuard = celixMutexLockGuard_init(&watcher->mutex); + celix_autofree service_browser_entry_t *browserEntry = (service_browser_entry_t *)celix_stringHashMap_get(watcher->serviceBrowsers, svcSubType); + if (browserEntry != NULL) { + browserEntry->refCnt++; + celix_steal_ptr(browserEntry); + break; + } + browserEntry = (service_browser_entry_t *)calloc(1, sizeof(*browserEntry)); + if (browserEntry == NULL) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to alloc service browser entry."); + break; + } + celix_autoptr(celix_string_hash_map_t) watchedServices = browserEntry->watchedServices = celix_stringHashMap_create(); + if (watchedServices == NULL) { + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to create watched services map."); + break; + } + browserEntry->refCnt = 1; + browserEntry->resolvedCnt = 0; + browserEntry->browseRef = NULL; + browserEntry->logHelper = watcher->logHelper; + browserEntry->markDeleted = false; + if (celix_stringHashMap_put(watcher->serviceBrowsers, svcSubType, browserEntry) != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to put service browser entry."); + break; + } + celix_steal_ptr(watchedServices); + celix_steal_ptr(browserEntry); + refreshBrowsers = true; + } while (0); + token = strtok(NULL, ","); + } + + if (refreshBrowsers) { + eventfd_t val = 1; + eventfd_write(watcher->eventFd, val); + } + + return CELIX_SUCCESS; +} + +int discoveryZeroConfWatcher_removeRSA(void *handle, void *svc, const celix_properties_t *props) { + assert(handle != NULL); + assert(svc != NULL); + assert(props != NULL); + discovery_zeroconf_watcher_t *watcher = (discovery_zeroconf_watcher_t *)handle; + const char *configsSupported = celix_properties_get(props, CELIX_RSA_REMOTE_CONFIGS_SUPPORTED, NULL); + celix_autofree char *configsSupportedCopy = celix_utils_strdup(configsSupported); + if (configsSupportedCopy == NULL) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to dup remote configs supported."); + return CELIX_ENOMEM; + } + bool refreshBrowsers = false; + char *token = strtok(configsSupportedCopy, ","); + while (token != NULL) { + token = celix_utils_trimInPlace(token); + const char *svcSubType = strrchr(token, '.'); + if (svcSubType != NULL) { + svcSubType += 1;//skip '.' + } else { + svcSubType = token; + } + celixThreadMutex_lock(&watcher->mutex); + service_browser_entry_t *browserEntry = (service_browser_entry_t *)celix_stringHashMap_get(watcher->serviceBrowsers, svcSubType); + if ((browserEntry != NULL) && (--browserEntry->refCnt == 0)) { + refreshBrowsers = true; + } + celixThreadMutex_unlock(&watcher->mutex); + token = strtok(NULL, ","); + } + + if (refreshBrowsers) { + eventfd_t val = 1; + eventfd_write(watcher->eventFd, val); + } + + return CELIX_SUCCESS; } static void OnServiceResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *host, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) { (void)sdRef;//unused (void)flags;//unused - (void)interfaceIndex;//unused - (void)host;//unused (void)port;//unused (void)fullname;//unused - if (errorCode != kDNSServiceErr_NoError) { - return; - } watched_service_entry_t *svcEntry = (watched_service_entry_t *)context; assert(svcEntry != NULL); + if (errorCode != kDNSServiceErr_NoError || strlen(host) > DZC_MAX_HOSTNAME_LEN) { + celix_logHelper_error(svcEntry->logHelper, "Watcher: Failed to resolve service, or hostname invalid, %d.", errorCode); + return; + } + if (interfaceIndex != svcEntry->ifIndex) { + return; + } celix_properties_t *properties = svcEntry->txtRecord; int cnt = TXTRecordGetCount(txtLen, txtRecord); for (int i = 0; i < cnt; ++i) { @@ -270,18 +429,39 @@ static void OnServiceResolveCallback(DNSServiceRef sdRef, DNSServiceFlags flags, uint8_t valLen = 0; DNSServiceErrorType err = TXTRecordGetItemAtIndex(txtLen, txtRecord, i, sizeof(key), key, &valLen, &valPtr); if (err != kDNSServiceErr_NoError) { + celix_logHelper_error(svcEntry->logHelper, "Watcher: Failed to get txt record item(%s), %d.", key, err); return; } assert(valLen <= UINT8_MAX); memcpy(val, valPtr, valLen); - celix_properties_set(properties, key, val); + int status = celix_properties_set(properties, key, val); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(svcEntry->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(svcEntry->logHelper, "Watcher: Failed to set txt record item(%s), %d.", key, status); + svcEntry->reResolve = (status == CELIX_ENOMEM) ? true : svcEntry->reResolve; + return; + } } - svcEntry->endpointId = celix_properties_get(properties, OSGI_RSA_ENDPOINT_ID, NULL); + svcEntry->endpointId = celix_properties_get(properties, CELIX_RSA_ENDPOINT_ID, NULL); long propSize = celix_properties_getAsLong(properties, DZC_SERVICE_PROPERTIES_SIZE_KEY, 0); - if (propSize == celix_properties_size(properties)) { + const char *version = celix_properties_get(properties, DZC_TXT_RECORD_VERSION_KEY, ""); + if (propSize == celix_properties_size(properties) && strcmp(DZC_CURRENT_TXT_RECORD_VERSION, version) == 0) { + svcEntry->port = ntohs(port); + if (celix_properties_get(properties, CELIX_RSA_IP_ADDRESSES, NULL) != NULL) {//If no need fill in dynamic ip address, no need to resolve ip address + free(svcEntry->hostname);//free old hostname + svcEntry->hostname = celix_utils_strdup(host); + if (svcEntry->hostname == NULL) { + celix_logHelper_error(svcEntry->logHelper, "Watcher: Failed to dup hostname."); + svcEntry->reResolve = true; + return; + } + } + celix_properties_unset(properties, DZC_SERVICE_PROPERTIES_SIZE_KEY);//Service endpoint do not need it + celix_properties_unset(properties, DZC_TXT_RECORD_VERSION_KEY);//Service endpoint do not need it svcEntry->resolved = true; + celix_logHelper_trace(svcEntry->logHelper, "Watcher: Resolved service %s on %u.", svcEntry->instanceName, interfaceIndex); } return; } @@ -290,78 +470,488 @@ static void OnServiceBrowseCallback(DNSServiceRef sdRef, DNSServiceFlags flags, (void)sdRef;//unused (void)regtype;//unused (void)replyDomain;//unused - discovery_zeroconf_watcher_t *watcher = (discovery_zeroconf_watcher_t *)context; - assert(watcher != NULL); + service_browser_entry_t *browser = (service_browser_entry_t *)context; + assert(browser != NULL); if (errorCode != kDNSServiceErr_NoError) { - celix_logHelper_error(watcher->logHelper, "Watcher: Failed to browse service, %d.", errorCode); + celix_logHelper_error(browser->logHelper, "Watcher: Failed to browse service, %d.", errorCode); return; } - watched_service_entry_t *svcEntry = NULL; - if (instanceName == NULL || strlen(instanceName) >= sizeof(svcEntry->instanceName)) { - celix_logHelper_error(watcher->logHelper, "Watcher: service name err."); + if (instanceName == NULL || strlen(instanceName) >= DZC_MAX_SERVICE_INSTANCE_NAME_LEN) { + celix_logHelper_error(browser->logHelper, "Watcher: service name err."); return; } - celix_logHelper_info(watcher->logHelper, "Watcher: %s %s on interface %d.", (flags & kDNSServiceFlagsAdd) ? "Add" : "Remove", instanceName, interfaceIndex); + celix_logHelper_info(browser->logHelper, "Watcher: %s %s on interface %d.", (flags & kDNSServiceFlagsAdd) ? "Add" : "Remove", instanceName, interfaceIndex); char key[128]={0}; - (void)snprintf(key, sizeof(key), "%s%d", instanceName, (int)interfaceIndex); + (void)snprintf(key, sizeof(key), "%s/%d", instanceName, (int)interfaceIndex); if (flags & kDNSServiceFlagsAdd) { - if (celix_stringHashMap_hasKey(watcher->watchedServices, key)) { - celix_logHelper_info(watcher->logHelper,"Watcher: %s already on interface %d.", instanceName, interfaceIndex); - return; - } - svcEntry = (watched_service_entry_t *)calloc(1, sizeof(*svcEntry)); - if (svcEntry == NULL) { - celix_logHelper_error(watcher->logHelper, "Watcher: Failed service entry."); - return; + int status = celix_stringHashMap_putLong(browser->watchedServices, key, interfaceIndex); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(browser->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(browser->logHelper, "Watcher: Failed to cache service instance name, %d.", status); } - svcEntry->resolveRef = NULL; - svcEntry->txtRecord = celix_properties_create(); - svcEntry->endpointId = NULL; - svcEntry->resolved = false; - strcpy(svcEntry->instanceName, instanceName); - svcEntry->ifIndex = (int)interfaceIndex; - svcEntry->resolvedStartTime.tv_sec = INT_MAX; - svcEntry->resolvedCnt = 0; - celix_stringHashMap_put(watcher->watchedServices, key, svcEntry); } else { - svcEntry = (watched_service_entry_t *)celix_stringHashMap_get(watcher->watchedServices, key); - if (svcEntry) { - celix_stringHashMap_remove(watcher->watchedServices, key); - if (svcEntry->resolveRef) { - DNSServiceRefDeallocate(svcEntry->resolveRef); + celix_stringHashMap_remove(browser->watchedServices, key); + } + return; +} + +static void discoveryZeroconfWatcher_pickUpdatedServiceBrowsers(discovery_zeroconf_watcher_t *watcher, celix_string_hash_map_t *updatedServiceBrowsers, unsigned int *pNextWorkIntervalTime) { + int status = CELIX_SUCCESS; + unsigned int nextWorkIntervalTime = *pNextWorkIntervalTime; + + celixThreadMutex_lock(&watcher->mutex); + celix_string_hash_map_iterator_t iter = celix_stringHashMap_begin(watcher->serviceBrowsers); + while (!celix_stringHashMapIterator_isEnd(&iter)) { + service_browser_entry_t *browserEntry = (service_browser_entry_t *)iter.value.ptrValue; + if (watcher->sharedRef != NULL && browserEntry->browseRef == NULL && browserEntry->refCnt > 0 && browserEntry->resolvedCnt < DZC_MAX_RESOLVED_CNT) { + status = celix_stringHashMap_put(updatedServiceBrowsers, iter.key, browserEntry); + if (status != CELIX_SUCCESS) { + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry browse after 5 seconds + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to put browse entry, %d.", status); } - celix_properties_destroy(svcEntry->txtRecord); - free(svcEntry); + } else if (browserEntry->refCnt <= 0) { + status = celix_stringHashMap_put(updatedServiceBrowsers, iter.key, browserEntry); + if (status == CELIX_SUCCESS) { + celix_stringHashMapIterator_remove(&iter); + browserEntry->markDeleted = true; + continue; + } else { + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry browse after 5 seconds + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to put browse entry, %d.", status); + } + } + celix_stringHashMapIterator_next(&iter); + } + celixThreadMutex_unlock(&watcher->mutex); + + //release to be deleted service browsers + celix_string_hash_map_iterator_t iter2 = celix_stringHashMap_begin(updatedServiceBrowsers); + while (!celix_stringHashMapIterator_isEnd(&iter2)) { + service_browser_entry_t *browserEntry = (service_browser_entry_t *)iter2.value.ptrValue; + if (browserEntry->markDeleted) { + celix_logHelper_trace(watcher->logHelper, "Watcher: Stop to browse service type %s,%s.", DZC_SERVICE_PRIMARY_TYPE, iter2.key); + celix_stringHashMapIterator_remove(&iter2); + if (browserEntry->browseRef) { + DNSServiceRefDeallocate(browserEntry->browseRef); + } + celix_stringHashMap_destroy(browserEntry->watchedServices); + free(browserEntry); + } else { + celix_stringHashMapIterator_next(&iter2); } } + + *pNextWorkIntervalTime = nextWorkIntervalTime; return; } -static void discoveryZeroconfWatcher_resolveServices(discovery_zeroconf_watcher_t *watcher) { +static void discoveryZeroconfWatcher_browseServices(discovery_zeroconf_watcher_t *watcher, celix_string_hash_map_t *updatedServiceBrowsers, unsigned int *pNextWorkIntervalTime) { + unsigned int nextWorkIntervalTime = *pNextWorkIntervalTime; + + CELIX_STRING_HASH_MAP_ITERATE(updatedServiceBrowsers, iter) { + service_browser_entry_t *browserEntry = (service_browser_entry_t *)iter.value.ptrValue; + browserEntry->browseRef = watcher->sharedRef; + char serviceType[128] = {0};//primary type(15bytes) + subtype(63bytes) + (void)snprintf(serviceType, sizeof(serviceType), "%s,%s", DZC_SERVICE_PRIMARY_TYPE, iter.key); + celix_logHelper_trace(watcher->logHelper, "Watcher: Start to browse service type %s.", serviceType); + DNSServiceErrorType dnsErr = DNSServiceBrowse(&browserEntry->browseRef, kDNSServiceFlagsShareConnection, 0, serviceType, "local", OnServiceBrowseCallback, browserEntry); + if (dnsErr != kDNSServiceErr_NoError) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to browse DNS service, %d.", dnsErr); + browserEntry->browseRef = NULL; + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry browse after 5 seconds + } + browserEntry->resolvedCnt ++; + } + + *pNextWorkIntervalTime = nextWorkIntervalTime; + return; +} + +static void discoveryZeroconfWatcher_resolveServices(discovery_zeroconf_watcher_t *watcher, unsigned int *pNextWorkIntervalTime) { + unsigned int nextWorkIntervalTime = *pNextWorkIntervalTime; + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedServices, iter) { watched_service_entry_t *svcEntry = (watched_service_entry_t *)iter.value.ptrValue; - //If resolving is not completed for a long time,then close it, and try again later. - if (svcEntry->resolved == false && svcEntry->resolveRef != NULL && celix_elapsedtime(CLOCK_MONOTONIC, svcEntry->resolvedStartTime) > DZC_MAX_RESOLVED_TIMEOUT) { - DNSServiceRefDeallocate(svcEntry->resolveRef); - svcEntry->resolveRef = NULL; - svcEntry->resolvedStartTime.tv_sec = INT_MAX; - svcEntry->resolvedStartTime.tv_nsec = 0; - celix_logHelper_error(watcher->logHelper, "Watcher: resolve %s on %d timeout.", svcEntry->instanceName, svcEntry->ifIndex); - } if (watcher->sharedRef && svcEntry->resolveRef == NULL && svcEntry->resolvedCnt < DZC_MAX_RESOLVED_CNT) { + celix_logHelper_trace(watcher->logHelper, "Watcher: Start to resolve service %s on %d.", svcEntry->instanceName, svcEntry->ifIndex); svcEntry->resolveRef = watcher->sharedRef; DNSServiceErrorType dnsErr = DNSServiceResolve(&svcEntry->resolveRef, kDNSServiceFlagsShareConnection , svcEntry->ifIndex, svcEntry->instanceName, DZC_SERVICE_PRIMARY_TYPE, "local", OnServiceResolveCallback, svcEntry); if (dnsErr != kDNSServiceErr_NoError) { svcEntry->resolveRef = NULL; celix_logHelper_error(watcher->logHelper, "Watcher: Failed to resolve %s on %d, %d.", svcEntry->instanceName, svcEntry->ifIndex, dnsErr); + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry resolve after 5 seconds } - svcEntry->resolvedStartTime = celix_gettime(CLOCK_MONOTONIC); svcEntry->resolvedCnt ++; } + + if (svcEntry->reResolve) {//release resolveRef and retry resolve service after 5 seconds + svcEntry->reResolve = false; + if (svcEntry->resolveRef) { + DNSServiceRefDeallocate(svcEntry->resolveRef); + svcEntry->resolveRef = NULL; + } + svcEntry->resolvedCnt = 0; + svcEntry->resolved = false; + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry resolve after 5 seconds + } } + *pNextWorkIntervalTime = nextWorkIntervalTime; + return; +} + +static void discoveryZeroconfWatcher_refreshWatchedServices(discovery_zeroconf_watcher_t *watcher, unsigned int *pNextWorkIntervalTime) { + unsigned int nextWorkIntervalTime = *pNextWorkIntervalTime; + + //mark deleted status for all watched services + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedServices, iter) { + watched_service_entry_t *svcEntry = (watched_service_entry_t *)iter.value.ptrValue; + svcEntry->markDeleted = true; + } + + celixThreadMutex_lock(&watcher->mutex); + CELIX_STRING_HASH_MAP_ITERATE(watcher->serviceBrowsers, iter) { + service_browser_entry_t *browserEntry = (service_browser_entry_t *)iter.value.ptrValue; + CELIX_STRING_HASH_MAP_ITERATE(browserEntry->watchedServices, iter2) { + const char *key = iter2.key; + int interfaceIndex = (int)iter2.value.longValue; + celix_autofree watched_service_entry_t *svcEntry = (watched_service_entry_t *)celix_stringHashMap_get(watcher->watchedServices, key); + if (svcEntry != NULL) { + svcEntry->markDeleted = false; + celix_steal_ptr(svcEntry); + continue; + } + char *instanceNameEnd = strrchr(key, '/'); + if (instanceNameEnd == NULL || instanceNameEnd-key >= DZC_MAX_SERVICE_INSTANCE_NAME_LEN) { + celix_logHelper_error(watcher->logHelper, "Watcher: Invalid service instance key, %s.", key); + continue; + } + svcEntry = (watched_service_entry_t *)calloc(1, sizeof(*svcEntry)); + if (svcEntry == NULL) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to alloc service entry."); + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry browse after 5 seconds + continue; + } + svcEntry->resolveRef = NULL; + svcEntry->txtRecord = celix_properties_create(); + if (svcEntry->txtRecord == NULL) { + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to create txt record for service entry."); + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry browse after 5 seconds + continue; + } + svcEntry->endpointId = NULL; + svcEntry->resolved = false; + strncpy(svcEntry->instanceName, key, instanceNameEnd-key); + svcEntry->instanceName[instanceNameEnd-key] = '\0'; + svcEntry->hostname = NULL; + svcEntry->ifIndex = interfaceIndex; + svcEntry->resolvedCnt = 0; + svcEntry->reResolve = false; + svcEntry->markDeleted = false; + svcEntry->logHelper = watcher->logHelper; + int status = celix_stringHashMap_put(watcher->watchedServices, key, svcEntry); + if (status != CELIX_SUCCESS) { + celix_properties_destroy(svcEntry->txtRecord); + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to put service entry, %d.", status); + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry browse after 5 seconds + continue; + } + celix_steal_ptr(svcEntry); + } + } + celixThreadMutex_unlock(&watcher->mutex); + + //remove to be deleted services + celix_string_hash_map_iterator_t iter = celix_stringHashMap_begin(watcher->watchedServices); + while (!celix_stringHashMapIterator_isEnd(&iter)) { + watched_service_entry_t *svcEntry = (watched_service_entry_t *)iter.value.ptrValue; + if (svcEntry->markDeleted) { + celix_logHelper_trace(watcher->logHelper, "Watcher: Stop to resolve service %s on %d.", svcEntry->instanceName, svcEntry->ifIndex); + celix_stringHashMapIterator_remove(&iter); + if (svcEntry->resolveRef) { + DNSServiceRefDeallocate(svcEntry->resolveRef); + } + celix_properties_destroy(svcEntry->txtRecord); + free(svcEntry->hostname); + free(svcEntry); + } else { + celix_stringHashMapIterator_next(&iter); + } + } + + discoveryZeroconfWatcher_resolveServices(watcher, &nextWorkIntervalTime); + + *pNextWorkIntervalTime = nextWorkIntervalTime; + return; +} + +static void onGetAddrInfoCb (DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, + const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context) { + (void)sdRef;//unused + (void)ttl;//unused + (void)hostname;//unused + int status = CELIX_SUCCESS; + watched_host_entry_t *hostEntry = (watched_host_entry_t *)context; + assert(hostEntry != NULL); + if (errorCode != kDNSServiceErr_NoError || address == NULL || (address->sa_family != AF_INET && address->sa_family != AF_INET6)) { + celix_logHelper_error(hostEntry->logHelper, "Watcher: Failed to resolve host %s on %d, %d.", hostEntry->hostname, hostEntry->ifIndex, errorCode); + return; + } + if (ifIndex != hostEntry->ifIndex) { + return; + } + + char ip[INET6_ADDRSTRLEN] = {0}; + if (address->sa_family == AF_INET) { + inet_ntop(AF_INET, &((struct sockaddr_in *)address)->sin_addr, ip, sizeof(ip)); + } else if (address->sa_family == AF_INET6) { + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)address)->sin6_addr, ip, sizeof(ip)); + } + + if (flags & kDNSServiceFlagsAdd) { + status = celix_stringHashMap_putBool(hostEntry->ipAddresses, ip, address->sa_family == AF_INET); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(hostEntry->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(hostEntry->logHelper, "Watcher: Failed to add ip address(%s). %d.", ip, status); + } + } else { + celix_stringHashMap_remove(hostEntry->ipAddresses, ip); + } + + celix_logHelper_trace(hostEntry->logHelper, "Watcher: %s ip %s for host %s on %d.", (flags & kDNSServiceFlagsAdd) ? "Add" : "Remove", ip, hostEntry->hostname, hostEntry->ifIndex); + + hostEntry->resolved = !(flags & kDNSServiceFlagsMoreComing); + + return; +} + +static watched_host_entry_t *discoveryZeroconfWatcher_getHostEntry(discovery_zeroconf_watcher_t *watcher, const char *hostname, int ifIndex) { + char key[256 + 10] = {0};//max hostname length is 255, ifIndex is int + (void)snprintf(key, sizeof(key), "%s%d", hostname, ifIndex); + return (watched_host_entry_t *)celix_stringHashMap_get(watcher->watchedHosts, key); +} + +static void discoveryZeroconfWatcher_updateWatchedHosts(discovery_zeroconf_watcher_t *watcher, unsigned int *pNextWorkIntervalTime) { + unsigned int nextWorkIntervalTime = *pNextWorkIntervalTime; + //mark deleted hosts + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedHosts, iter) { + watched_host_entry_t *hostEntry = (watched_host_entry_t *)iter.value.ptrValue; + hostEntry->markDeleted = true; + } + + //add or mark hosts + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedServices, iter) { + watched_service_entry_t *svcEntry = (watched_service_entry_t *) iter.value.ptrValue; + if (svcEntry->hostname != NULL && svcEntry->ifIndex != kDNSServiceInterfaceIndexLocalOnly) { + celix_autofree watched_host_entry_t *hostEntry = discoveryZeroconfWatcher_getHostEntry(watcher, svcEntry->hostname, svcEntry->ifIndex); + if (hostEntry != NULL) { + hostEntry->markDeleted = false; + celix_steal_ptr(hostEntry); + } else { + hostEntry = (watched_host_entry_t *)calloc(1, sizeof(*hostEntry)); + if (hostEntry == NULL) { + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry after 5 seconds + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to alloc host entry for %s.", svcEntry->instanceName); + continue; + } + celix_autoptr(celix_string_hash_map_t) ipAddresses = hostEntry->ipAddresses = celix_stringHashMap_create(); + if (ipAddresses == NULL) { + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry after 5 seconds + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to alloc ip address list for %s.", svcEntry->instanceName); + continue; + } + celix_autofree char *hostname = hostEntry->hostname = celix_utils_strdup(svcEntry->hostname); + if (hostname == NULL) { + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry after 5 seconds + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to dup hostname for %s.", svcEntry->instanceName); + continue; + } + hostEntry->sdRef = NULL; + hostEntry->logHelper = watcher->logHelper; + hostEntry->resolved = false; + hostEntry->ifIndex = svcEntry->ifIndex; + hostEntry->resolvedCnt = 0; + hostEntry->markDeleted = false; + char key[256 + 10] = {0};//max hostname length is 255, ifIndex is int + (void)snprintf(key, sizeof(key), "%s%d", svcEntry->hostname, svcEntry->ifIndex); + if (celix_stringHashMap_put(watcher->watchedHosts, key, hostEntry) != CELIX_SUCCESS) { + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry after 5 seconds + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to add host entry for %s.", svcEntry->instanceName); + continue; + } + celix_steal_ptr(hostname); + celix_steal_ptr(ipAddresses); + celix_steal_ptr(hostEntry); + } + } + } + + //delete hosts + celix_string_hash_map_iterator_t iter = celix_stringHashMap_begin(watcher->watchedHosts); + while (!celix_stringHashMapIterator_isEnd(&iter)) { + watched_host_entry_t *hostEntry = (watched_host_entry_t *)iter.value.ptrValue; + if (hostEntry->markDeleted) { + celix_logHelper_trace(watcher->logHelper, "Watcher: Stop to resolve host %s on %d.", hostEntry->hostname, hostEntry->ifIndex); + celix_stringHashMapIterator_remove(&iter); + if (hostEntry->sdRef) { + DNSServiceRefDeallocate(hostEntry->sdRef); + } + celix_stringHashMap_destroy(hostEntry->ipAddresses); + free(hostEntry->hostname); + free(hostEntry); + } else { + celix_stringHashMapIterator_next(&iter); + } + } + + *pNextWorkIntervalTime = nextWorkIntervalTime; + return; +} + +static void discoveryZeroconfWatcher_refreshHostsInfo(discovery_zeroconf_watcher_t *watcher, unsigned int *pNextWorkIntervalTime) { + unsigned int nextWorkIntervalTime = *pNextWorkIntervalTime; + + discoveryZeroconfWatcher_updateWatchedHosts(watcher, &nextWorkIntervalTime); + + //resolve hosts + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedHosts, iter1) { + watched_host_entry_t *hostEntry = (watched_host_entry_t *)iter1.value.ptrValue; + if (watcher->sharedRef && hostEntry->sdRef == NULL && hostEntry->resolvedCnt < DZC_MAX_RESOLVED_CNT) { + celix_logHelper_trace(watcher->logHelper, "Watcher: Start to resolve host %s on %d.", hostEntry->hostname, hostEntry->ifIndex); + hostEntry->sdRef = watcher->sharedRef; + DNSServiceErrorType dnsErr = DNSServiceGetAddrInfo(&hostEntry->sdRef, kDNSServiceFlagsShareConnection, hostEntry->ifIndex, kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, hostEntry->hostname, onGetAddrInfoCb, hostEntry); + if (dnsErr != kDNSServiceErr_NoError) { + hostEntry->sdRef = NULL; + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to get address info for %s on %d, %d.", hostEntry->hostname, hostEntry->ifIndex, dnsErr); + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry resolve after 5 seconds + } + hostEntry->resolvedCnt ++; + } + } + + *pNextWorkIntervalTime = nextWorkIntervalTime; + return; +} + +static bool discoveryZeroConfWatcher_isHostResolved(discovery_zeroconf_watcher_t *watcher, const char *hostname, int ifIndex) { + if (hostname == NULL || ifIndex == kDNSServiceInterfaceIndexLocalOnly) {//if no need to resolve host info, then return true + return true; + } + watched_host_entry_t *hostEntry = discoveryZeroconfWatcher_getHostEntry(watcher, hostname, ifIndex); + if (hostEntry == NULL) { + return false; + } + if (celix_stringHashMap_size(hostEntry->ipAddresses) == 0) { + return false; + } + + return hostEntry->resolved; +} + +static int discoveryZeroConfWatcher_getHostIpAddresses(discovery_zeroconf_watcher_t *watcher, const char *hostname, int ifIndex, char **ipAddressesStrOut) { + celix_autofree char *ipAddressesStr = NULL; + if (ifIndex == kDNSServiceInterfaceIndexLocalOnly) { + *ipAddressesStrOut = celix_utils_strdup("127.0.0.1,::1"); + return (*ipAddressesStrOut != NULL) ? CELIX_SUCCESS : CELIX_ENOMEM; + } + watched_host_entry_t *hostEntry = discoveryZeroconfWatcher_getHostEntry(watcher, hostname, ifIndex); + if (hostEntry != NULL) { + CELIX_STRING_HASH_MAP_ITERATE(hostEntry->ipAddresses, iter) { + const char *ip = iter.key; + char *tmp= NULL; + if (ipAddressesStr == NULL) { + tmp = celix_utils_strdup(ip); + } else { + asprintf(&tmp, "%s,%s", ipAddressesStr, ip); + } + if (tmp == NULL) { + return CELIX_ENOMEM; + } + free(ipAddressesStr); + ipAddressesStr = tmp; + } + } + if (ipAddressesStr == NULL) { + return CELIX_ILLEGAL_STATE; + } + *ipAddressesStrOut = celix_steal_ptr(ipAddressesStr); + return CELIX_SUCCESS; +} + +static int discoveryZeroConfWatcher_createEndpointEntryForService(discovery_zeroconf_watcher_t *watcher, watched_service_entry_t *svcEntry, watched_endpoint_entry_t **epOut) { + celix_autoptr(celix_properties_t) properties = celix_properties_copy(svcEntry->txtRecord); + if (properties == NULL) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to copy endpoint properties."); + return CELIX_ENOMEM; + } + celix_autoptr(endpoint_description_t) ep = NULL; + int status = endpointDescription_create(properties, &ep); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to create endpoint description. %d.", status); + return status; + } + celix_steal_ptr(properties);//properties now owned by ep + + celix_autofree watched_endpoint_entry_t *epEntry = (watched_endpoint_entry_t *)calloc(1, sizeof(*epEntry)); + if (epEntry == NULL) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to alloc endpoint entry."); + return CELIX_ENOMEM; + } + epEntry->endpoint = ep; + epEntry->ifIndex = svcEntry->ifIndex; + epEntry->expiredTime.tv_sec = INT_MAX; + epEntry->ipAddressesStr = NULL; + epEntry->hostname = NULL; + + if (svcEntry->hostname == NULL) {//if no need to resolve host info, then return CELIX_SUCCESS + celix_steal_ptr(ep); + *epOut = celix_steal_ptr(epEntry); + return CELIX_SUCCESS; + } + + celix_autofree char *hostname = epEntry->hostname = celix_utils_strdup(svcEntry->hostname); + if (hostname == NULL) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to dup hostname for endpoint %s.", svcEntry->instanceName); + return CELIX_ENOMEM; + } + + celix_autofree char *ipAddressesStr = NULL; + status = discoveryZeroConfWatcher_getHostIpAddresses(watcher, hostname, svcEntry->ifIndex, &ipAddressesStr); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to get ip addresses for endpoint %s.", svcEntry->instanceName); + return status; + } + + status = celix_properties_setLong(ep->properties, CELIX_RSA_PORT, svcEntry->port); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to set imported config port."); + return status; + } + status = celix_properties_set(ep->properties, CELIX_RSA_IP_ADDRESSES, ipAddressesStr); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to set imported config ip address list."); + return status; + } + epEntry->ipAddressesStr = celix_properties_get(ep->properties, CELIX_RSA_IP_ADDRESSES, ""); + + celix_steal_ptr(hostname); + celix_steal_ptr(ep); + *epOut = celix_steal_ptr(epEntry); + + return CELIX_SUCCESS; +} + +static void endpointEntry_destroy(watched_endpoint_entry_t *entry) { + endpointDescription_destroy(entry->endpoint); + free(entry->hostname); + free(entry); return; } @@ -381,96 +971,161 @@ static void discoveryZeroConfWatcher_informEPLs(discovery_zeroconf_watcher_t *wa return; } -static bool discoveryZeroconfWatcher_hasWatchedServiceForEndpoint(discovery_zeroconf_watcher_t *watcher, const char *endpointId) { - CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedServices, iter) { +static void discoveryZeroconfWatcher_filterSameFrameWorkServices(discovery_zeroconf_watcher_t *watcher) { + celix_string_hash_map_iterator_t iter = celix_stringHashMap_begin(watcher->watchedServices); + while (!celix_stringHashMapIterator_isEnd(&iter)) { watched_service_entry_t *svcEntry = (watched_service_entry_t *)iter.value.ptrValue; - if (svcEntry->endpointId != NULL && strcmp(svcEntry->endpointId, endpointId) == 0) { - return true; - } - } - return false; -} - -static void discoveryZeroconfWatcher_refreshEndpoints(discovery_zeroconf_watcher_t *watcher) { - watched_endpoint_entry_t *epEntry = NULL; - watched_service_entry_t *svcEntry = NULL; - - //remove self endpoints - celix_string_hash_map_iterator_t svcIter = celix_stringHashMap_begin(watcher->watchedServices); - while (!celix_stringHashMapIterator_isEnd(&svcIter)) { - svcEntry = (watched_service_entry_t *)svcIter.value.ptrValue; if (svcEntry->resolved) { - const char *epFwUuid = celix_properties_get(svcEntry->txtRecord, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); + const char *epFwUuid = celix_properties_get(svcEntry->txtRecord, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); if (epFwUuid != NULL && strcmp(epFwUuid, watcher->fwUuid) == 0) { celix_logHelper_debug(watcher->logHelper, "Watcher: Ignore self endpoint for %s.", celix_properties_get(svcEntry->txtRecord, CELIX_FRAMEWORK_SERVICE_NAME, "unknown")); - celix_stringHashMapIterator_remove(&svcIter); + celix_stringHashMapIterator_remove(&iter); + + //remove service instance name from service browser + char instanceNameKey[128]={0}; + (void)snprintf(instanceNameKey, sizeof(instanceNameKey), "%s/%d", svcEntry->instanceName, svcEntry->ifIndex); + celixThreadMutex_lock(&watcher->mutex); + CELIX_STRING_HASH_MAP_ITERATE(watcher->serviceBrowsers, iter2) { + service_browser_entry_t *browserEntry = (service_browser_entry_t *)iter2.value.ptrValue; + celix_stringHashMap_remove(browserEntry->watchedServices, instanceNameKey); + } + celixThreadMutex_unlock(&watcher->mutex); + + //release service info if (svcEntry->resolveRef) { DNSServiceRefDeallocate(svcEntry->resolveRef); } celix_properties_destroy(svcEntry->txtRecord); + free(svcEntry->hostname); free(svcEntry); continue; } } - celix_stringHashMapIterator_next(&svcIter); + celix_stringHashMapIterator_next(&iter); } + return; +} - celixThreadMutex_lock(&watcher->mutex); +static bool discoveryZeroconfWatcher_checkEndpointIpAddressesChanged(discovery_zeroconf_watcher_t *watcher, watched_endpoint_entry_t *endpointEntry) { + if (endpointEntry->hostname == NULL || endpointEntry->ifIndex == kDNSServiceInterfaceIndexLocalOnly) { + return false; + } + watched_host_entry_t *hostEntry = discoveryZeroconfWatcher_getHostEntry(watcher, endpointEntry->hostname, endpointEntry->ifIndex); + if (hostEntry == NULL) { + return false; + } + if (!hostEntry->resolved) { + return false; + } + if (endpointEntry->ipAddressesStr != NULL) { + const char *p = endpointEntry->ipAddressesStr; + const char *end = p + strlen(p); + char ip[INET6_ADDRSTRLEN] = {0}; + int i = 0; + int ipCnt = 0; + while (p <= end && i < INET6_ADDRSTRLEN){ + ip[i] = (*p == ',') ? '\0' : *p; + if (ip[i++] == '\0') { + if (!celix_stringHashMap_hasKey(hostEntry->ipAddresses, ip)) { + return true; + } + i = 0; + ipCnt ++; + } + p++; + } + if (ipCnt != celix_stringHashMap_size(hostEntry->ipAddresses)) { + return true; + } + } + return false; +} + +static bool endpointEntry_matchServiceEntry(watched_endpoint_entry_t *epEntry, watched_service_entry_t *svcEntry) { + if (epEntry->ifIndex != svcEntry->ifIndex) { + return false; + } + if (epEntry->hostname == NULL && svcEntry->hostname == NULL) { + return true; + } + if (epEntry->hostname != NULL && svcEntry->hostname != NULL && strcmp(epEntry->hostname, svcEntry->hostname) == 0) { + return true; + } + return false; +} + +static void discoveryZeroconfWatcher_refreshEndpoints(discovery_zeroconf_watcher_t *watcher, unsigned int *pNextWorkIntervalTime) { + watched_endpoint_entry_t *epEntry = NULL; + watched_service_entry_t *svcEntry = NULL; + unsigned int nextWorkIntervalTime = *pNextWorkIntervalTime; + + celix_auto(celix_mutex_lock_guard_t) lockGuard = celixMutexLockGuard_init(&watcher->mutex); + + struct timespec now = celix_gettime(CLOCK_MONOTONIC); + //remove the endpoint which ip address list changed and expired endpoint, and mark expired time of the endpoint. + celix_string_hash_map_iterator_t epIter = celix_stringHashMap_begin(watcher->watchedEndpoints); + while (!celix_stringHashMapIterator_isEnd(&epIter)) { + epEntry = (watched_endpoint_entry_t *)epIter.value.ptrValue; + if (discoveryZeroconfWatcher_checkEndpointIpAddressesChanged(watcher, epEntry) + || celix_compareTime(&now, &epEntry->expiredTime) >= 0) { + celix_logHelper_debug(watcher->logHelper, "Watcher: Remove endpoint for %s on %d.", epEntry->endpoint->serviceName, epEntry->ifIndex); + celix_stringHashMapIterator_remove(&epIter); + discoveryZeroConfWatcher_informEPLs(watcher, epEntry->endpoint, false); + endpointEntry_destroy(epEntry); + } else { + if (epEntry->expiredTime.tv_sec == INT_MAX) { + epEntry->expiredTime = celix_gettime(CLOCK_MONOTONIC); + epEntry->expiredTime.tv_sec += DZC_EP_JITTER_INTERVAL; + } + celix_stringHashMapIterator_next(&epIter); + } + } //add new endpoint CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedServices, iter) { svcEntry = (watched_service_entry_t *)iter.value.ptrValue; if (svcEntry->endpointId != NULL && svcEntry->resolved) { epEntry = (watched_endpoint_entry_t *)celix_stringHashMap_get(watcher->watchedEndpoints, svcEntry->endpointId); - if (epEntry == NULL) { - celix_properties_t *properties = celix_properties_copy(svcEntry->txtRecord); - endpoint_description_t *ep = NULL; - celix_status_t status = endpointDescription_create(properties,&ep); + if (epEntry == NULL && discoveryZeroConfWatcher_isHostResolved(watcher, svcEntry->hostname, svcEntry->ifIndex)) { + celix_status_t status = discoveryZeroConfWatcher_createEndpointEntryForService(watcher, svcEntry, &epEntry); if (status != CELIX_SUCCESS) { - celix_properties_destroy(properties); // If properties invalid,endpointDescription_create will return error. - // Avoid endpointDescription_create again, set svcEntry->resolved false. - svcEntry->resolved = false; + // Avoid create endpointDescription again, set svcEntry->resolved false. + if (status != CELIX_ENOMEM) { + svcEntry->resolved = false; + } else { + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry after 5 seconds + } + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to create endpoint for %s. %d.", svcEntry->instanceName, status); continue; } - celix_logHelper_debug(watcher->logHelper, "Watcher: Add endpoint for %s on %s.", ep->serviceName,ep->frameworkUUID); - epEntry = (watched_endpoint_entry_t *)calloc(1, sizeof(*epEntry)); - if (epEntry == NULL) { - celix_logHelper_error(watcher->logHelper, "Watcher:Failed to alloc endpoint entry."); - //It will free ep and properties - endpointDescription_destroy(ep); - continue; + celix_logHelper_debug(watcher->logHelper, "Watcher: Add endpoint for %s on %d.", epEntry->endpoint->serviceName, epEntry->ifIndex); + if (celix_stringHashMap_put(watcher->watchedEndpoints, epEntry->endpoint->id, epEntry) == CELIX_SUCCESS) { + discoveryZeroConfWatcher_informEPLs(watcher, epEntry->endpoint, true); + } else { + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to add endpoint for %s.", epEntry->endpoint->serviceName); + endpointEntry_destroy(epEntry); + nextWorkIntervalTime = MIN(nextWorkIntervalTime, DZC_MAX_RETRY_INTERVAL);//retry after 5 seconds } - epEntry->endpoint = ep; - discoveryZeroConfWatcher_informEPLs(watcher, ep, true); - celix_stringHashMap_put(watcher->watchedEndpoints, epEntry->endpoint->id, epEntry); + } else if (epEntry != NULL && endpointEntry_matchServiceEntry(epEntry, svcEntry)) { + epEntry->expiredTime.tv_sec = INT_MAX; + epEntry->expiredTime.tv_nsec = 0; } - epEntry->expiredTime.tv_sec = INT_MAX; } } - //remove expired endpoint - celix_string_hash_map_iterator_t epIter = celix_stringHashMap_begin(watcher->watchedEndpoints); - while (!celix_stringHashMapIterator_isEnd(&epIter)) { - epEntry = (watched_endpoint_entry_t *)epIter.value.ptrValue; - const char *endpointId = epIter.key; - if (!discoveryZeroconfWatcher_hasWatchedServiceForEndpoint(watcher, endpointId)) { - if (epEntry->expiredTime.tv_sec == INT_MAX) { - epEntry->expiredTime = celix_gettime(CLOCK_MONOTONIC); - } else if (celix_elapsedtime(CLOCK_MONOTONIC, epEntry->expiredTime) >= DZC_EP_JITTER_INTERVAL) { - celix_logHelper_debug(watcher->logHelper, "Watcher: Remove endpoint for %s on %s.", epEntry->endpoint->serviceName, epEntry->endpoint->frameworkUUID); - celix_stringHashMapIterator_remove(&epIter); - discoveryZeroConfWatcher_informEPLs(watcher, epEntry->endpoint, false); - endpointDescription_destroy(epEntry->endpoint); - free(epEntry); - continue; - } + //calculate next work time + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedEndpoints, iter) { + epEntry = (watched_endpoint_entry_t *)iter.value.ptrValue; + if (epEntry->expiredTime.tv_sec != INT_MAX) { + int timeOut = celix_difftime(&now, &epEntry->expiredTime) + 1; + assert(timeOut >= 0);//We have removed expired endpoint before. + nextWorkIntervalTime = MIN(nextWorkIntervalTime, timeOut); } - celix_stringHashMapIterator_next(&epIter); } - celixThreadMutex_unlock(&watcher->mutex); - + *pNextWorkIntervalTime = nextWorkIntervalTime; return; } @@ -479,8 +1134,7 @@ static void discoveryZeroconfWatcher_clearEndpoints(discovery_zeroconf_watcher_t CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedEndpoints, iter) { watched_endpoint_entry_t *epEntry = (watched_endpoint_entry_t *)iter.value.ptrValue; discoveryZeroConfWatcher_informEPLs(watcher, epEntry->endpoint, false); - endpointDescription_destroy(epEntry->endpoint); - free(epEntry); + endpointEntry_destroy(epEntry); } celix_stringHashMap_clear(watcher->watchedEndpoints); celixThreadMutex_unlock(&watcher->mutex); @@ -491,15 +1145,33 @@ static void discoveryZeroconfWatcher_closeMDNSConnection(discovery_zeroconf_watc if (watcher->sharedRef) { DNSServiceRefDeallocate(watcher->sharedRef); watcher->sharedRef = NULL; - watcher->browseRef = NULL;//no need free entry->browseRef, 'DNSServiceRefDeallocate(watcher->sharedRef)' has do it. } + + celixThreadMutex_lock(&watcher->mutex); + CELIX_STRING_HASH_MAP_ITERATE(watcher->serviceBrowsers, iter) { + service_browser_entry_t *browseEntry = (service_browser_entry_t *)iter.value.ptrValue; + browseEntry->browseRef = NULL;//no need free V->browseRef, 'DNSServiceRefDeallocate(watcher->sharedRef)' has done it. + browseEntry->resolvedCnt = 0; + celix_stringHashMap_clear(browseEntry->watchedServices); + } + celixThreadMutex_unlock(&watcher->mutex); + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedServices, iter) { watched_service_entry_t *svcEntry = (watched_service_entry_t *) iter.value.ptrValue; - //no need free svcEntry->resolveRef, 'DNSServiceRefDeallocate(watcher->sharedRef)' has do it. + //no need free svcEntry->resolveRef, 'DNSServiceRefDeallocate(watcher->sharedRef)' has done it. celix_properties_destroy(svcEntry->txtRecord); + free(svcEntry->hostname); free(svcEntry); } celix_stringHashMap_clear(watcher->watchedServices); + CELIX_STRING_HASH_MAP_ITERATE(watcher->watchedHosts, iter) { + watched_host_entry_t *hostEntry = (watched_host_entry_t *) iter.value.ptrValue; + //no need free hostEntry->sdRef, 'DNSServiceRefDeallocate(watcher->sharedRef)' has done it. + celix_stringHashMap_destroy(hostEntry->ipAddresses); + free(hostEntry->hostname); + free(hostEntry); + } + celix_stringHashMap_clear(watcher->watchedHosts); return; } @@ -523,22 +1195,26 @@ static void *discoveryZeroconfWatcher_watchEPThread(void *data) { eventfd_t val; int dsFd; int maxFd; - struct timeval timeout; + struct timeval timeoutVal; + struct timeval *timeout = NULL; + unsigned int timeoutInS = UINT_MAX; bool running = watcher->running; + + celix_autoptr(celix_string_hash_map_t) updatedBrowsers = celix_stringHashMap_create(); + if (updatedBrowsers == NULL) { + celix_logHelper_logTssErrors(watcher->logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(watcher->logHelper, "Watcher: Failed to create updated service browsers cache."); + return NULL; + } + while (running) { if (watcher->sharedRef == NULL) { dnsErr = DNSServiceCreateConnection(&watcher->sharedRef); if (dnsErr != kDNSServiceErr_NoError) { celix_logHelper_error(watcher->logHelper, "Watcher: Failed to create connection for DNS service, %d.", dnsErr); - } - } - - if (watcher->sharedRef != NULL && watcher->browseRef == NULL) { - watcher->browseRef = watcher->sharedRef; - dnsErr = DNSServiceBrowse(&watcher->browseRef, kDNSServiceFlagsShareConnection, 0, DZC_SERVICE_PRIMARY_TYPE, "local", OnServiceBrowseCallback, watcher); - if (dnsErr != kDNSServiceErr_NoError) { - celix_logHelper_error(watcher->logHelper, "Watcher: Failed to browse DNS service, %d.", dnsErr); - watcher->browseRef = NULL; + timeoutInS = MIN(DZC_MAX_RETRY_INTERVAL, timeoutInS);//retry after 5 seconds + } else { + timeoutInS = 0;//need to browse service immediately when connection created } } @@ -550,19 +1226,23 @@ static void *discoveryZeroconfWatcher_watchEPThread(void *data) { assert(dsFd >= 0); FD_SET(dsFd, &readfds); maxFd = MAX(maxFd, dsFd); - timeout.tv_sec = 1; - timeout.tv_usec = 0; } else { dsFd = -1; - timeout.tv_sec = 5; - timeout.tv_usec = 0; } - int result = select(maxFd+1, &readfds, NULL, NULL, &timeout); + if (timeoutInS == UINT_MAX) { + timeout = NULL;//wait until eventfd or dsFd ready + } else { + timeoutVal.tv_sec = timeoutInS; + timeoutVal.tv_usec = 0; + timeout = &timeoutVal; + } + + int result = select(maxFd+1, &readfds, NULL, NULL, timeout); if (result > 0) { if (FD_ISSET(watcher->eventFd, &readfds)) { eventfd_read(watcher->eventFd, &val); - //do nothing, the thread will be exited + //the thread will be exited or browse service } if (dsFd >= 0 && FD_ISSET(dsFd, &readfds)) { @@ -570,10 +1250,19 @@ static void *discoveryZeroconfWatcher_watchEPThread(void *data) { } } else if (result == -1 && errno != EINTR) { celix_logHelper_error(watcher->logHelper, "Watcher: Error Selecting event, %d.", errno); + sleep(1);//avoid busy loop } - discoveryZeroconfWatcher_resolveServices(watcher); - discoveryZeroconfWatcher_refreshEndpoints(watcher); + timeoutInS = UINT_MAX; + discoveryZeroconfWatcher_pickUpdatedServiceBrowsers(watcher, updatedBrowsers, &timeoutInS); + if (celix_stringHashMap_size(updatedBrowsers) > 0) { + discoveryZeroconfWatcher_browseServices(watcher, updatedBrowsers, &timeoutInS); + celix_stringHashMap_clear(updatedBrowsers); + } + discoveryZeroconfWatcher_refreshWatchedServices(watcher, &timeoutInS); + discoveryZeroconfWatcher_filterSameFrameWorkServices(watcher); + discoveryZeroconfWatcher_refreshHostsInfo(watcher, &timeoutInS); + discoveryZeroconfWatcher_refreshEndpoints(watcher, &timeoutInS); celixThreadMutex_lock(&watcher->mutex); running = watcher->running; diff --git a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.h b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.h index ee9c97d15..da1b2a4e8 100644 --- a/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.h +++ b/bundles/remote_services/discovery_zeroconf/src/discovery_zeroconf_watcher.h @@ -36,6 +36,14 @@ void discoveryZeroconfWatcher_destroy(discovery_zeroconf_watcher_t *watcher); CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(discovery_zeroconf_watcher_t, discoveryZeroconfWatcher_destroy) +int discoveryZeroconfWatcher_addEPL(void *handle, void *svc, const celix_properties_t *props); + +int discoveryZeroconfWatcher_removeEPL(void *handle, void *svc, const celix_properties_t *props); + +int discoveryZeroConfWatcher_addRSA(void *handle, void *svc, const celix_properties_t *props); + +int discoveryZeroConfWatcher_removeRSA(void *handle, void *svc, const celix_properties_t *props); + #ifdef __cplusplus } #endif diff --git a/bundles/remote_services/examples/calculator_service/src/calculator_activator.c b/bundles/remote_services/examples/calculator_service/src/calculator_activator.c index 261169e0e..30ab57dca 100644 --- a/bundles/remote_services/examples/calculator_service/src/calculator_activator.c +++ b/bundles/remote_services/examples/calculator_service/src/calculator_activator.c @@ -40,9 +40,9 @@ celix_status_t calculatorBndStart(struct activator *act, celix_bundle_context_t act->service.sqrt = (void*)calculator_sqrt; celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, CALCULATOR_SERVICE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, CALCULATOR_CONFIGURATION_TYPE); act->svcId = celix_bundleContext_registerService(ctx, &act->service, CALCULATOR_SERVICE, properties); } diff --git a/bundles/remote_services/examples/interceptors/src/rs_interceptor_activator.c b/bundles/remote_services/examples/interceptors/src/rs_interceptor_activator.c index d580ca41b..79c7ef6dd 100644 --- a/bundles/remote_services/examples/interceptors/src/rs_interceptor_activator.c +++ b/bundles/remote_services/examples/interceptors/src/rs_interceptor_activator.c @@ -55,8 +55,8 @@ static int interceptor_start(struct interceptorActivator *act, celix_bundle_cont celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; opts.svc = interceptorSvc; - opts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; - opts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + opts.serviceName = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME; + opts.serviceVersion = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_VERSION; opts.properties = props; act->interceptorSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts); @@ -79,8 +79,8 @@ static int interceptor_start(struct interceptorActivator *act, celix_bundle_cont celix_service_registration_options_t secondOpts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; secondOpts.svc = secondInterceptorSvc; - secondOpts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; - secondOpts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + secondOpts.serviceName = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME; + secondOpts.serviceVersion = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_VERSION; secondOpts.properties = secondProps; act->secondInterceptorSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &secondOpts); diff --git a/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c b/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c index 59522e30d..461bccf30 100644 --- a/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c +++ b/bundles/remote_services/examples/remote_example_service/src/remote_example_activator.c @@ -45,7 +45,7 @@ celix_status_t remoteExampleBndStart(struct activator *act, celix_bundle_context act->service.createAdditionalRemoteService = (void*)remoteExample_createAdditionalRemoteService; celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, REMOTE_EXAMPLE_NAME); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, REMOTE_EXAMPLE_NAME); act->svcId = celix_bundleContext_registerService(ctx, &act->service, REMOTE_EXAMPLE_NAME, properties); } return CELIX_SUCCESS; diff --git a/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c b/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c index f462d3427..3a95ff610 100644 --- a/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c +++ b/bundles/remote_services/examples/remote_example_service/src/remote_example_impl.c @@ -160,7 +160,7 @@ int remoteExample_createAdditionalRemoteService(remote_example_impl_t* impl) { fprintf(stdout, "additional remote already created\n"); } else { celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, REMOTE_EXAMPLE_NAME); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, REMOTE_EXAMPLE_NAME); long newSvcId = celix_bundleContext_registerService(impl->ctx, &impl->additionalSvc, REMOTE_EXAMPLE_NAME, properties); pthread_mutex_lock(&impl->mutex); prevSvcId = impl->additionalSvcId; diff --git a/bundles/remote_services/remote_service_admin_dfi/CMakeLists.txt b/bundles/remote_services/remote_service_admin_dfi/CMakeLists.txt index 27dee5838..c2d5f0965 100644 --- a/bundles/remote_services/remote_service_admin_dfi/CMakeLists.txt +++ b/bundles/remote_services/remote_service_admin_dfi/CMakeLists.txt @@ -27,6 +27,7 @@ if (RSA_REMOTE_SERVICE_ADMIN_DFI) SYMBOLIC_NAME "apache_celix_remote_service_admin_dfi" NAME "Apache Celix Remote Service Admin Dynamic Function Interface (DFI)" GROUP "Celix/RSA" + FILENAME celix_rsa_dfi SOURCES src/remote_service_admin_dfi.c src/remote_service_admin_activator.c diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt b/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt index b291dea8e..9d023c128 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/CMakeLists.txt @@ -70,6 +70,10 @@ configure_file(server.properties.in server.properties) #add exception service interface descriptor configure_file(exception_test_service.descriptor exception_test_service.descriptor) +target_compile_options(test_rsa_dfi PRIVATE -DRSA_DFI_BUNDLE_FILE="${rsa_bundle_file}") +target_compile_options(test_rsa_dfi PRIVATE -DCALC_BUNDLE_FILE="${calc_bundle_file}") +target_compile_options(test_rsa_dfi PRIVATE -DTST_BUNDLE_FILE="${tst_bundle_file}") + add_celix_bundle_dependencies(test_rsa_dfi rsa_dfi #note depend on the target creating the bundle zip not the lib target calculator diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc index 919075ac4..7fb210585 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc @@ -36,6 +36,7 @@ extern "C" { #include "framework.h" #include "remote_service_admin.h" #include "remote_interceptor.h" +#include "calculator_service.h" #define RSA_DIF_EXCEPTION_TEST_SERVICE "exception_test_service" typedef struct rsa_dfi_exception_test_service { @@ -88,8 +89,8 @@ typedef struct rsa_dfi_exception_test_service { static void registerExceptionTestServer(void) { celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, RSA_DIF_EXCEPTION_TEST_SERVICE); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, "org.amdatu.remote.admin.http"); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, RSA_DIF_EXCEPTION_TEST_SERVICE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, "org.amdatu.remote.admin.http"); exceptionTestService = (rsa_dfi_exception_test_service_t *)calloc(1,sizeof(*exceptionTestService)); exceptionTestService->handle = NULL; exceptionTestService->func1 = rsaDfi_excepTestFunc1; @@ -145,8 +146,8 @@ typedef struct rsa_dfi_exception_test_service { celix_properties_setLong(svcInterceptorProps, CELIX_FRAMEWORK_SERVICE_RANKING, 10); celix_service_registration_options_t svcInterceptorOpts{}; svcInterceptorOpts.svc = serverSvcInterceptor; - svcInterceptorOpts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; - svcInterceptorOpts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + svcInterceptorOpts.serviceName = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME; + svcInterceptorOpts.serviceVersion = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_VERSION; svcInterceptorOpts.properties = svcInterceptorProps; serverSvcInterceptorSvcId = celix_bundleContext_registerServiceWithOptions(serverContext, &svcInterceptorOpts); @@ -161,8 +162,8 @@ typedef struct rsa_dfi_exception_test_service { celix_properties_setLong(clientInterceptorProps, CELIX_FRAMEWORK_SERVICE_RANKING, 10); celix_service_registration_options_t clientInterceptorOpts{}; clientInterceptorOpts.svc = clientSvcInterceptor; - clientInterceptorOpts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; - clientInterceptorOpts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + clientInterceptorOpts.serviceName = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME; + clientInterceptorOpts.serviceVersion = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_VERSION; clientInterceptorOpts.properties = clientInterceptorProps; clientSvcInterceptorSvcId = celix_bundleContext_registerServiceWithOptions(clientContext, &clientInterceptorOpts); } @@ -402,3 +403,138 @@ TEST_F(RsaDfiClientServerInterceptorTests,TestInterceptorPreProxyCallReturnFalse TEST_F(RsaDfiClientServerExceptionTests,TestExceptionService) { testExceptionService(); } + + +class RsaDfiDynamicIpServerTestSuite : public ::testing::Test { +public: + RsaDfiDynamicIpServerTestSuite() { + { + auto* props = celix_properties_create(); + celix_properties_setBool(props, "CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT", true); + celix_properties_setBool(props, CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, true); + celix_properties_set(props, CELIX_FRAMEWORK_CACHE_DIR, ".rsa_dfi_server_cache"); + serverFw = std::shared_ptr{celix_frameworkFactory_createFramework(props), [](auto f) {celix_frameworkFactory_destroyFramework(f);}}; + serverCtx = std::shared_ptr{celix_framework_getFrameworkContext(serverFw.get()), [](auto*){/*nop*/}}; + + auto bundleId = celix_bundleContext_installBundle(serverCtx.get(), RSA_DFI_BUNDLE_FILE, true); + EXPECT_TRUE(bundleId >= 0); + + bundleId = celix_bundleContext_installBundle(serverCtx.get(), CALC_BUNDLE_FILE, true); + EXPECT_TRUE(bundleId >= 0); + + celix_bundleContext_waitForEvents(serverCtx.get()); + } + + { + auto* props = celix_properties_create(); + celix_properties_setBool(props, CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, true); + celix_properties_set(props, CELIX_FRAMEWORK_CACHE_DIR, ".rsa_dfi_client_cache"); + clientFw = std::shared_ptr{celix_frameworkFactory_createFramework(props), [](auto f) {celix_frameworkFactory_destroyFramework(f);}}; + clientCtx = std::shared_ptr{celix_framework_getFrameworkContext(clientFw.get()), [](auto*){/*nop*/}}; + + auto bundleId = celix_bundleContext_installBundle(clientCtx.get(), RSA_DFI_BUNDLE_FILE, true); + EXPECT_TRUE(bundleId >= 0); + + bundleId = celix_bundleContext_installBundle(clientCtx.get(), TST_BUNDLE_FILE, true); + EXPECT_TRUE(bundleId >= 0); + + celix_bundleContext_waitForEvents(clientCtx.get()); + } + } + ~RsaDfiDynamicIpServerTestSuite() override = default; + + void TestRemoteCalculator(void (*testBody)(tst_service_t* testSvc), const char* serverIp = "127.0.0.1") { + remote_service_admin_service_t* serverRsaSvc{nullptr}; + remote_service_admin_service_t* clientRsaSvc{nullptr}; + serverRsaTrkId = celix_bundleContext_trackService(serverCtx.get(), CELIX_RSA_REMOTE_SERVICE_ADMIN, + &serverRsaSvc, [](void* handle, void* svc){ + auto rsaSvc = static_cast(handle); + *rsaSvc = static_cast(svc); + }); + EXPECT_GE(serverRsaTrkId, 0); + clientRsaTrkId = celix_bundleContext_trackService(clientCtx.get(), CELIX_RSA_REMOTE_SERVICE_ADMIN, + &clientRsaSvc, [](void* handle, void* svc){ + auto rsaSvc = static_cast(handle); + *rsaSvc = static_cast(svc); + }); + EXPECT_GE(clientRsaTrkId, 0); + long calcId = celix_bundleContext_findService(serverCtx.get(), CALCULATOR_SERVICE); + ASSERT_TRUE(calcId >= 0L); + ASSERT_TRUE(clientRsaSvc != nullptr); + ASSERT_TRUE(serverRsaSvc != nullptr); + + char calcIdStr[32] = {0}; + snprintf(calcIdStr, 32, "%li", calcId); + celix_array_list_t *svcRegistrations = NULL; + auto status = serverRsaSvc->exportService(serverRsaSvc->admin, calcIdStr, NULL, &svcRegistrations); + ASSERT_EQ(CELIX_SUCCESS, status); + ASSERT_EQ(1, celix_arrayList_size(svcRegistrations)); + export_registration_t *exportedReg = static_cast(celix_arrayList_get(svcRegistrations, 0)); + export_reference_t *exportedRef = nullptr; + status = serverRsaSvc->exportRegistration_getExportReference(exportedReg, &exportedRef); + ASSERT_EQ(CELIX_SUCCESS, status); + endpoint_description_t *exportedEndpoint = nullptr; + status = serverRsaSvc->exportReference_getExportedEndpoint(exportedRef, &exportedEndpoint); + ASSERT_EQ(CELIX_SUCCESS, status); + free(exportedRef); + celix_arrayList_destroy(svcRegistrations); + + celix_properties_t *importProps = celix_properties_copy(exportedEndpoint->properties); + ASSERT_TRUE(importProps != nullptr); + celix_properties_set(importProps, CELIX_RSA_IP_ADDRESSES, serverIp); + endpoint_description_t *importedEndpoint = nullptr; + status = endpointDescription_create(importProps, &importedEndpoint); + ASSERT_EQ(CELIX_SUCCESS, status); + + import_registration_t* reg = nullptr; + status = clientRsaSvc->importService(clientRsaSvc->admin, importedEndpoint, ®); + ASSERT_EQ(CELIX_SUCCESS, status); + celix_bundleContext_waitForEvents(clientCtx.get()); + + celix_service_use_options_t opts{}; + opts.filter.serviceName = TST_SERVICE_NAME; + opts.callbackHandle = (void*)testBody; + opts.use = [](void *handle , void *svc) { + auto* testBody = (void (*)(tst_service_t*))handle; + testBody(static_cast(svc)); + }; + opts.waitTimeoutInSeconds = 5; + auto called = celix_bundleContext_useServiceWithOptions(clientCtx.get(), &opts); + ASSERT_TRUE(called); + + status = clientRsaSvc->importRegistration_close(clientRsaSvc->admin, reg); + ASSERT_EQ(CELIX_SUCCESS, status); + endpointDescription_destroy(importedEndpoint); + + status = serverRsaSvc->exportRegistration_close(serverRsaSvc->admin, exportedReg); + ASSERT_EQ(CELIX_SUCCESS, status); + + celix_bundleContext_stopTracker(clientCtx.get(), clientRsaTrkId); + celix_bundleContext_stopTracker(serverCtx.get(), serverRsaTrkId); + } + + std::shared_ptr serverFw{}; + std::shared_ptr serverCtx{}; + long serverRsaTrkId{-1}; + std::shared_ptr clientFw{}; + std::shared_ptr clientCtx{}; + long clientRsaTrkId{-1}; +}; + +TEST_F(RsaDfiDynamicIpServerTestSuite, RemoteCalculatorTest) { + TestRemoteCalculator([](tst_service_t* testSvc) { + auto ok = testSvc->testCalculator(testSvc->handle); + ASSERT_TRUE(ok); + }); +} + +TEST_F(RsaDfiDynamicIpServerTestSuite, CallingMultiTimesRemoteCalculatorTest) { + TestRemoteCalculator([](tst_service_t* testSvc) { + auto ok = testSvc->testCalculator(testSvc->handle); + ASSERT_TRUE(ok); + + ok = testSvc->testCalculator(testSvc->handle); + ASSERT_TRUE(ok); + }); +} + diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc index c0ebdd601..3195b4630 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc @@ -74,7 +74,7 @@ extern "C" { static void testServices(void) { celix_service_use_options_t opts{}; - opts.filter.serviceName = OSGI_RSA_REMOTE_SERVICE_ADMIN; + opts.filter.serviceName = CELIX_RSA_REMOTE_SERVICE_ADMIN; opts.use = testServicesCallback; opts.waitTimeoutInSeconds = 0.25; bool called = celix_bundleContext_useServiceWithOptions(context, &opts); @@ -101,7 +101,7 @@ extern "C" { static void testExportService(void) { celix_service_use_options_t opts{}; - opts.filter.serviceName = OSGI_RSA_REMOTE_SERVICE_ADMIN; + opts.filter.serviceName = CELIX_RSA_REMOTE_SERVICE_ADMIN; opts.use = testExportServiceCallback; opts.waitTimeoutInSeconds = 0.25; bool called = celix_bundleContext_useServiceWithOptions(context, &opts); @@ -114,10 +114,10 @@ extern "C" { if (init) { auto *rsa = static_cast(svc); celix_properties_t *props = celix_properties_create(); - celix_properties_set(props, OSGI_RSA_ENDPOINT_SERVICE_ID, "42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); - celix_properties_set(props, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); + celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); + celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.Example"); int rc = endpointDescription_create(props, &endpoint); @@ -137,7 +137,7 @@ extern "C" { static void testImportService(void) { celix_service_use_options_t opts{}; - opts.filter.serviceName = OSGI_RSA_REMOTE_SERVICE_ADMIN; + opts.filter.serviceName = CELIX_RSA_REMOTE_SERVICE_ADMIN; opts.use = testImportServiceCallback; opts.waitTimeoutInSeconds = 0.25; diff --git a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c index 54893b9d2..425800611 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c +++ b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c @@ -100,7 +100,7 @@ celix_status_t exportRegistration_create(celix_log_helper_t *helper, service_ref } const char *exports = NULL; - CELIX_DO_IF(status, serviceReference_getProperty(reference, (char *) OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &exports)); + CELIX_DO_IF(status, serviceReference_getProperty(reference, (char *) CELIX_RSA_SERVICE_EXPORTED_INTERFACES, &exports)); celix_bundle_t *bundle = NULL; CELIX_DO_IF(status, serviceReference_getBundle(reference, &bundle)); diff --git a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c index a0c55724a..7a5af4fc9 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c +++ b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c @@ -322,16 +322,15 @@ static void importRegistration_proxyFunc(void *userData, void *args[], void *ret if (status == CELIX_SUCCESS) { char *reply = NULL; - int rc = 0; //printf("sending request\n"); celix_properties_t *metadata = NULL; bool cont = remoteInterceptorHandler_invokePreProxyCall(import->interceptorsHandler, import->endpoint->properties, dynFunction_getName(entry->dynFunc), &metadata); if (cont) { - status = import->send(import->sendHandle, import->endpoint, invokeRequest, metadata, &reply, &rc); + status = import->send(import->sendHandle, import->endpoint, invokeRequest, metadata, &reply); //printf("request sended. got reply '%s' with status %i\n", reply, rc); - if (status == CELIX_SUCCESS && rc == CELIX_SUCCESS && dynFunction_hasReturn(entry->dynFunc)) { + if (status == CELIX_SUCCESS && dynFunction_hasReturn(entry->dynFunc)) { //fjprintf("Handling reply '%s'\n", reply); int rsErrno = CELIX_SUCCESS; int retVal = jsonRpc_handleReply(entry->dynFunc, reply, args, &rsErrno); @@ -341,8 +340,6 @@ static void importRegistration_proxyFunc(void *userData, void *args[], void *ret //return the invocation error of remote service function *(int *) returnVal = rsErrno; } - } else if (rc != CELIX_SUCCESS) { - *(int *) returnVal = rc; } remoteInterceptorHandler_invokePostProxyCall(import->interceptorsHandler, import->endpoint->properties, @@ -361,7 +358,7 @@ static void importRegistration_proxyFunc(void *userData, void *args[], void *ret const char *url = importRegistration_getUrl(import); const char *svcName = importRegistration_getServiceName(import); fprintf(import->logFile, "REMOTE CALL NR %i\n\turl=%s\n\tservice=%s\n\tpayload=%s\n\treturn_code=%i\n\treply=%s\n", - callCount, url, svcName, invokeRequest, rc, reply); + callCount, url, svcName, invokeRequest, status, reply == NULL ? "null" : reply); fflush(import->logFile); callCount += 1; } @@ -399,6 +396,10 @@ celix_status_t importRegistration_getImportReference(import_registration_t *regi return status; } +endpoint_description_t* importRegistration_getEndpointDescription(import_registration_t *registration) { + return registration->endpoint; +} + celix_status_t importReference_getImportedEndpoint(import_reference_t *reference) { celix_status_t status = CELIX_SUCCESS; return status; diff --git a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h index 13353204f..26c7e52c9 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h +++ b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.h @@ -22,10 +22,11 @@ #include "import_registration.h" #include "dfi_utils.h" +#include "endpoint_description.h" #include -typedef celix_status_t (*send_func_type)(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply, int* replyStatus); +typedef celix_status_t (*send_func_type)(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply); celix_status_t importRegistration_create( celix_bundle_context_t *context, @@ -40,4 +41,6 @@ void importRegistration_destroy(import_registration_t *import); celix_status_t importRegistration_start(import_registration_t *import); +endpoint_description_t* importRegistration_getEndpointDescription(import_registration_t *registration); + #endif //CELIX_IMPORT_REGISTRATION_DFI_H diff --git a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c index 0b470da72..75b711bca 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c +++ b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_activator.c @@ -22,6 +22,8 @@ #include "remote_service_admin_dfi.h" #include "export_registration_dfi.h" #include "import_registration_dfi.h" +#include "remote_service_admin_dfi_constants.h" +#include "remote_constants.h" typedef struct celix_remote_service_admin_activator { remote_service_admin_t *admin; @@ -32,7 +34,21 @@ typedef struct celix_remote_service_admin_activator { static celix_status_t celix_rsa_start(celix_remote_service_admin_activator_t* activator, celix_bundle_context_t* ctx) { celix_status_t status = CELIX_SUCCESS; activator->svcIdRsa = -1; - + celix_autoptr(celix_properties_t) props = celix_properties_create(); + if (props == NULL) { + return CELIX_ENOMEM; + } + status = celix_properties_set(props, CELIX_RSA_REMOTE_CONFIGS_SUPPORTED, RSA_DFI_CONFIGURATION_TYPE); + if (status != CELIX_SUCCESS) { + return status; + } + bool dynamicIpSupport = celix_bundleContext_getPropertyAsBool(ctx, CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT, CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT_DEFAULT); + if (dynamicIpSupport) { + status = celix_properties_setBool(props, CELIX_RSA_DYNAMIC_IP_SUPPORT, true); + if (status != CELIX_SUCCESS) { + return status; + } + } status = remoteServiceAdmin_create(ctx, &activator->admin); if (status == CELIX_SUCCESS) { activator->adminService.admin = activator->admin; @@ -56,7 +72,8 @@ static celix_status_t celix_rsa_start(celix_remote_service_admin_activator_t* ac activator->adminService.importRegistration_getException = importRegistration_getException; activator->adminService.importRegistration_getImportReference = importRegistration_getImportReference; - activator->svcIdRsa = celix_bundleContext_registerService(ctx, &activator->adminService, OSGI_RSA_REMOTE_SERVICE_ADMIN, NULL); + activator->svcIdRsa = celix_bundleContext_registerService(ctx, &activator->adminService, CELIX_RSA_REMOTE_SERVICE_ADMIN, + celix_steal_ptr(props)); } return status; diff --git a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c index d0ea98911..aa4224758 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c +++ b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c @@ -34,6 +34,7 @@ #include "json_serializer.h" #include "utils.h" #include "celix_utils.h" +#include "celix_ref.h" #include "import_registration_dfi.h" #include "export_registration_dfi.h" @@ -46,6 +47,8 @@ #include "remote_service_admin_dfi_constants.h" #include "celix_bundle_context.h" +#include "celix_string_hash_map.h" +#include "celix_stdlib_cleanup.h" // defines how often the webserver is restarted (with an increased port number) #define MAX_NUMBER_OF_RESTARTS 5 @@ -71,6 +74,11 @@ #define CELIX_RSA_USE_STOP_EXPORT_THREAD true +typedef struct celix_imported_endpoint_url_ref { + struct celix_ref ref;//It must be first + char url[0]; +}celix_imported_endpoint_url_ref_t; + struct remote_service_admin { celix_bundle_context_t *context; celix_log_helper_t *loghelper; @@ -87,10 +95,12 @@ struct remote_service_admin { celix_thread_mutex_t importedServicesLock; celix_array_list_t* importedServices; + celix_string_hash_map_t* importedEndpointUrls;//key: endpointId, value: celix_imported_endpoint_url_ref_t* char *port; char *ip; char *discoveryInterface; + bool dynamicIpSupport; struct mg_context *ctx; @@ -115,8 +125,8 @@ struct celix_get_data_reply { size_t size; }; -#define OSGI_RSA_REMOTE_PROXY_FACTORY "remote_proxy_factory" -#define OSGI_RSA_REMOTE_PROXY_TIMEOUT "remote_proxy_timeout" +#define CELIX_RSA_REMOTE_PROXY_FACTORY "remote_proxy_factory" +#define CELIX_RSA_REMOTE_PROXY_TIMEOUT "remote_proxy_timeout" static const char *data_response_headers = "HTTP/1.1 200 OK\r\n" @@ -131,7 +141,7 @@ static const unsigned int DEFAULT_TIMEOUT = 0; static int remoteServiceAdmin_callback(struct mg_connection *conn); static celix_status_t remoteServiceAdmin_createEndpointDescription(remote_service_admin_t *admin, service_reference_pt reference, celix_properties_t *props, char *interface, endpoint_description_t **description); -static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply, int* replyStatus); +static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply); static celix_status_t remoteServiceAdmin_getIpAddress(char* interface, char** ip); static char* remoteServiceAdmin_getIFNameForIP(const char *ip); static size_t remoteServiceAdmin_readCallback(void *ptr, size_t size, size_t nmemb, void *userp); @@ -195,6 +205,8 @@ celix_status_t remoteServiceAdmin_create(celix_bundle_context_t *context, remote celixThreadRwlock_create(&(*admin)->exportedServicesLock, NULL); celixThreadMutex_create(&(*admin)->importedServicesLock, NULL); + (*admin)->importedEndpointUrls = celix_stringHashMap_create();//Ignore ENOMEM for now and deal with it on other PRs in the future + (*admin)->loghelper = celix_logHelper_create(context, "celix_rsa_admin"); long port = celix_bundleContext_getPropertyAsLong(context, RSA_PORT_KEY, RSA_PORT_DEFAULT); @@ -202,30 +214,17 @@ celix_status_t remoteServiceAdmin_create(celix_bundle_context_t *context, remote const char *interface = celix_bundleContext_getProperty(context, RSA_INTERFACE_KEY, NULL); (*admin)->curlShareEnabled = celix_bundleContext_getPropertyAsBool(context, RSA_DFI_USE_CURL_SHARE_HANDLE, RSA_DFI_USE_CURL_SHARE_HANDLE_DEFAULT); - const char *networkInterfaces = celix_bundleContext_getProperty(context, CELIX_RSA_NETWORK_INTERFACES, NULL); - char *interfacesCopy = NULL; - if (networkInterfaces != NULL) { - interfacesCopy = celix_utils_strdup(networkInterfaces); - const char delimiter[2] = ","; - char *savePtr; - //TODO Supports multiple network interfaces - interface = strtok_r(interfacesCopy, delimiter, &savePtr); - } + (*admin)->dynamicIpSupport = celix_bundleContext_getPropertyAsBool(context, CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT, CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT_DEFAULT); - char *discoveryInterface = NULL; char *detectedIp = NULL; if ((interface != NULL) && (remoteServiceAdmin_getIpAddress((char*)interface, &detectedIp) != CELIX_SUCCESS)) { celix_logHelper_log((*admin)->loghelper, CELIX_LOG_LEVEL_WARNING, "RSA: Could not retrieve IP address for interface %s", interface); } if (detectedIp != NULL) { ip = detectedIp; - discoveryInterface = celix_utils_strdup(interface); + (*admin)->discoveryInterface = celix_utils_strdup(interface); } else { - discoveryInterface = remoteServiceAdmin_getIFNameForIP(ip); - } - - if (interfacesCopy != NULL) { - free(interfacesCopy); + (*admin)->discoveryInterface = remoteServiceAdmin_getIFNameForIP(ip); } if (ip != NULL) { @@ -275,7 +274,7 @@ celix_status_t remoteServiceAdmin_create(celix_bundle_context_t *context, remote bool bindToAllInterfaces = celix_bundleContext_getPropertyAsBool(context, CELIX_RSA_BIND_ON_ALL_INTERFACES, CELIX_RSA_BIND_ON_ALL_INTERFACES_DEFAULT); do { char *listeningPorts = NULL; - if (bindToAllInterfaces) { + if (bindToAllInterfaces || (*admin)->dynamicIpSupport) { asprintf(&listeningPorts,"0.0.0.0:%s", newPort); } else { asprintf(&listeningPorts,"%s:%s", (*admin)->ip, newPort); @@ -297,13 +296,6 @@ celix_status_t remoteServiceAdmin_create(celix_bundle_context_t *context, remote free(listeningPorts); } while (((*admin)->ctx == NULL) && (port_counter < MAX_NUMBER_OF_RESTARTS)); - - if (bindToAllInterfaces) { - free(discoveryInterface); - (*admin)->discoveryInterface = celix_utils_strdup("all");//announce service to all network interface - } else { - (*admin)->discoveryInterface = discoveryInterface; - } } bool logCalls = celix_bundleContext_getPropertyAsBool(context, RSA_LOG_CALLS_KEY, RSA_LOG_CALLS_DEFAULT); @@ -338,6 +330,13 @@ celix_status_t remoteServiceAdmin_destroy(remote_service_admin_t **admin) { pthread_mutex_destroy(&(*admin)->curlMutexConnect); pthread_mutex_destroy(&(*admin)->curlMutexCookie); pthread_mutex_destroy(&(*admin)->curlMutexDns); + CELIX_STRING_HASH_MAP_ITERATE((*admin)->importedEndpointUrls, iter) { + celix_imported_endpoint_url_ref_t* urlRef = iter.value.ptrValue; + celix_ref_put(&urlRef->ref, (void*)free); + } + celix_stringHashMap_destroy((*admin)->importedEndpointUrls); + celixThreadRwlock_destroy(&(*admin)->exportedServicesLock); + celixThreadMutex_destroy(&(*admin)->importedServicesLock); free(*admin); *admin = NULL; @@ -581,7 +580,7 @@ celix_status_t remoteServiceAdmin_exportService(remote_service_admin_t *admin, c celix_status_t status = CELIX_SUCCESS; bool export = false; - const char *exportConfigs = celix_properties_get(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, RSA_DFI_CONFIGURATION_TYPE); + const char *exportConfigs = celix_properties_get(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, RSA_DFI_CONFIGURATION_TYPE); if (exportConfigs != NULL) { // See if the EXPORT_CONFIGS matches this RSA. If so, try to export. @@ -637,7 +636,7 @@ celix_status_t remoteServiceAdmin_exportService(remote_service_admin_t *admin, c const char *exports = NULL; const char *provided = NULL; if (status == CELIX_SUCCESS) { - serviceReference_getProperty(reference, (char *) OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &exports); + serviceReference_getProperty(reference, (char *) CELIX_RSA_SERVICE_EXPORTED_INTERFACES, &exports); serviceReference_getProperty(reference, (char *) CELIX_FRAMEWORK_SERVICE_NAME, &provided); if (exports == NULL || provided == NULL || strcmp(exports, provided) != 0) { @@ -738,8 +737,8 @@ static celix_status_t remoteServiceAdmin_createEndpointDescription(remote_servic const char *value = NULL; if (serviceReference_getProperty(reference, key, &value) == CELIX_SUCCESS - && strcmp(key, (char*) OSGI_RSA_SERVICE_EXPORTED_INTERFACES) != 0 - && strcmp(key, (char*) OSGI_RSA_SERVICE_EXPORTED_CONFIGS) != 0 + && strcmp(key, (char*) CELIX_RSA_SERVICE_EXPORTED_INTERFACES) != 0 + && strcmp(key, (char*) CELIX_RSA_SERVICE_EXPORTED_CONFIGS) != 0 && strcmp(key, (char*) CELIX_FRAMEWORK_SERVICE_NAME) != 0) { celix_properties_set(endpointProperties, key, value); } @@ -760,15 +759,19 @@ static celix_status_t remoteServiceAdmin_createEndpointDescription(remote_servic uuid_unparse_lower(endpoint_uid, endpoint_uuid); bundleContext_getProperty(admin->context, CELIX_FRAMEWORK_UUID, &uuid); - celix_properties_set(endpointProperties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + celix_properties_set(endpointProperties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); celix_properties_set(endpointProperties, CELIX_FRAMEWORK_SERVICE_NAME, interface); - celix_properties_set(endpointProperties, OSGI_RSA_ENDPOINT_SERVICE_ID, serviceId); - celix_properties_set(endpointProperties, OSGI_RSA_ENDPOINT_ID, endpoint_uuid); - celix_properties_set(endpointProperties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(endpointProperties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, (char*) RSA_DFI_CONFIGURATION_TYPE); + celix_properties_set(endpointProperties, CELIX_RSA_ENDPOINT_SERVICE_ID, serviceId); + celix_properties_set(endpointProperties, CELIX_RSA_ENDPOINT_ID, endpoint_uuid); + celix_properties_set(endpointProperties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(endpointProperties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, RSA_DFI_CONFIGURATION_TYPE); celix_properties_set(endpointProperties, RSA_DFI_ENDPOINT_URL, url); if (admin->discoveryInterface != NULL) { - celix_properties_set(endpointProperties, CELIX_RSA_NETWORK_INTERFACES, admin->discoveryInterface); + celix_properties_set(endpointProperties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, admin->discoveryInterface); + } + if (admin->dynamicIpSupport) { + celix_properties_set(endpointProperties, RSA_DFI_ENDPOINT_URL, buf); + celix_properties_set(endpointProperties, CELIX_RSA_PORT, admin->port); } if (props != NULL) { @@ -781,9 +784,9 @@ static celix_status_t remoteServiceAdmin_createEndpointDescription(remote_servic if (!*endpoint) { status = CELIX_ENOMEM; } else { - (*endpoint)->id = (char*) celix_properties_get(endpointProperties, (char*) OSGI_RSA_ENDPOINT_ID, NULL); + (*endpoint)->id = (char*) celix_properties_get(endpointProperties, (char*) CELIX_RSA_ENDPOINT_ID, NULL); (*endpoint)->serviceId = serviceReference_getServiceId(reference); - (*endpoint)->frameworkUUID = (char*) celix_properties_get(endpointProperties, (char*) OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); + (*endpoint)->frameworkUUID = (char*) celix_properties_get(endpointProperties, (char*) CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); (*endpoint)->serviceName = strndup(interface, 1024*10); (*endpoint)->properties = endpointProperties; } @@ -874,7 +877,7 @@ celix_status_t remoteServiceAdmin_importService(remote_service_admin_t *admin, e celix_status_t status = CELIX_SUCCESS; bool importService = false; - const char *importConfigs = celix_properties_get(endpointDescription->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, NULL); + const char *importConfigs = celix_properties_get(endpointDescription->properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, NULL); if (importConfigs != NULL) { // Check whether this RSA must be imported char *ecCopy = strndup(importConfigs, strlen(importConfigs)); @@ -894,7 +897,7 @@ celix_status_t remoteServiceAdmin_importService(remote_service_admin_t *admin, e free(ecCopy); } else { celix_logHelper_log(admin->loghelper, CELIX_LOG_LEVEL_WARNING, "Mandatory %s element missing from endpoint description", - OSGI_RSA_SERVICE_IMPORTED_CONFIGS); + CELIX_RSA_SERVICE_IMPORTED_CONFIGS); } if (importService) { @@ -930,6 +933,16 @@ celix_status_t remoteServiceAdmin_importService(remote_service_admin_t *admin, e return status; } +static void remoteServiceAdmin_removeDynamicIpUrlOfImportedRegistration(remote_service_admin_t* admin, import_registration_t *registration) { + endpoint_description_t* endpoint = importRegistration_getEndpointDescription(registration); + assert(endpoint != NULL); + celix_imported_endpoint_url_ref_t* urlRef = celix_stringHashMap_get(admin->importedEndpointUrls, endpoint->id); + if (urlRef != NULL) { + celix_ref_put(&urlRef->ref, (void*)free); + celix_stringHashMap_remove(admin->importedEndpointUrls, endpoint->id); + } + return; +} celix_status_t remoteServiceAdmin_removeImportedService(remote_service_admin_t *admin, import_registration_t *registration) { celix_status_t status = CELIX_SUCCESS; @@ -943,6 +956,7 @@ celix_status_t remoteServiceAdmin_removeImportedService(remote_service_admin_t * current = celix_arrayList_get(admin->importedServices, i); if (current == registration) { celix_arrayList_removeAt(admin->importedServices, i); + remoteServiceAdmin_removeDynamicIpUrlOfImportedRegistration(admin, registration); importRegistration_destroy(current); break; } @@ -952,7 +966,90 @@ celix_status_t remoteServiceAdmin_removeImportedService(remote_service_admin_t * return status; } -static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply, int* replyStatus) { +static bool shouldTryUseOtherDynamicIp(celix_status_t useUrlStatus) { + switch (useUrlStatus) { + case CELIX_SUCCESS: + case CELIX_ERROR_MAKE(CELIX_FACILITY_CURL,CURLE_OUT_OF_MEMORY): + return false; + default: + return true; + } +} + +static celix_status_t remoteServiceAdmin_useDynamicIpUrlsForEndpoint(remote_service_admin_t* rsa, endpoint_description_t* endpointDescription, +celix_status_t (*useUrl)(void* handle, const char* url), void* handle) { + celix_status_t status = CELIX_ERROR_MAKE(CELIX_FACILITY_CURL,CURLE_COULDNT_CONNECT); + celixThreadMutex_lock(&rsa->importedServicesLock); + celix_imported_endpoint_url_ref_t* urlRef = celix_stringHashMap_get(rsa->importedEndpointUrls, endpointDescription->id); + if (urlRef != NULL) { + celix_ref_get(&urlRef->ref); + celixThreadMutex_unlock(&rsa->importedServicesLock); + status = useUrl(handle, urlRef->url); + celix_ref_put(&urlRef->ref, (void*)free); + } else { + celixThreadMutex_unlock(&rsa->importedServicesLock); + } + if (!shouldTryUseOtherDynamicIp(status)) { + return status; + } + + const char *serviceUrl = celix_properties_get(endpointDescription->properties, (char*) RSA_DFI_ENDPOINT_URL, ""); + const char *ipaddresses = celix_properties_get(endpointDescription->properties, CELIX_RSA_IP_ADDRESSES, NULL); + int port = (int)celix_properties_getAsLong(endpointDescription->properties, CELIX_RSA_PORT, RSA_PORT_DEFAULT); + celix_autofree char *ipStrListCopy = NULL; + ipStrListCopy = celix_utils_strdup(ipaddresses); + if (ipStrListCopy == NULL) { + celix_logHelper_error(rsa->loghelper, "Error duplicating ip addresses"); + return CELIX_ENOMEM; + } + char url[256] = {0}; + char *savePtr = NULL; + char *token = strtok_r(ipStrListCopy, ",", &savePtr); + while (token != NULL) { + char *ip = celix_utils_trimInPlace(token); + struct sockaddr_in sa; + if (inet_pton(AF_INET, ip, &(sa.sin_addr)) == 1) { + snprintf(url, sizeof(url), "http://%s:%d%s", ip, port, serviceUrl); + } else { + snprintf(url, sizeof(url), "http://[%s]:%d%s", ip, port, serviceUrl); + } + status = useUrl(handle, url); + if (!shouldTryUseOtherDynamicIp(status)) { + celix_imported_endpoint_url_ref_t* urlRefNew = calloc(1, sizeof(*urlRefNew) + strlen(url) + 1); + if (urlRefNew == NULL) { + celix_logHelper_error(rsa->loghelper, "Error allocating memory for imported endpoint url reference"); + return CELIX_ENOMEM; + } + celix_ref_init(&urlRefNew->ref); + strcpy(urlRefNew->url, url); + + celixThreadMutex_lock(&rsa->importedServicesLock); + if (celix_stringHashMap_put(rsa->importedEndpointUrls, endpointDescription->id, urlRefNew) != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(rsa->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(rsa->loghelper, "Error storing imported endpoint url reference for endpoint %s", endpointDescription->id); + celix_ref_put(&urlRefNew->ref, (void*)free); + }else if (urlRef != NULL) { + celix_ref_put(&urlRef->ref, (void*)free); + } + celixThreadMutex_unlock(&rsa->importedServicesLock); + break; + } + token = strtok_r(NULL, ",", &savePtr); + } + return status; +} + +static celix_status_t onUseUrlCallback(void* handle, const char* url) { + CURL *curl = handle; + curl_easy_setopt(curl, CURLOPT_URL, url); + CURLcode ret = curl_easy_perform(curl); + if (ret != CURLE_OK) { + return CELIX_ERROR_MAKE(CELIX_FACILITY_CURL, ret); + } + return CELIX_SUCCESS; +} + +static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description_t *endpointDescription, char *request, celix_properties_t *metadata, char **reply) { remote_service_admin_t * rsa = handle; struct celix_post_data post; post.readptr = request; @@ -973,10 +1070,10 @@ static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description const char *timeoutStr = NULL; // Check if the endpoint has a timeout, if so, use it. - timeoutStr = (char*) celix_properties_get(endpointDescription->properties, (char*) OSGI_RSA_REMOTE_PROXY_TIMEOUT, NULL); + timeoutStr = (char*) celix_properties_get(endpointDescription->properties, (char*) CELIX_RSA_REMOTE_PROXY_TIMEOUT, NULL); if (timeoutStr == NULL) { // If not, get the global variable and use that one. - bundleContext_getProperty(rsa->context, (char*) OSGI_RSA_REMOTE_PROXY_TIMEOUT, &timeoutStr); + bundleContext_getProperty(rsa->context, (char*) CELIX_RSA_REMOTE_PROXY_TIMEOUT, &timeoutStr); } // Update timeout if a property is used to set it. @@ -990,6 +1087,8 @@ static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description curl = curl_easy_init(); if(!curl) { + fclose(get.stream); + free(get.buf); status = CELIX_ILLEGAL_STATE; } else { struct curl_slist *metadataHeader = NULL; @@ -1006,7 +1105,6 @@ static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); - curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_POST, 1L); curl_easy_setopt(curl, CURLOPT_READFUNCTION, remoteServiceAdmin_readCallback); curl_easy_setopt(curl, CURLOPT_READDATA, &post); @@ -1016,12 +1114,24 @@ static celix_status_t remoteServiceAdmin_send(void *handle, endpoint_description if (rsa->curlShareEnabled) { curl_easy_setopt(curl, CURLOPT_SHARE, rsa->curlShare); } - res = curl_easy_perform(curl); + + const char *ipaddresses = celix_properties_get(endpointDescription->properties, CELIX_RSA_IP_ADDRESSES, NULL); + if (ipaddresses == NULL) { + curl_easy_setopt(curl, CURLOPT_URL, url); + res = curl_easy_perform(curl); + status = (res == CURLE_OK) ? CELIX_SUCCESS:CELIX_ERROR_MAKE(CELIX_FACILITY_CURL,res); + } else { + status = remoteServiceAdmin_useDynamicIpUrlsForEndpoint(rsa, endpointDescription, onUseUrlCallback, curl); + } fputc('\0', get.stream); fclose(get.stream); *reply = get.buf; - *replyStatus = (res == CURLE_OK) ? CELIX_SUCCESS:CELIX_ERROR_MAKE(CELIX_FACILITY_HTTP,res); + if (status == CELIX_SUCCESS) { + long httpCode = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); + status = (httpCode == 200/*HTTP OK*/) ? CELIX_SUCCESS : CELIX_ERROR_MAKE(CELIX_FACILITY_HTTP,httpCode); + } curl_easy_cleanup(curl); curl_slist_free_all(metadataHeader); diff --git a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi_constants.h b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi_constants.h index e10a6d662..1adcfaa57 100644 --- a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi_constants.h +++ b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi_constants.h @@ -67,5 +67,17 @@ */ #define CELIX_RSA_BIND_ON_ALL_INTERFACES_DEFAULT true +/** + * @brief Remote Service Admin DFI environment property, it indicates whether the RSA_DFI implementation supports dynamic IP address fill-in for service exports. + * Its type is boolean.If this property is not specified, it defaults to false. + * + */ +#define CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT "CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT" + +/** + * @brief Default value for the property CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT + */ +#define CELIX_RSA_DFI_DYNAMIC_IP_SUPPORT_DEFAULT false + #endif //CELIX_REMOTE_SERVICE_ADMIN_DFI_CONSTANTS_H diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/CMakeLists.txt b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/CMakeLists.txt index b7189afcd..48370496c 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/CMakeLists.txt +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/CMakeLists.txt @@ -41,6 +41,7 @@ add_celix_bundle(rsa_shm SYMBOLIC_NAME "apache_celix_remote_service_admin_shm_v2" NAME "Apache Celix Remote Service Admin SHM V2" GROUP "Celix/RSA" + FILENAME celix_rsa_shm SOURCES ${RSA_SHM_SRC} ) diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmActivatorUnitTestSuite.cc b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmActivatorUnitTestSuite.cc index ac2528376..d680b706b 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmActivatorUnitTestSuite.cc +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmActivatorUnitTestSuite.cc @@ -21,8 +21,9 @@ #include "remote_service_admin.h" #include "celix_api.h" #include "celix_log_helper_ei.h" -#include "malloc_ei.h" +#include "celix_properties_ei.h" #include "celix_bundle_context_ei.h" +#include "malloc_ei.h" #include class RsaShmActivatorUnitTestSuite : public ::testing::Test { @@ -41,6 +42,8 @@ class RsaShmActivatorUnitTestSuite : public ::testing::Test { celix_ei_expect_celix_logHelper_create(nullptr, 0, nullptr); celix_ei_expect_calloc(nullptr, 0, nullptr); celix_ei_expect_celix_bundleContext_registerServiceAsync(nullptr, 0, 0); + celix_ei_expect_celix_properties_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_set(nullptr, 0, 0); } @@ -55,7 +58,7 @@ TEST_F(RsaShmActivatorUnitTestSuite, RsaShmActivatorStart) { status = celix_bundleActivator_start(userData, ctx.get()); EXPECT_EQ(status, CELIX_SUCCESS); - bool found = celix_bundleContext_findService(ctx.get(), OSGI_RSA_REMOTE_SERVICE_ADMIN); + bool found = celix_bundleContext_findService(ctx.get(), CELIX_RSA_REMOTE_SERVICE_ADMIN); EXPECT_TRUE(found); status = celix_bundleActivator_stop(userData, ctx.get()); @@ -90,6 +93,30 @@ TEST_F(RsaShmActivatorUnitTestSuite, RsaShmActivatorStartWithCreatingRsaError) { EXPECT_EQ(status, CELIX_SUCCESS); } +TEST_F(RsaShmActivatorUnitTestSuite, RsaShmActivatorStartWithCreatingServicePropertiesError) { + void *userData = nullptr; + auto status = celix_bundleActivator_create(ctx.get(), &userData); + EXPECT_EQ(status, CELIX_SUCCESS); + celix_ei_expect_celix_properties_create((void*)&celix_bundleActivator_start, 1, nullptr); + status = celix_bundleActivator_start(userData, ctx.get()); + EXPECT_EQ(status, CELIX_ENOMEM); + + status = celix_bundleActivator_destroy(userData, ctx.get()); + EXPECT_EQ(status, CELIX_SUCCESS); +} + +TEST_F(RsaShmActivatorUnitTestSuite, RsaShmActivatorStartWithSettingServicePropertiesError) { + void *userData = nullptr; + auto status = celix_bundleActivator_create(ctx.get(), &userData); + EXPECT_EQ(status, CELIX_SUCCESS); + celix_ei_expect_celix_properties_set((void*)&celix_bundleActivator_start, 1, CELIX_ENOMEM); + status = celix_bundleActivator_start(userData, ctx.get()); + EXPECT_EQ(status, CELIX_ENOMEM); + + status = celix_bundleActivator_destroy(userData, ctx.get()); + EXPECT_EQ(status, CELIX_SUCCESS); +} + TEST_F(RsaShmActivatorUnitTestSuite, RsaShmActivatorStartWithRegisteringRsaServiceError) { void *userData = nullptr; auto status = celix_bundleActivator_create(ctx.get(), &userData); diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmExportRegistrationUnitTestSuite.cc b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmExportRegistrationUnitTestSuite.cc index a85691905..9c8c0d15b 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmExportRegistrationUnitTestSuite.cc +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmExportRegistrationUnitTestSuite.cc @@ -36,6 +36,8 @@ #include #include +#define RSA_RPC_TYPE_FOR_TEST "celix.remote.admin.rpc_type.test" + static celix_status_t expect_RpcFacCreateEndpoint_ret = CELIX_SUCCESS; static celix_status_t RpcFacCreateEndpoint(void *handle, const endpoint_description_t *endpoint, long *requestHandlerSvcId) { (void)endpoint; //unused @@ -54,8 +56,8 @@ static celix_status_t RpcFacCreateEndpoint(void *handle, const endpoint_descript }; celix_service_registration_options_t opts{}; opts.svc = &requestHandler; - opts.serviceName = RSA_REQUEST_HANDLER_SERVICE_NAME; - opts.serviceVersion = RSA_REQUEST_HANDLER_SERVICE_VERSION; + opts.serviceName = CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME; + opts.serviceVersion = CELIX_RSA_REQUEST_HANDLER_SERVICE_VERSION; auto svcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); EXPECT_GE(svcId, 0); *requestHandlerSvcId = svcId; @@ -89,9 +91,10 @@ class RsaShmExportRegUnitTestSuite : public ::testing::Test { return CELIX_SUCCESS; }; celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE"," RSA_RPC_TYPE_PREFIX"mock"); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, RSA_SHM_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); calcSvcId = celix_bundleContext_registerServiceAsync(ctx.get(), &calcService, RSA_SHM_CALCULATOR_SERVICE, properties); EXPECT_GE(calcSvcId, 0); @@ -103,9 +106,9 @@ class RsaShmExportRegUnitTestSuite : public ::testing::Test { rpcFactory.destroyEndpoint = RpcFacDestroyEndpoint; celix_properties_t *rpcFacProps = celix_properties_create(); - celix_properties_set(rpcFacProps, RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_PREFIX"mock"); - celix_properties_set(rpcFacProps, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_RPC_FACTORY_VERSION); - rpcFactorySvcId = celix_bundleContext_registerServiceAsync(ctx.get(), &rpcFactory, RSA_RPC_FACTORY_NAME, rpcFacProps); + celix_properties_set(rpcFacProps, CELIX_RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); + celix_properties_set(rpcFacProps, CELIX_FRAMEWORK_SERVICE_VERSION, CELIX_RSA_RPC_FACTORY_VERSION); + rpcFactorySvcId = celix_bundleContext_registerServiceAsync(ctx.get(), &rpcFactory, CELIX_RSA_RPC_FACTORY_NAME, rpcFacProps); EXPECT_GE(rpcFactorySvcId, 1); celix_bundleContext_waitForEvents(ctx.get()); @@ -128,11 +131,12 @@ class RsaShmExportRegUnitTestSuite : public ::testing::Test { celix_properties_t *properties = celix_properties_create(); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, RSA_SHM_CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE"," RSA_RPC_TYPE_PREFIX"mock"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "7f7efba5-500f-4ee9-b733-68de012091da"); - celix_properties_setLong(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, calcSvcId); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, "")); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, RSA_SHM_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "7f7efba5-500f-4ee9-b733-68de012091da"); + celix_properties_setLong(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, calcSvcId); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, "")); celix_properties_set(properties, RSA_SHM_SERVER_NAME_KEY, "ShmServ-dummy"); endpoint_description_t *endpoint = nullptr; auto status = endpointDescription_create(properties, &endpoint); @@ -204,39 +208,7 @@ TEST_F(RsaShmExportRegUnitTestSuite, CreateExportRegistrationWithOutRpcType) { endpoint_description_t *endpoint = CreateEndpointDescription(); service_reference_pt reference = GetServiceReference(); - celix_properties_set(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); - - export_registration_t *exportRegistration = nullptr; - auto status = exportRegistration_create(ctx.get(), logHelper.get(), reference, endpoint, &exportRegistration); - EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); - - bundleContext_ungetServiceReference(ctx.get(), reference); - endpointDescription_destroy(endpoint); -} - -TEST_F(RsaShmExportRegUnitTestSuite, CreateExportRegistrationWithOverlongRpcTypeString) { - endpoint_description_t *endpoint = CreateEndpointDescription(); - service_reference_pt reference = GetServiceReference(); - - char overlongRpcType[128] = RSA_RPC_TYPE_PREFIX; - for (int i = strlen(RSA_RPC_TYPE_PREFIX); i < 127; ++i) { - overlongRpcType[i] = 'a'; - } - celix_properties_set(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, overlongRpcType); - - export_registration_t *exportRegistration = nullptr; - auto status = exportRegistration_create(ctx.get(), logHelper.get(), reference, endpoint, &exportRegistration); - EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); - - bundleContext_ungetServiceReference(ctx.get(), reference); - endpointDescription_destroy(endpoint); -} - -TEST_F(RsaShmExportRegUnitTestSuite, CreateExportRegistrationWithOutConfigType) { - endpoint_description_t *endpoint = CreateEndpointDescription(); - service_reference_pt reference = GetServiceReference(); - - celix_properties_unset(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS); + celix_properties_unset(endpoint->properties, RSA_SHM_RPC_TYPE_KEY); export_registration_t *exportRegistration = nullptr; auto status = exportRegistration_create(ctx.get(), logHelper.get(), reference, endpoint, &exportRegistration); @@ -329,9 +301,9 @@ TEST_F(RsaShmExportRegUnitTestSuite, RegisterMoreThanOneRpcFactory) { //register another rpc factory celix_properties_t *props = celix_properties_create(); - celix_properties_set(props, RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_PREFIX"mock"); - celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_RPC_FACTORY_VERSION); - auto svcId = celix_bundleContext_registerServiceAsync(ctx.get(), (void*)"dumb-rpc-service", RSA_RPC_FACTORY_NAME, props); + celix_properties_set(props, CELIX_RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); + celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, CELIX_RSA_RPC_FACTORY_VERSION); + auto svcId = celix_bundleContext_registerServiceAsync(ctx.get(), (void*)"dumb-rpc-service", CELIX_RSA_RPC_FACTORY_NAME, props); EXPECT_GE(svcId, 1); celix_bundleContext_waitForEvents(ctx.get()); celix_bundleContext_unregisterServiceAsync(ctx.get(), svcId, nullptr, nullptr); diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImplUnitTestSuite.cc b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImplUnitTestSuite.cc index 0b41f6e59..e602ee9ee 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImplUnitTestSuite.cc +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImplUnitTestSuite.cc @@ -81,9 +81,10 @@ class RsaShmUnitTestSuite : public ::testing::Test { calcService.handle = nullptr, calcService.add = calculator_add; celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE "," RSA_SHM_RPC_TYPE_DEFAULT); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, RSA_SHM_RPC_TYPE_KEY, RSA_SHM_RPC_TYPE_DEFAULT); calcSvcId = celix_bundleContext_registerService(ctx.get(), &calcService, RSA_SHM_CALCULATOR_SERVICE, properties); }; @@ -96,11 +97,12 @@ class RsaShmUnitTestSuite : public ::testing::Test { celix_properties_t *properties = celix_properties_create(); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, RSA_SHM_CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE "," RSA_SHM_RPC_TYPE_DEFAULT); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "7f7efba5-500f-4ee9-b733-68de012091da"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, "1234"); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, "0a068612-9f95-4f1b-bf0b-ffa6916dae12"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, RSA_SHM_RPC_TYPE_KEY, RSA_SHM_RPC_TYPE_DEFAULT); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "7f7efba5-500f-4ee9-b733-68de012091da"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, "1234"); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "0a068612-9f95-4f1b-bf0b-ffa6916dae12"); celix_properties_set(properties, RSA_SHM_SERVER_NAME_KEY, "ShmServ-dummy"); endpoint_description_t *endpoint = nullptr; auto status = endpointDescription_create(properties, &endpoint); @@ -217,10 +219,10 @@ TEST_F(RsaShmUnitTestSuite, ExportService) { status = exportReference_getExportedEndpoint(ref, &endpoint); EXPECT_EQ(CELIX_SUCCESS, status); EXPECT_STREQ("AdditionValue", celix_properties_get(endpoint->properties, "AdditionKey", nullptr)); - EXPECT_EQ(nullptr, celix_properties_get(endpoint->properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, nullptr)); + EXPECT_EQ(nullptr, celix_properties_get(endpoint->properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, nullptr)); EXPECT_STREQ(RSA_SHM_CALCULATOR_SERVICE, celix_properties_get(endpoint->properties, CELIX_FRAMEWORK_SERVICE_NAME, nullptr)); - EXPECT_STREQ("true", celix_properties_get(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED, nullptr)); - EXPECT_EQ(calcSvcId, celix_properties_getAsLong(endpoint->properties, OSGI_RSA_ENDPOINT_SERVICE_ID, -1)); + EXPECT_STREQ("true", celix_properties_get(endpoint->properties, CELIX_RSA_SERVICE_IMPORTED, nullptr)); + EXPECT_EQ(calcSvcId, celix_properties_getAsLong(endpoint->properties, CELIX_RSA_ENDPOINT_SERVICE_ID, -1)); free(ref); status = rsaShm_removeExportedService(admin, reg); @@ -243,7 +245,7 @@ TEST_F(RsaShmUnitTestSuite, ExportServiceWithObjectClass) { RegisterCalculatorService(); celix_properties_t *prop = celix_properties_create(); - celix_properties_set(prop, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, "*"); + celix_properties_set(prop, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, "*"); celix_array_list_t *regs = nullptr; status = rsaShm_exportService(admin, const_cast(std::to_string(calcSvcId).c_str()), prop, ®s); EXPECT_EQ(CELIX_SUCCESS, status); @@ -288,7 +290,7 @@ TEST_F(RsaShmUnitTestSuite, ExportedInterfaceNotMatchObjectClass) { RegisterCalculatorService(); celix_properties_t *prop = celix_properties_create(); - celix_properties_set(prop, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, "unmatched-interface"); + celix_properties_set(prop, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, "unmatched-interface"); celix_array_list_t *regs = nullptr; status = rsaShm_exportService(admin, const_cast(std::to_string(calcSvcId).c_str()), prop, ®s); EXPECT_EQ(CELIX_SUCCESS, status); @@ -310,7 +312,7 @@ TEST_F(RsaShmUnitTestSuite, ExportServiceWithUnmatchedConfigType) { RegisterCalculatorService(); celix_properties_t *prop = celix_properties_create(); - celix_properties_set(prop, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, "unmatched-config-type"); + celix_properties_set(prop, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, "unmatched-config-type"); celix_array_list_t *regs = nullptr; status = rsaShm_exportService(admin, const_cast(std::to_string(calcSvcId).c_str()), prop, ®s); EXPECT_EQ(CELIX_SUCCESS, status); @@ -335,7 +337,7 @@ TEST_F(RsaShmUnitTestSuite, ServiceLostExportedInterfaceProperty) { }; celix_properties_t *properties = celix_properties_create(); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); calcSvcId = celix_bundleContext_registerService(ctx.get(), &calcService, RSA_SHM_CALCULATOR_SERVICE, properties); celix_array_list_t *regs = nullptr; @@ -533,7 +535,7 @@ TEST_F(RsaShmUnitTestSuite, ImportServiceWithUnmatchedConfigType) { endpoint_description_t *endpoint = CreateEndpointDescription(); EXPECT_NE(nullptr, endpoint); - celix_properties_set(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "unmatched-config-type"); + celix_properties_set(endpoint->properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, "unmatched-config-type"); status = rsaShm_importService(admin, endpoint, ®s); @@ -554,7 +556,7 @@ TEST_F(RsaShmUnitTestSuite, EndpointLostConfigType) { endpoint_description_t *endpoint = CreateEndpointDescription(); EXPECT_NE(nullptr, endpoint); - celix_properties_unset(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS); + celix_properties_unset(endpoint->properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS); status = rsaShm_importService(admin, endpoint, ®s); EXPECT_EQ(CELIX_SUCCESS, status); @@ -615,7 +617,7 @@ TEST_F(RsaShmUnitTestSuite, EndpointLostRpcType) { endpoint_description_t *endpoint = CreateEndpointDescription(); EXPECT_NE(nullptr, endpoint); - celix_properties_set(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_unset(endpoint->properties, RSA_SHM_RPC_TYPE_KEY); status = rsaShm_importService(admin, endpoint, ®s); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -756,9 +758,9 @@ class RsaShmRpcTestSuite : public ::testing::Test { .add = calculator_add, }; celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE ",celix.remote.admin.rpc_type.json"); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE ",celix.remote.admin.rpc_type.json"); calcSvcId = celix_bundleContext_registerService(serverCtx.get(), &calcService, RSA_SHM_CALCULATOR_SERVICE, properties); EXPECT_TRUE(calcSvcId >= 0); } diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImportRegistrationUnitTestSuite.cc b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImportRegistrationUnitTestSuite.cc index 93d8a7440..d2ada2bb2 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImportRegistrationUnitTestSuite.cc +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmImportRegistrationUnitTestSuite.cc @@ -33,6 +33,8 @@ #include "celix_errno.h" #include +#define RSA_RPC_TYPE_FOR_TEST "celix.remote.admin.rpc_type.test" + static celix_status_t expect_RpcFacCreateProxy_ret = CELIX_SUCCESS; static celix_status_t RpcFacCreateProxy(void *handle, const endpoint_description_t *endpointDesc, long requestSenderSvcId, long *proxySvcId) { (void)endpointDesc;//unused @@ -49,9 +51,10 @@ static celix_status_t RpcFacCreateProxy(void *handle, const endpoint_description return CELIX_SUCCESS; }; celix_properties_t *properties = celix_properties_create(); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, RSA_SHM_CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE"," RSA_RPC_TYPE_PREFIX"mock"); + celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, RSA_SHM_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); auto calcSvcId = celix_bundleContext_registerServiceAsync(ctx, &calcService, RSA_SHM_CALCULATOR_SERVICE, properties); EXPECT_GE(calcSvcId, 0); *proxySvcId = calcSvcId; @@ -85,9 +88,9 @@ class RsaShmImportRegUnitTestSuite : public ::testing::Test { rpcFactory.destroyEndpoint = nullptr; celix_properties_t *rpcFacProps = celix_properties_create(); - celix_properties_set(rpcFacProps, RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_PREFIX"mock"); - celix_properties_set(rpcFacProps, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_RPC_FACTORY_VERSION); - rpcFactorySvcId = celix_bundleContext_registerServiceAsync(ctx.get(), &rpcFactory, RSA_RPC_FACTORY_NAME, rpcFacProps); + celix_properties_set(rpcFacProps, CELIX_RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); + celix_properties_set(rpcFacProps, CELIX_FRAMEWORK_SERVICE_VERSION, CELIX_RSA_RPC_FACTORY_VERSION); + rpcFactorySvcId = celix_bundleContext_registerServiceAsync(ctx.get(), &rpcFactory, CELIX_RSA_RPC_FACTORY_NAME, rpcFacProps); EXPECT_GE(rpcFactorySvcId, 1); celix_bundleContext_waitForEvents(ctx.get()); @@ -107,11 +110,12 @@ class RsaShmImportRegUnitTestSuite : public ::testing::Test { celix_properties_t *properties = celix_properties_create(); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_NAME, RSA_SHM_CALCULATOR_SERVICE); celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_SHM_CALCULATOR_SERVICE_VERSION); - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE"," RSA_RPC_TYPE_PREFIX"mock"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_ID, "7f7efba5-500f-4ee9-b733-68de012091da"); - celix_properties_setLong(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, 100);//Set a dummy service id - celix_properties_set(properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - celix_properties_set(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, "")); + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CALCULATOR_CONFIGURATION_TYPE); + celix_properties_set(properties, RSA_SHM_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_ID, "7f7efba5-500f-4ee9-b733-68de012091da"); + celix_properties_setLong(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, 100);//Set a dummy service id + celix_properties_set(properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, "")); celix_properties_set(properties, RSA_SHM_SERVER_NAME_KEY, "ShmServ-dummy"); endpoint_description_t *endpoint = nullptr; auto status = endpointDescription_create(properties, &endpoint); @@ -187,41 +191,12 @@ TEST_F(RsaShmImportRegUnitTestSuite, FailedToCloneEndpointDescription) { endpointDescription_destroy(endpoint); } -TEST_F(RsaShmImportRegUnitTestSuite, CreateImportRegistrationWithInvalidRpcType) { - auto* endpoint = CreateEndpointDescription(); - - import_registration_t *importRegistration = nullptr; - long reqSenderSvcId = 123;//set dummy service id - celix_properties_set(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, "invalid"); - auto status = importRegistration_create(ctx.get(), logHelper.get(), endpoint, reqSenderSvcId, &importRegistration); - EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); - - endpointDescription_destroy(endpoint); -} - TEST_F(RsaShmImportRegUnitTestSuite, CreateImportRegistrationWithoutRpcType) { auto* endpoint = CreateEndpointDescription(); import_registration_t *importRegistration = nullptr; long reqSenderSvcId = 123;//set dummy service id - celix_properties_unset(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS); - auto status = importRegistration_create(ctx.get(), logHelper.get(), endpoint, reqSenderSvcId, &importRegistration); - EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); - - endpointDescription_destroy(endpoint); -} - -TEST_F(RsaShmImportRegUnitTestSuite, CreateImportRegistrationWithOverlongRpcTypeString) { - endpoint_description_t *endpoint = CreateEndpointDescription(); - - char overlongRpcType[128] = RSA_RPC_TYPE_PREFIX; - for (int i = strlen(RSA_RPC_TYPE_PREFIX); i < 127; ++i) { - overlongRpcType[i] = 'a'; - } - celix_properties_set(endpoint->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, overlongRpcType); - - import_registration_t *importRegistration = nullptr; - long reqSenderSvcId = 123;//set dummy service id + celix_properties_unset(endpoint->properties, RSA_SHM_RPC_TYPE_KEY); auto status = importRegistration_create(ctx.get(), logHelper.get(), endpoint, reqSenderSvcId, &importRegistration); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -255,9 +230,9 @@ TEST_F(RsaShmImportRegUnitTestSuite, RegisterMoreThanOneRpcFactory) { //register another rpc factory celix_properties_t *props = celix_properties_create(); - celix_properties_set(props, RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_PREFIX"mock"); - celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, RSA_RPC_FACTORY_VERSION); - auto svcId = celix_bundleContext_registerServiceAsync(ctx.get(), (void*)"dumb-rpc-service", RSA_RPC_FACTORY_NAME, props); + celix_properties_set(props, CELIX_RSA_RPC_TYPE_KEY, RSA_RPC_TYPE_FOR_TEST); + celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, CELIX_RSA_RPC_FACTORY_VERSION); + auto svcId = celix_bundleContext_registerServiceAsync(ctx.get(), (void*)"dumb-rpc-service", CELIX_RSA_RPC_FACTORY_NAME, props); EXPECT_GE(svcId, 1); celix_bundleContext_waitForEvents(ctx.get()); celix_bundleContext_unregisterServiceAsync(ctx.get(), svcId, nullptr, nullptr); diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmIntegrationTestSuite.cc b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmIntegrationTestSuite.cc index c0b36cdbb..d7af36be3 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmIntegrationTestSuite.cc +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmIntegrationTestSuite.cc @@ -43,6 +43,6 @@ class RsaShmActivatorTestSuite : public ::testing::Test { TEST_F(RsaShmActivatorTestSuite, FindRsaShmService) { celix_bundleContext_waitForEvents(ctx.get()); - long found = celix_bundleContext_findService(ctx.get(), OSGI_RSA_REMOTE_SERVICE_ADMIN); + long found = celix_bundleContext_findService(ctx.get(), CELIX_RSA_REMOTE_SERVICE_ADMIN); EXPECT_GE(found, 0); } diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c index c3029ff93..50a1d74bb 100755 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_activator.c @@ -19,6 +19,8 @@ #include "rsa_shm_export_registration.h" #include "rsa_shm_import_registration.h" #include "rsa_shm_impl.h" +#include "rsa_shm_constants.h" +#include "remote_constants.h" #include "remote_service_admin.h" #include "celix_log_helper.h" #include "celix_api.h" @@ -47,7 +49,15 @@ celix_status_t rsaShmActivator_start(rsa_shm_activator_t *activator, celix_bundl if (status != CELIX_SUCCESS) { return status; } + celix_autoptr(celix_properties_t) props = celix_properties_create(); + if (props == NULL) { + return CELIX_ENOMEM; + } + status = celix_properties_set(props, CELIX_RSA_REMOTE_CONFIGS_SUPPORTED, RSA_SHM_CONFIGURATION_TYPE); + if (status != CELIX_SUCCESS) { + return status; + } activator->adminService.admin = (void*)admin; activator->adminService.exportService = (void*)rsaShm_exportService; @@ -70,7 +80,7 @@ celix_status_t rsaShmActivator_start(rsa_shm_activator_t *activator, celix_bundl activator->adminService.importRegistration_getImportReference = importRegistration_getImportReference; activator->adminSvcId = celix_bundleContext_registerServiceAsync(context, &activator->adminService, - OSGI_RSA_REMOTE_SERVICE_ADMIN, NULL); + CELIX_RSA_REMOTE_SERVICE_ADMIN, celix_steal_ptr(props)); if (activator->adminSvcId < 0) { return CELIX_BUNDLE_EXCEPTION; } diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_constants.h b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_constants.h index 11b5a5523..a7c47a0f2 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_constants.h +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_constants.h @@ -24,17 +24,25 @@ extern "C" { #endif - -#define RSA_SHM_CONFIGURATION_TYPE "celix.remote.admin.shm" - -#define RSA_SHM_SERVER_NAME_KEY "rsaShmServerName" +/** + * @brief RSA Configuration type for shared memory + */ +#define RSA_SHM_CONFIGURATION_TYPE "celix.remote.admin.shm" +/** + * @brief The unix domain socket server name, which is used to create an abstract socket. The abstract socket is used to transfer shared memory address information. + */ +#define RSA_SHM_SERVER_NAME_KEY "celix.remote.admin.shm.server_name" +/** + * @brief The serializer type of RSA_SHM_CONFIGURATION_TYPE. The value should be associated with RSA_RPC_TYPE_KEY of rsa_rpc_factory_t. + */ +#define RSA_SHM_RPC_TYPE_KEY "celix.remote.admin.shm.rpc_type" /** * @brief A property of RsaShm bundle that indicates the shared memory pool size. - * Its value should be greater than 8192 + * Its value should be greater than or equal to 8192, because the memory pool ctrl block(control_t) size is 6536 bytes. * */ -#define RSA_SHM_MEMORY_POOL_SIZE_KEY "rsaShmPoolSize" +#define RSA_SHM_MEMORY_POOL_SIZE_KEY "CELIX_RSA_SHM_POOL_SIZE" /** * @brief Shared memory pool default size * @@ -45,7 +53,7 @@ extern "C" { * @brief A property of RsaShm bundle that indicates the timeout of remote service invocation. * */ -#define RSA_SHM_MSG_TIMEOUT_KEY "rsaShmMsgTimeout" +#define RSA_SHM_MSG_TIMEOUT_KEY "CELIX_RSA_SHM_MSG_TIMEOUT" /** * @brief The default timeout of remote service invocation. * @@ -57,7 +65,7 @@ extern "C" { * If there are more concurrent invocations than its value, service invocation will fail. * */ -#define RSA_SHM_MAX_CONCURRENT_INVOCATIONS_KEY "rsaShmCctIvNum" +#define RSA_SHM_MAX_CONCURRENT_INVOCATIONS_KEY "CELIX_RSA_SHM_MAX_CONCURRENT_INVOCATIONS_NUM" /** * @brief The default value of the maximum concurrent invocations, If property RSA_SHM_MAX_CONCURRENT_INVOCATIONS_KEY does not exist, the default value is used diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_export_registration.c b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_export_registration.c index f44bfaef0..736593470 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_export_registration.c +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_export_registration.c @@ -18,6 +18,7 @@ */ #include "rsa_shm_export_registration.h" +#include "rsa_shm_constants.h" #include "rsa_request_handler_service.h" #include "rsa_rpc_factory.h" #include "endpoint_description.h" @@ -108,46 +109,28 @@ celix_status_t exportRegistration_create(celix_bundle_context_t *context, } export->reqHandlerSvcEntry = reqHandlerSvcEntry; - const char *serviceImportedConfigs = celix_properties_get(endpointDesc->properties, - OSGI_RSA_SERVICE_IMPORTED_CONFIGS, NULL); - if (serviceImportedConfigs == NULL) { - celix_logHelper_error(logHelper,"RSA export reg: service.imported.configs property is not exist."); - return CELIX_ILLEGAL_ARGUMENT; - } - char *rsaRpcType = NULL; - celix_autofree char *icCopy = strdup(serviceImportedConfigs); - const char delimiter[2] = ","; - char *token, *savePtr; - token = strtok_r(icCopy, delimiter, &savePtr); - while (token != NULL) { - rsaRpcType = celix_utils_trimInPlace(token); - if (strncmp(rsaRpcType, RSA_RPC_TYPE_PREFIX, sizeof(RSA_RPC_TYPE_PREFIX) - 1) == 0) { - break; - } - rsaRpcType = NULL; - token = strtok_r(NULL, delimiter, &savePtr); - } - if (rsaRpcType == NULL) { - celix_logHelper_error(logHelper,"RSA export reg: %s property is not exist.", RSA_RPC_TYPE_KEY); + const char *rsaShmRpcType = celix_properties_get(endpointDesc->properties, RSA_SHM_RPC_TYPE_KEY, NULL); + if (rsaShmRpcType == NULL) { + celix_logHelper_error(logHelper,"RSA export reg: %s property is not exist.", RSA_SHM_RPC_TYPE_KEY); return CELIX_ILLEGAL_ARGUMENT; } char filter[128] = {0}; - int bytes = snprintf(filter, sizeof(filter), "(%s=%s)", RSA_RPC_TYPE_KEY, rsaRpcType); + int bytes = snprintf(filter, sizeof(filter), "(%s=%s)", CELIX_RSA_RPC_TYPE_KEY, rsaShmRpcType); if (bytes >= sizeof(filter)) { - celix_logHelper_error(logHelper,"RSA export reg: The value(%s) of %s is too long.", rsaRpcType, RSA_RPC_TYPE_KEY); + celix_logHelper_error(logHelper, "RSA export reg: The value(%s) of %s is too long.", rsaShmRpcType, CELIX_RSA_RPC_TYPE_KEY); return CELIX_ILLEGAL_ARGUMENT; } celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; opts.filter.filter = filter; - opts.filter.serviceName = RSA_RPC_FACTORY_NAME; - opts.filter.versionRange = RSA_RPC_FACTORY_USE_RANGE; + opts.filter.serviceName = CELIX_RSA_RPC_FACTORY_NAME; + opts.filter.versionRange = CELIX_RSA_RPC_FACTORY_USE_RANGE; opts.callbackHandle = export; opts.add = exportRegistration_addRpcFac; opts.remove = exportRegistration_removeRpcFac; export->rpcSvcTrkId = celix_bundleContext_trackServicesWithOptionsAsync(context, &opts); if (export->rpcSvcTrkId < 0) { - celix_logHelper_error(logHelper,"RSA export reg: Error Tracking service for %s.", RSA_RPC_FACTORY_NAME); + celix_logHelper_error(logHelper, "RSA export reg: Error Tracking service for %s.", CELIX_RSA_RPC_FACTORY_NAME); return CELIX_SERVICE_EXCEPTION; } @@ -244,8 +227,8 @@ static void exportRegistration_addRpcFac(void *handle, void *svc) { reqHandlerSvcId); celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; opts.filter.filter = filter; - opts.filter.serviceName = RSA_REQUEST_HANDLER_SERVICE_NAME; - opts.filter.versionRange = RSA_REQUEST_HANDLER_SERVICE_USE_RANGE; + opts.filter.serviceName = CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME; + opts.filter.versionRange = CELIX_RSA_REQUEST_HANDLER_SERVICE_USE_RANGE; opts.callbackHandle = export->reqHandlerSvcEntry; // exportRegistration_removeRequestHandlerSvc maybe occur after exportRegistration_destroyCallback. Therefore,Using refrence count here. exportRegistration_retainReqHandlerSvcEntry(export->reqHandlerSvcEntry); @@ -253,7 +236,7 @@ static void exportRegistration_addRpcFac(void *handle, void *svc) { opts.remove = exportRegistration_removeRequestHandlerSvc; export->reqHandlerSvcTrkId = celix_bundleContext_trackServicesWithOptionsAsync(export->context, &opts); if (export->reqHandlerSvcTrkId < 0) { - celix_logHelper_error(export->logHelper,"RSA export reg: Error Tracking service for %s(%ld)", RSA_REQUEST_HANDLER_SERVICE_NAME, export->reqHandlerSvcId); + celix_logHelper_error(export->logHelper, "RSA export reg: Error Tracking service for %s(%ld)", CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME, export->reqHandlerSvcId); exportRegistration_releaseReqHandlerSvcEntry(export->reqHandlerSvcEntry); rpcFac->destroyEndpoint(rpcFac->handle, reqHandlerSvcId); return; diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_impl.c b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_impl.c index ba2fd6f31..6e8c9ff08 100755 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_impl.c +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_impl.c @@ -103,8 +103,8 @@ celix_status_t rsaShm_create(celix_bundle_context_t *context, celix_log_helper_t ad->reqSenderService.handle = ad; ad->reqSenderService.sendRequest = (void*)rsaShm_send; celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; - opts.serviceName = RSA_REQUEST_SENDER_SERVICE_NAME; - opts.serviceVersion = RSA_REQUEST_SENDER_SERVICE_VERSION; + opts.serviceName = CELIX_RSA_REQUEST_SENDER_SERVICE_NAME; + opts.serviceVersion = CELIX_RSA_REQUEST_SENDER_SERVICE_VERSION; opts.svc = &ad->reqSenderService; ad->reqSenderSvcId = celix_bundleContext_registerServiceWithOptionsAsync(context, &opts); if (ad->reqSenderSvcId < 0) { @@ -188,7 +188,7 @@ static celix_status_t rsaShm_receiveMsgCB(void *handle, rsa_shm_server_t *shmSer } rsa_shm_t *admin = handle; - long serviceId = celix_properties_getAsLong(metadata, OSGI_RSA_ENDPOINT_SERVICE_ID, -1); + long serviceId = celix_properties_getAsLong(metadata, CELIX_RSA_ENDPOINT_SERVICE_ID, -1); if (serviceId < 0) { celix_logHelper_error(admin->logHelper, "Service id is invalid."); return CELIX_ILLEGAL_ARGUMENT; @@ -220,7 +220,7 @@ celix_status_t rsaShm_send(rsa_shm_t *admin, endpoint_description_t *endpoint, return CELIX_SERVICE_EXCEPTION; } celix_autoptr(celix_properties_t) newMetadata = celix_properties_copy(metadata); - celix_properties_setLong(newMetadata,OSGI_RSA_ENDPOINT_SERVICE_ID, endpoint->serviceId); + celix_properties_setLong(newMetadata, CELIX_RSA_ENDPOINT_SERVICE_ID, endpoint->serviceId); status = rsaShmClientManager_sendMsgTo(admin->shmClientManager, shmServerName, (long)endpoint->serviceId, newMetadata, request, response); @@ -255,11 +255,11 @@ static void rsaShm_overlayProperties(celix_properties_t *additionalProperties, c static bool rsaShm_isConfigTypeMatched(celix_properties_t *properties) { bool matched = false; - /* If OSGI_RSA_SERVICE_EXPORTED_CONFIGS property is not set, then the Remote Service + /* If CELIX_RSA_SERVICE_EXPORTED_CONFIGS property is not set, then the Remote Service * Admin implementation must choose a convenient configuration type. */ const char *exportConfigs = celix_properties_get(properties, - OSGI_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CONFIGURATION_TYPE); + CELIX_RSA_SERVICE_EXPORTED_CONFIGS, RSA_SHM_CONFIGURATION_TYPE); if (exportConfigs != NULL) { // See if the EXPORT_CONFIGS matches this RSA. If so, try to export. @@ -330,10 +330,10 @@ celix_status_t rsaShm_exportService(rsa_shm_t *admin, char *serviceId, celix_autoptr(celix_array_list_t) registrations = NULL; if (rsaShm_isConfigTypeMatched(exportedProperties)) { - const char *exportsProp = celix_properties_get(exportedProperties, (char *) OSGI_RSA_SERVICE_EXPORTED_INTERFACES, NULL); + const char *exportsProp = celix_properties_get(exportedProperties, (char *) CELIX_RSA_SERVICE_EXPORTED_INTERFACES, NULL); const char *providedProp = celix_properties_get(exportedProperties, (char *) CELIX_FRAMEWORK_SERVICE_NAME, NULL); if (exportsProp == NULL || providedProp == NULL) { - celix_logHelper_error(admin->logHelper, "Error exporting service %s. Missing property %s or %s.", serviceId, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, CELIX_FRAMEWORK_SERVICE_NAME); + celix_logHelper_error(admin->logHelper, "Error exporting service %s. Missing property %s or %s.", serviceId, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, CELIX_FRAMEWORK_SERVICE_NAME); return CELIX_ILLEGAL_STATE; } celix_autofree char *exports = celix_utils_trim(exportsProp); @@ -453,34 +453,6 @@ celix_status_t rsaShm_removeExportedService(rsa_shm_t *admin, export_registratio return status; } -static char *rsaShm_getRpcTypeWithDefault(rsa_shm_t *admin CELIX_UNUSED, const char *serviceExportedConfigs, const char *defaultVal) { - char *rpcType = NULL; - if (serviceExportedConfigs != NULL) { - celix_autofree char *ecCopy = celix_utils_strdup(serviceExportedConfigs); - if (ecCopy == NULL) { - return NULL; - } - const char delimiter[2] = ","; - char *token, *savePtr; - - token = strtok_r(ecCopy, delimiter, &savePtr); - while (token != NULL) { - celix_autofree char *tokenTrim = celix_utils_trim(token); - if (tokenTrim != NULL && strncmp(tokenTrim, RSA_RPC_TYPE_PREFIX, sizeof(RSA_RPC_TYPE_PREFIX) - 1) == 0) { - rpcType = celix_steal_ptr(tokenTrim); - break;//TODO Multiple RPC type values may be supported in the future. - } - token = strtok_r(NULL, delimiter, &savePtr); - } - } - //if rpc type is not exist, then set a default value. - if (rpcType == NULL && defaultVal != NULL) { - rpcType = celix_utils_strdup(defaultVal); - } - - return rpcType; -} - static celix_status_t rsaShm_createEndpointDescription(rsa_shm_t *admin, celix_properties_t *exportedProperties, char *interface, endpoint_description_t **description) { celix_status_t status = CELIX_SUCCESS; @@ -491,8 +463,8 @@ static celix_status_t rsaShm_createEndpointDescription(rsa_shm_t *admin, celix_autoptr(celix_properties_t) endpointProperties = celix_properties_copy(exportedProperties); celix_properties_unset(endpointProperties,CELIX_FRAMEWORK_SERVICE_NAME); - celix_properties_unset(endpointProperties,OSGI_RSA_SERVICE_EXPORTED_INTERFACES); - celix_properties_unset(endpointProperties,OSGI_RSA_SERVICE_EXPORTED_CONFIGS); + celix_properties_unset(endpointProperties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES); + celix_properties_unset(endpointProperties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS); celix_properties_unset(endpointProperties, CELIX_FRAMEWORK_SERVICE_ID); long serviceId = celix_properties_getAsLong(exportedProperties, CELIX_FRAMEWORK_SERVICE_ID, -1); @@ -507,26 +479,16 @@ static celix_status_t rsaShm_createEndpointDescription(rsa_shm_t *admin, celix_logHelper_error(admin->logHelper, "Cannot get framework uuid"); return CELIX_FRAMEWORK_EXCEPTION; } - celix_properties_set(endpointProperties, (char*) OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + celix_properties_set(endpointProperties, (char*) CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); celix_properties_set(endpointProperties, (char*) CELIX_FRAMEWORK_SERVICE_NAME, interface); - celix_properties_setLong(endpointProperties, (char*) OSGI_RSA_ENDPOINT_SERVICE_ID, serviceId); - celix_properties_set(endpointProperties, (char*) OSGI_RSA_ENDPOINT_ID, endpoint_uuid); - celix_properties_set(endpointProperties, (char*) OSGI_RSA_SERVICE_IMPORTED, "true"); - - celix_autofree char *rpcType = rsaShm_getRpcTypeWithDefault(admin, celix_properties_get(exportedProperties,OSGI_RSA_SERVICE_EXPORTED_CONFIGS, NULL), - RSA_SHM_RPC_TYPE_DEFAULT); - if (rpcType == NULL) { - celix_logHelper_error(admin->logHelper, "Failed to get rpc type"); - return CELIX_ENOMEM; - } - - char *importedConfigs = NULL; - int bytes = asprintf(&importedConfigs, "%s,%s",RSA_SHM_CONFIGURATION_TYPE, rpcType); - if (bytes < 0) { - celix_logHelper_error(admin->logHelper, "Failed to create imported configs"); - return CELIX_ENOMEM; + celix_properties_setLong(endpointProperties, (char*) CELIX_RSA_ENDPOINT_SERVICE_ID, serviceId); + celix_properties_set(endpointProperties, (char*) CELIX_RSA_ENDPOINT_ID, endpoint_uuid); + celix_properties_set(endpointProperties, (char*) CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(endpointProperties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, RSA_SHM_CONFIGURATION_TYPE); + //If the rpc type of RSA_SHM_CONFIGURATION_TYPE is not set, then set a default value. + if (celix_properties_get(endpointProperties, RSA_SHM_RPC_TYPE_KEY, NULL) == NULL) { + celix_properties_set(endpointProperties, RSA_SHM_RPC_TYPE_KEY, RSA_SHM_RPC_TYPE_DEFAULT); } - celix_properties_setWithoutCopy(endpointProperties, strdup(OSGI_RSA_SERVICE_IMPORTED_CONFIGS), importedConfigs); celix_properties_set(endpointProperties, (char *) RSA_SHM_SERVER_NAME_KEY, admin->shmServerName); status = endpointDescription_create(endpointProperties, description); if (status != CELIX_SUCCESS) { @@ -562,7 +524,7 @@ celix_status_t rsaShm_importService(rsa_shm_t *admin, endpoint_description_t *en celix_logHelper_info(admin->logHelper, "Import service %s", endpointDesc->serviceName); bool importService = false; - const char *importConfigs = celix_properties_get(endpointDesc->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, NULL); + const char *importConfigs = celix_properties_get(endpointDesc->properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, NULL); if (importConfigs != NULL) { // Check whether this RSA must be imported celix_autofree char *ecCopy = strndup(importConfigs, strlen(importConfigs)); @@ -579,7 +541,7 @@ celix_status_t rsaShm_importService(rsa_shm_t *admin, endpoint_description_t *en token = strtok_r(NULL, delimiter, &savePtr); } } else { - celix_logHelper_warning(admin->logHelper, "Mandatory %s element missing from endpoint description", OSGI_RSA_SERVICE_IMPORTED_CONFIGS); + celix_logHelper_warning(admin->logHelper, "Mandatory %s element missing from endpoint description", CELIX_RSA_SERVICE_IMPORTED_CONFIGS); } if (!importService) { return CELIX_SUCCESS; diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_import_registration.c b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_import_registration.c index 0238b7e20..d232377b7 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_import_registration.c +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_import_registration.c @@ -18,6 +18,7 @@ */ #include "rsa_shm_import_registration.h" +#include "rsa_shm_constants.h" #include "rsa_rpc_factory.h" #include "remote_constants.h" #include "celix_log_helper.h" @@ -63,46 +64,28 @@ celix_status_t importRegistration_create(celix_bundle_context_t *context, import->rpcFac = NULL; import->proxySvcId = -1; - const char *serviceImportedConfigs = celix_properties_get(endpointDesc->properties, - OSGI_RSA_SERVICE_IMPORTED_CONFIGS, NULL); - if (serviceImportedConfigs == NULL) { - celix_logHelper_error(logHelper,"RSA import reg: service.imported.configs property is not exist."); - return CELIX_ILLEGAL_ARGUMENT; - } - char *rsaRpcType = NULL; - celix_autofree char *icCopy = strdup(serviceImportedConfigs); - const char delimiter[2] = ","; - char *token, *savePtr; - token = strtok_r(icCopy, delimiter, &savePtr); - while (token != NULL) { - rsaRpcType = celix_utils_trimInPlace(token); - if (strncmp(rsaRpcType, RSA_RPC_TYPE_PREFIX, sizeof(RSA_RPC_TYPE_PREFIX) - 1) == 0) { - break; - } - rsaRpcType = NULL; - token = strtok_r(NULL, delimiter, &savePtr); - } - if (rsaRpcType == NULL) { - celix_logHelper_error(logHelper,"RSA import reg: %s property is not exist.", RSA_RPC_TYPE_KEY); + const char *rsaShmRpcType = celix_properties_get(endpointDesc->properties, RSA_SHM_RPC_TYPE_KEY, NULL); + if (rsaShmRpcType == NULL) { + celix_logHelper_error(logHelper,"RSA import reg: %s property is not exist.", RSA_SHM_RPC_TYPE_KEY); return CELIX_ILLEGAL_ARGUMENT; } char filter[128] = {0}; - int bytes = snprintf(filter, sizeof(filter), "(%s=%s)", RSA_RPC_TYPE_KEY, rsaRpcType); + int bytes = snprintf(filter, sizeof(filter), "(%s=%s)", CELIX_RSA_RPC_TYPE_KEY, rsaShmRpcType); if (bytes >= sizeof(filter)) { - celix_logHelper_error(logHelper,"RSA import reg: The value(%s) of %s is too long.", rsaRpcType, RSA_RPC_TYPE_KEY); - return CELIX_ILLEGAL_ARGUMENT; + celix_logHelper_error(logHelper, "RSA import reg: The value(%s) of %s is too long.", rsaShmRpcType, CELIX_RSA_RPC_TYPE_KEY); + return CELIX_ILLEGAL_ARGUMENT; } celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; opts.filter.filter = filter; - opts.filter.serviceName = RSA_RPC_FACTORY_NAME; - opts.filter.versionRange = RSA_RPC_FACTORY_USE_RANGE; + opts.filter.serviceName = CELIX_RSA_RPC_FACTORY_NAME; + opts.filter.versionRange = CELIX_RSA_RPC_FACTORY_USE_RANGE; opts.callbackHandle = import; opts.add = importRegistration_addRpcFac; opts.remove = importRegistration_removeRpcFac; import->rpcSvcTrkId = celix_bundleContext_trackServicesWithOptionsAsync(context, &opts); if (import->rpcSvcTrkId < 0) { - celix_logHelper_error(logHelper,"RSA import reg: Error Tracking service for %s.", RSA_RPC_FACTORY_NAME); + celix_logHelper_error(logHelper, "RSA import reg: Error Tracking service for %s.", CELIX_RSA_RPC_FACTORY_NAME); return CELIX_SERVICE_EXCEPTION; } diff --git a/bundles/remote_services/rsa_common/gtest/src/EndpointDescriptionUnitTestSuite.cc b/bundles/remote_services/rsa_common/gtest/src/EndpointDescriptionUnitTestSuite.cc index 7ef2ba492..bf4a51ad2 100644 --- a/bundles/remote_services/rsa_common/gtest/src/EndpointDescriptionUnitTestSuite.cc +++ b/bundles/remote_services/rsa_common/gtest/src/EndpointDescriptionUnitTestSuite.cc @@ -38,10 +38,10 @@ class EndpointDescriptionUnitTestSuite : public ::testing::Test { fw = std::shared_ptr{celix_frameworkFactory_createFramework(props), [](auto* f) {celix_frameworkFactory_destroyFramework(f);}}; properties = std::shared_ptr(celix_properties_create(), [](celix_properties_t* p) {celix_properties_destroy(p);}); - celix_properties_set(properties.get(), OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, "e7c2a8ab-79a8-40c5-a926-85ae64c9382a"); + celix_properties_set(properties.get(), CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "e7c2a8ab-79a8-40c5-a926-85ae64c9382a"); celix_properties_set(properties.get(), CELIX_FRAMEWORK_SERVICE_NAME, "org.example.api.Foo"); - celix_properties_set(properties.get(), OSGI_RSA_ENDPOINT_ID, "983e0ad8-5de9-44a8-b336-b3dc79d364b5"); - celix_properties_set(properties.get(), OSGI_RSA_ENDPOINT_SERVICE_ID, "100"); + celix_properties_set(properties.get(), CELIX_RSA_ENDPOINT_ID, "983e0ad8-5de9-44a8-b336-b3dc79d364b5"); + celix_properties_set(properties.get(), CELIX_RSA_ENDPOINT_SERVICE_ID, "100"); } ~EndpointDescriptionUnitTestSuite() override { @@ -87,7 +87,7 @@ TEST_F(EndpointDescriptionUnitTestSuite, CreateEndpointDescriptionWithENOMEM) { TEST_F(EndpointDescriptionUnitTestSuite, CreateEndpointDescriptionWithInvalidProperties1) { endpoint_description_t* endpointDescription = nullptr; celix_properties_t *props = celix_properties_copy(properties.get()); - celix_properties_unset(props, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID); + celix_properties_unset(props, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID); auto status = endpointDescription_create(props, &endpointDescription); EXPECT_EQ(status, CELIX_BUNDLE_EXCEPTION); @@ -106,7 +106,7 @@ TEST_F(EndpointDescriptionUnitTestSuite, CreateEndpointDescriptionWithInvalidPro TEST_F(EndpointDescriptionUnitTestSuite, CreateEndpointDescriptionWithInvalidProperties3) { endpoint_description_t* endpointDescription = nullptr; celix_properties_t *props = celix_properties_copy(properties.get()); - celix_properties_unset(props, OSGI_RSA_ENDPOINT_ID); + celix_properties_unset(props, CELIX_RSA_ENDPOINT_ID); auto status = endpointDescription_create(props, &endpointDescription); EXPECT_EQ(status, CELIX_BUNDLE_EXCEPTION); celix_properties_destroy(props); @@ -115,7 +115,7 @@ TEST_F(EndpointDescriptionUnitTestSuite, CreateEndpointDescriptionWithInvalidPro TEST_F(EndpointDescriptionUnitTestSuite, CreateEndpointDescriptionWithInvalidProperties4) { endpoint_description_t* endpointDescription = nullptr; celix_properties_t *props = celix_properties_copy(properties.get()); - celix_properties_unset(props, OSGI_RSA_ENDPOINT_SERVICE_ID); + celix_properties_unset(props, CELIX_RSA_ENDPOINT_SERVICE_ID); auto status = endpointDescription_create(props, &endpointDescription); EXPECT_EQ(status, CELIX_BUNDLE_EXCEPTION); celix_properties_destroy(props); diff --git a/bundles/remote_services/rsa_common/src/endpoint_description.c b/bundles/remote_services/rsa_common/src/endpoint_description.c index e9e9affa1..be9c1fdaf 100644 --- a/bundles/remote_services/rsa_common/src/endpoint_description.c +++ b/bundles/remote_services/rsa_common/src/endpoint_description.c @@ -49,10 +49,10 @@ celix_status_t endpointDescription_create(celix_properties_t *properties, endpoi return CELIX_ENOMEM; } ep->properties = properties; - ep->frameworkUUID = (char*)celix_properties_get(properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); - ep->id = (char*)celix_properties_get(properties, OSGI_RSA_ENDPOINT_ID, NULL); + ep->frameworkUUID = (char*)celix_properties_get(properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); + ep->id = (char*)celix_properties_get(properties, CELIX_RSA_ENDPOINT_ID, NULL); ep->serviceName = celix_utils_strdup(celix_properties_get(properties, CELIX_FRAMEWORK_SERVICE_NAME, NULL)); - ep->serviceId = celix_properties_getAsLong(properties, OSGI_RSA_ENDPOINT_SERVICE_ID, -1); + ep->serviceId = celix_properties_getAsLong(properties, CELIX_RSA_ENDPOINT_SERVICE_ID, -1); if (!(ep->frameworkUUID) || !(ep->id) || !(ep->serviceName) || ep->serviceId < 0) { fw_log(celix_frameworkLogger_globalLogger(), CELIX_LOG_LEVEL_ERROR, "ENDPOINT_DESCRIPTION: incomplete description!."); @@ -95,9 +95,9 @@ endpoint_description_t *endpointDescription_clone(const endpoint_description_t * if (newDesc->properties == NULL) { return NULL; } - newDesc->frameworkUUID = (char*)celix_properties_get(newDesc->properties,OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); + newDesc->frameworkUUID = (char*)celix_properties_get(newDesc->properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, NULL); newDesc->serviceId = description->serviceId; - newDesc->id = (char*)celix_properties_get(newDesc->properties, OSGI_RSA_ENDPOINT_ID, NULL); + newDesc->id = (char*)celix_properties_get(newDesc->properties, CELIX_RSA_ENDPOINT_ID, NULL); newDesc->serviceName = celix_utils_strdup(description->serviceName); if (newDesc->serviceName == NULL) { return NULL; diff --git a/bundles/remote_services/rsa_common/src/export_registration_impl.c b/bundles/remote_services/rsa_common/src/export_registration_impl.c index 32f28f72f..ad541e5fb 100644 --- a/bundles/remote_services/rsa_common/src/export_registration_impl.c +++ b/bundles/remote_services/rsa_common/src/export_registration_impl.c @@ -127,7 +127,7 @@ celix_status_t exportRegistration_createEndpointTracker(export_registration_t *r if (status == CELIX_SUCCESS) { char filter[512]; - snprintf(filter, 512, "(&(%s=%s)(remote.interface=%s))", (char*) CELIX_FRAMEWORK_SERVICE_NAME, (char*) OSGI_RSA_REMOTE_ENDPOINT, registration->endpointDescription->serviceName); + snprintf(filter, 512, "(&(%s=%s)(remote.interface=%s))", (char*) CELIX_FRAMEWORK_SERVICE_NAME, (char*) CELIX_RSA_REMOTE_ENDPOINT, registration->endpointDescription->serviceName); status = serviceTracker_createWithFilter(registration->context, filter, customizer, tracker); } diff --git a/bundles/remote_services/rsa_common/src/import_registration_impl.c b/bundles/remote_services/rsa_common/src/import_registration_impl.c index afd4c5b69..3e377b57e 100644 --- a/bundles/remote_services/rsa_common/src/import_registration_impl.c +++ b/bundles/remote_services/rsa_common/src/import_registration_impl.c @@ -166,7 +166,7 @@ celix_status_t importRegistration_createProxyFactoryTracker(import_registration_ if (status == CELIX_SUCCESS) { char filter[512]; - snprintf(filter, 512, "(&(%s=%s)(proxy.interface=%s))", (char*) CELIX_FRAMEWORK_SERVICE_NAME, (char*) OSGI_RSA_REMOTE_PROXY_FACTORY, registration_factory->serviceName); + snprintf(filter, 512, "(&(%s=%s)(proxy.interface=%s))", (char*) CELIX_FRAMEWORK_SERVICE_NAME, (char*) CELIX_RSA_REMOTE_PROXY_FACTORY, registration_factory->serviceName); status = serviceTracker_createWithFilter(registration_factory->context, filter, customizer, tracker); if (status == CELIX_SUCCESS) diff --git a/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c b/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c index 65c25207c..dddfa4899 100644 --- a/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c +++ b/bundles/remote_services/rsa_common/src/remote_interceptors_handler.c @@ -63,7 +63,7 @@ celix_status_t remoteInterceptorsHandler_create(celix_bundle_context_t *ctx, rem if (status == CELIX_SUCCESS) { // Create service tracker here, and not in the activator celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; - opts.filter.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; + opts.filter.serviceName = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME; opts.callbackHandle = *handler; opts.addWithProperties = remoteInterceptorsHandler_addInterceptor; opts.removeWithProperties = remoteInterceptorsHandler_removeInterceptor; diff --git a/bundles/remote_services/rsa_common/src/remote_proxy_factory_impl.c b/bundles/remote_services/rsa_common/src/remote_proxy_factory_impl.c index 3e455951c..a72a7d7ca 100644 --- a/bundles/remote_services/rsa_common/src/remote_proxy_factory_impl.c +++ b/bundles/remote_services/rsa_common/src/remote_proxy_factory_impl.c @@ -112,7 +112,7 @@ celix_status_t remoteProxyFactory_register(remote_proxy_factory_t *remote_proxy_ } if (status == CELIX_SUCCESS) { - status = bundleContext_registerService(remote_proxy_factory_ptr->context_ptr, OSGI_RSA_REMOTE_PROXY_FACTORY, + status = bundleContext_registerService(remote_proxy_factory_ptr->context_ptr, CELIX_RSA_REMOTE_PROXY_FACTORY, remote_proxy_factory_ptr->remote_proxy_factory_service_ptr, remote_proxy_factory_ptr->properties, &remote_proxy_factory_ptr->registration); } diff --git a/bundles/remote_services/rsa_rpc_json/CMakeLists.txt b/bundles/remote_services/rsa_rpc_json/CMakeLists.txt index 779b7e864..0733be48e 100644 --- a/bundles/remote_services/rsa_rpc_json/CMakeLists.txt +++ b/bundles/remote_services/rsa_rpc_json/CMakeLists.txt @@ -44,6 +44,7 @@ if (RSA_JSON_RPC) SYMBOLIC_NAME "apache_celix_rsa_json_rpc" NAME "Apache Celix Remote Service Admin JSON RPC" GROUP "Celix/RSA" + FILENAME celix_rsa_json_rpc SOURCES ${RSA_JSON_RPC_SRC} ) diff --git a/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcIntegrationTestSuite.cc b/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcIntegrationTestSuite.cc index 843e6f48a..0fcbfa776 100644 --- a/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcIntegrationTestSuite.cc +++ b/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcIntegrationTestSuite.cc @@ -45,6 +45,6 @@ class RsaJsonRpcIntegrationTestSuite : public ::testing::Test { TEST_F(RsaJsonRpcIntegrationTestSuite, FindRsaJsonRpcService) { celix_bundleContext_waitForEvents(ctx.get()); -long found = celix_bundleContext_findService(ctx.get(), RSA_RPC_FACTORY_NAME); +long found = celix_bundleContext_findService(ctx.get(), CELIX_RSA_RPC_FACTORY_NAME); EXPECT_GE(found, 0); } \ No newline at end of file diff --git a/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcUnitTestSuite.cc b/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcUnitTestSuite.cc index cdd3e5278..97c183f52 100644 --- a/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcUnitTestSuite.cc +++ b/bundles/remote_services/rsa_rpc_json/gtest/src/RsaJsonRpcUnitTestSuite.cc @@ -87,14 +87,14 @@ class RsaJsonRpcUnitTestSuite : public ::testing::Test { endpointDesc->properties = celix_properties_create(); EXPECT_TRUE(endpointDesc->properties != nullptr); const char *uuid = celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); - celix_properties_set(endpointDesc->properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + celix_properties_set(endpointDesc->properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); celix_properties_set(endpointDesc->properties, CELIX_FRAMEWORK_SERVICE_NAME, RSA_RPC_JSON_TEST_SERVICE); celix_properties_set(endpointDesc->properties, CELIX_FRAMEWORK_SERVICE_VERSION, "1.0.0"); - celix_properties_set(endpointDesc->properties, OSGI_RSA_ENDPOINT_ID, "8cf05b2d-421e-4c46-b55e-c3f1900b7cba"); - celix_properties_set(endpointDesc->properties, OSGI_RSA_SERVICE_IMPORTED, "true"); - endpointDesc->frameworkUUID = (char*)celix_properties_get(endpointDesc->properties, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, nullptr); + celix_properties_set(endpointDesc->properties, CELIX_RSA_ENDPOINT_ID, "8cf05b2d-421e-4c46-b55e-c3f1900b7cba"); + celix_properties_set(endpointDesc->properties, CELIX_RSA_SERVICE_IMPORTED, "true"); + endpointDesc->frameworkUUID = (char*)celix_properties_get(endpointDesc->properties, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, nullptr); endpointDesc->serviceId = svcId; - endpointDesc->id = (char*)celix_properties_get(endpointDesc->properties, OSGI_RSA_ENDPOINT_ID, nullptr); + endpointDesc->id = (char*)celix_properties_get(endpointDesc->properties, CELIX_RSA_ENDPOINT_ID, nullptr); endpointDesc->serviceName = strdup(RSA_RPC_JSON_TEST_SERVICE); return endpointDesc; } @@ -342,8 +342,8 @@ class RsaJsonRpcProxyUnitTestSuite : public RsaJsonRpcUnitTestSuite { return CELIX_SUCCESS; }; celix_service_registration_options_t opts{}; - opts.serviceName = RSA_REQUEST_SENDER_SERVICE_NAME; - opts.serviceVersion = RSA_REQUEST_SENDER_SERVICE_VERSION; + opts.serviceName = CELIX_RSA_REQUEST_SENDER_SERVICE_NAME; + opts.serviceVersion = CELIX_RSA_REQUEST_SENDER_SERVICE_VERSION; opts.svc = &reqSenderSvc; reqSenderSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx.get(), &opts); EXPECT_NE(-1, reqSenderSvcId); @@ -627,8 +627,8 @@ TEST_F(RsaJsonRpcProxyUnitTestSuite2, ServiceInvocationIsIntercepted) { }; celix_service_registration_options_t opts{}; - opts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; - opts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + opts.serviceName = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME; + opts.serviceVersion = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_VERSION; opts.svc = &interceptor; auto interceptorSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx.get(), &opts); celix_bundleContext_waitForAsyncRegistration(ctx.get(), interceptorSvcId); @@ -738,7 +738,7 @@ TEST_F(RsaJsonRpcEndPointUnitTestSuite, UseRequestHandler) { celix_properties_t *metadata = celix_properties_create(); celix_properties_setLong(metadata, "SerialProtocolId", serialProtoId); - auto found = celix_bundleContext_useService(ctx.get(), RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { + auto found = celix_bundleContext_useService(ctx.get(), CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { celix_properties_t *metadata = static_cast< celix_properties_t *>(handle);//unused auto reqHandler = static_cast(svc); EXPECT_NE(nullptr, reqHandler); @@ -770,7 +770,7 @@ TEST_F(RsaJsonRpcEndPointUnitTestSuite, FailedToFindInterfaceDescriptor) { celix_properties_t *metadata = celix_properties_create(); celix_properties_setLong(metadata, "SerialProtocolId", serialProtoId); - auto found = celix_bundleContext_useService(ctx.get(), RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { + auto found = celix_bundleContext_useService(ctx.get(), CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { celix_properties_t *metadata = static_cast< celix_properties_t *>(handle);//unused auto reqHandler = static_cast(svc); EXPECT_NE(nullptr, reqHandler); @@ -803,7 +803,7 @@ TEST_F(RsaJsonRpcEndPointUnitTestSuite, ServiceVersionMismatched) { celix_properties_t *metadata = celix_properties_create(); celix_properties_setLong(metadata, "SerialProtocolId", serialProtoId); - auto found = celix_bundleContext_useService(ctx.get(), RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { + auto found = celix_bundleContext_useService(ctx.get(), CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { celix_properties_t *metadata = static_cast< celix_properties_t *>(handle);//unused auto reqHandler = static_cast(svc); EXPECT_NE(nullptr, reqHandler); @@ -835,7 +835,7 @@ TEST_F(RsaJsonRpcEndPointUnitTestSuite, EndpointLostServiceVersion) { celix_properties_t *metadata = celix_properties_create(); celix_properties_setLong(metadata, "SerialProtocolId", serialProtoId); - auto found = celix_bundleContext_useService(ctx.get(), RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { + auto found = celix_bundleContext_useService(ctx.get(), CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { celix_properties_t *metadata = static_cast< celix_properties_t *>(handle);//unused auto reqHandler = static_cast(svc); EXPECT_NE(nullptr, reqHandler); @@ -866,7 +866,7 @@ TEST_F(RsaJsonRpcEndPointUnitTestSuite, UseRequestHandlerWithInvalidParams) { celix_properties_t *metadata = celix_properties_create(); celix_properties_setLong(metadata, "SerialProtocolId", serialProtoId); - auto found = celix_bundleContext_useService(ctx.get(), RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { + auto found = celix_bundleContext_useService(ctx.get(), CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { celix_properties_t *metadata = static_cast< celix_properties_t *>(handle);//unused auto reqHandler = static_cast(svc); EXPECT_NE(nullptr, reqHandler); @@ -927,8 +927,8 @@ TEST_F(RsaJsonRpcEndPointUnitTestSuite, ServiceInvocationIsIntercepted) { return; }; celix_service_registration_options_t opts{}; - opts.serviceName = REMOTE_INTERCEPTOR_SERVICE_NAME; - opts.serviceVersion = REMOTE_INTERCEPTOR_SERVICE_VERSION; + opts.serviceName = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME; + opts.serviceVersion = CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_VERSION; opts.svc = &interceptor; auto interceptorSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx.get(), &opts); celix_bundleContext_waitForAsyncRegistration(ctx.get(), interceptorSvcId); @@ -937,7 +937,7 @@ TEST_F(RsaJsonRpcEndPointUnitTestSuite, ServiceInvocationIsIntercepted) { celix_properties_t *metadata = celix_properties_create(); celix_properties_setLong(metadata, "SerialProtocolId", serialProtoId); - auto found = celix_bundleContext_useService(ctx.get(), RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { + auto found = celix_bundleContext_useService(ctx.get(), CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME, metadata, [](void *handle, void *svc) { celix_properties_t *metadata = static_cast< celix_properties_t *>(handle);//unused auto reqHandler = static_cast(svc); EXPECT_NE(nullptr, reqHandler); diff --git a/bundles/remote_services/rsa_rpc_json/gtest/src/RsaRequestSenderTrackerUnitTestSuite.cc b/bundles/remote_services/rsa_rpc_json/gtest/src/RsaRequestSenderTrackerUnitTestSuite.cc index 9728cde00..8c46cd839 100644 --- a/bundles/remote_services/rsa_rpc_json/gtest/src/RsaRequestSenderTrackerUnitTestSuite.cc +++ b/bundles/remote_services/rsa_rpc_json/gtest/src/RsaRequestSenderTrackerUnitTestSuite.cc @@ -58,8 +58,8 @@ class RsaRequestSenderTrackerUnitTestSuite : public ::testing::Test { return CELIX_SUCCESS; }; celix_service_registration_options_t opts{}; - opts.serviceName = RSA_REQUEST_SENDER_SERVICE_NAME; - opts.serviceVersion = RSA_REQUEST_SENDER_SERVICE_VERSION; + opts.serviceName = CELIX_RSA_REQUEST_SENDER_SERVICE_NAME; + opts.serviceVersion = CELIX_RSA_REQUEST_SENDER_SERVICE_VERSION; opts.svc = &reqSenderSvc; reqSenderSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx.get(), &opts); EXPECT_NE(-1, reqSenderSvcId); diff --git a/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_activator.c b/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_activator.c index 2aca6aafe..24a9d16e5 100644 --- a/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_activator.c +++ b/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_activator.c @@ -55,15 +55,15 @@ static celix_status_t rsaJsonRpc_start(rsa_json_rpc_activator_t* activator, celi celix_logHelper_error(activator->logHelper, "Error creating properties for json rpc."); return CELIX_ENOMEM; } - celix_properties_set(props, RSA_RPC_TYPE_KEY, "celix.remote.admin.rpc_type.json"); + celix_properties_set(props, CELIX_RSA_RPC_TYPE_KEY, "celix.remote.admin.rpc_type.json"); activator->rpcFac.handle = activator->jsonRpc; activator->rpcFac.createProxy = rsaJsonRpc_createProxy; activator->rpcFac.destroyProxy = rsaJsonRpc_destroyProxy; activator->rpcFac.createEndpoint = rsaJsonRpc_createEndpoint; activator->rpcFac.destroyEndpoint = rsaJsonRpc_destroyEndpoint; celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; - opts.serviceName = RSA_RPC_FACTORY_NAME; - opts.serviceVersion = RSA_RPC_FACTORY_VERSION; + opts.serviceName = CELIX_RSA_RPC_FACTORY_NAME; + opts.serviceVersion = CELIX_RSA_RPC_FACTORY_VERSION; opts.properties = props; opts.svc = &activator->rpcFac; activator->rpcSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); diff --git a/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_endpoint_impl.c b/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_endpoint_impl.c index fd3e96951..b922e88ca 100644 --- a/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_endpoint_impl.c +++ b/bundles/remote_services/rsa_rpc_json/src/rsa_json_rpc_endpoint_impl.c @@ -106,8 +106,8 @@ celix_status_t rsaJsonRpcEndpoint_create(celix_bundle_context_t* ctx, celix_log_ endpoint->reqHandlerSvc.handle = endpoint; endpoint->reqHandlerSvc.handleRequest = rsaJsonRpcEndpoint_handleRequest; celix_service_registration_options_t opts1 = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; - opts1.serviceName = RSA_REQUEST_HANDLER_SERVICE_NAME; - opts1.serviceVersion = RSA_REQUEST_HANDLER_SERVICE_VERSION; + opts1.serviceName = CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME; + opts1.serviceVersion = CELIX_RSA_REQUEST_HANDLER_SERVICE_VERSION; opts1.svc = &endpoint->reqHandlerSvc; celix_steal_ptr(lock); celix_steal_ptr(endpointDescCopy); diff --git a/bundles/remote_services/rsa_rpc_json/src/rsa_request_sender_tracker.c b/bundles/remote_services/rsa_rpc_json/src/rsa_request_sender_tracker.c index 57589d456..b746144f1 100644 --- a/bundles/remote_services/rsa_rpc_json/src/rsa_request_sender_tracker.c +++ b/bundles/remote_services/rsa_rpc_json/src/rsa_request_sender_tracker.c @@ -60,8 +60,8 @@ celix_status_t rsaRequestSenderTracker_create(celix_bundle_context_t* ctx, celix celix_autoptr(celix_long_hash_map_t) requestSenderSvcs = tracker->requestSenderSvcs = celix_longHashMap_create(); assert(tracker->requestSenderSvcs != NULL); celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; - opts.filter.serviceName = RSA_REQUEST_SENDER_SERVICE_NAME; - opts.filter.versionRange = RSA_REQUEST_SENDER_SERVICE_USE_RANGE; + opts.filter.serviceName = CELIX_RSA_REQUEST_SENDER_SERVICE_NAME; + opts.filter.versionRange = CELIX_RSA_REQUEST_SENDER_SERVICE_USE_RANGE; opts.callbackHandle = tracker; opts.addWithProperties = rsaRequestSenderTracker_addServiceWithProperties; opts.removeWithProperties = rsaRequestSenderTracker_removeServiceWithProperties; diff --git a/bundles/remote_services/rsa_spi/include/endpoint_listener.h b/bundles/remote_services/rsa_spi/include/endpoint_listener.h index 0a58a1a2b..870923d32 100644 --- a/bundles/remote_services/rsa_spi/include/endpoint_listener.h +++ b/bundles/remote_services/rsa_spi/include/endpoint_listener.h @@ -29,9 +29,9 @@ #include "endpoint_description.h" -static const char * const OSGI_ENDPOINT_LISTENER_SERVICE = "endpoint_listener"; +#define CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME "endpoint_listener" -static const char * const OSGI_ENDPOINT_LISTENER_SCOPE = "endpoint.listener.scope"; +#define CELIX_RSA_ENDPOINT_LISTENER_SCOPE "endpoint.listener.scope" struct endpoint_listener { void *handle; diff --git a/bundles/remote_services/rsa_spi/include/remote_constants.h b/bundles/remote_services/rsa_spi/include/remote_constants.h index efc490157..383eb9001 100644 --- a/bundles/remote_services/rsa_spi/include/remote_constants.h +++ b/bundles/remote_services/rsa_spi/include/remote_constants.h @@ -27,23 +27,50 @@ #ifndef REMOTE_CONSTANTS_H_ #define REMOTE_CONSTANTS_H_ -static const char * const OSGI_RSA_SERVICE_EXPORTED_INTERFACES = "service.exported.interfaces"; -static const char * const OSGI_RSA_ENDPOINT_FRAMEWORK_UUID = "endpoint.framework.uuid"; -static const char * const OSGI_RSA_ENDPOINT_SERVICE_ID = "endpoint.service.id"; -static const char * const OSGI_RSA_ENDPOINT_ID = "endpoint.id"; -static const char * const OSGI_RSA_SERVICE_IMPORTED = "service.imported"; -static const char * const OSGI_RSA_SERVICE_IMPORTED_CONFIGS = "service.imported.configs"; -static const char * const OSGI_RSA_SERVICE_EXPORTED_CONFIGS = "service.exported.configs"; -static const char * const OSGI_RSA_SERVICE_LOCATION = "service.location"; +#define CELIX_RSA_SERVICE_EXPORTED_INTERFACES "service.exported.interfaces" +#define CELIX_RSA_ENDPOINT_FRAMEWORK_UUID "endpoint.framework.uuid" +#define CELIX_RSA_ENDPOINT_SERVICE_ID "endpoint.service.id" +#define CELIX_RSA_ENDPOINT_ID "endpoint.id" +#define CELIX_RSA_SERVICE_IMPORTED "service.imported" +#define CELIX_RSA_SERVICE_IMPORTED_CONFIGS "service.imported.configs" +#define CELIX_RSA_SERVICE_EXPORTED_CONFIGS "service.exported.configs" +#define CELIX_RSA_SERVICE_LOCATION "service.location" /** - * Remote service admin property identifying the network interfaces that announce service. - * The property value is network interfaces name, it Can be a comma separated list of CIDR notation,eg:"eth0,en0". - * Default value is "", and the loopback interface will be used. Its exported service will be discovered - * only by other local clients on the same machine. - * If want to bound service to all network interfaces, we can set the property value to "all". + * @brief It identify which types of remote service configurations are supported by a distribution provider. + * @ref https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.remoteservices.html#i1708968 */ -static const char * const CELIX_RSA_NETWORK_INTERFACES = "org.apache.celix.rsa.network.interfaces"; +#define CELIX_RSA_REMOTE_CONFIGS_SUPPORTED "remote.configs.supported" +/** + * @breif It is a property of remote service admin service. It indicates whether the RSA implementation supports dynamic IP address fill-in for service exports. + * Its type is boolean.If this property is not specified, it defaults to false. + * @details If dynamic IP fill-in is supported, the RSA implementation should bind to ANY address (0.0.0.0). And the topology manager will create multiple endpoints for a single export registration based on the available network interfaces and an optional network selection configuration. + */ +#define CELIX_RSA_DYNAMIC_IP_SUPPORT "celix.rsa.dynamic.ip.support" + +/** + * @brief It is a replaceable property of endpoint. It indicates the dynamically determined IP address for the endpoint. Its type is string with comma-separated list of IP addresses. + * @todo Use string array instead of comma-separated list.(depends on https://github.com/apache/celix/issues/674) + */ +#define CELIX_RSA_IP_ADDRESSES "celix.rsa.ip.addresses" + +/** + * @brief It is a property of endpoint. It indicates the port number of the endpoint for which a dynamic IP address is required. Its type is integer. + */ +#define CELIX_RSA_PORT "celix.rsa.port" + +/** + * @brief It is a replaceable property of endpoint. It indicates which network interface is used for exported endpoint exposure. + * Its type is string. If this property is not specified, discovery implementation should select a proper exposure policy. + */ +#define CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE "celix.rsa.ifname" + +/** + * @brief It is a property of discovery endpoint listener service. It indicates whether the discovery implementation supports handling of interface-specific endpoints. + * Its type is boolean. If this property is not specified, it defaults to false. + * @details If handling interface-specific endpoints are supported, the discovery implementation will fill in the dynamic IP address to the property `CELIX_RSA_IP_ADDRESSES` of endpoint. + */ +#define CELIX_RSA_DISCOVERY_INTERFACE_SPECIFIC_ENDPOINTS_SUPPORT "celix.rsa.discovery.interface.specific.endpoints.support" #endif /* REMOTE_CONSTANTS_H_ */ diff --git a/bundles/remote_services/rsa_spi/include/remote_endpoint.h b/bundles/remote_services/rsa_spi/include/remote_endpoint.h index 45a1d7e9f..f96f22568 100644 --- a/bundles/remote_services/rsa_spi/include/remote_endpoint.h +++ b/bundles/remote_services/rsa_spi/include/remote_endpoint.h @@ -27,7 +27,7 @@ #ifndef REMOTE_ENDPOINT_H_ #define REMOTE_ENDPOINT_H_ -#define OSGI_RSA_REMOTE_ENDPOINT "remote_endpoint" +#define CELIX_RSA_REMOTE_ENDPOINT "remote_endpoint" typedef struct remote_endpoint remote_endpoint_t; diff --git a/bundles/remote_services/rsa_spi/include/remote_interceptor.h b/bundles/remote_services/rsa_spi/include/remote_interceptor.h index d1f501c1e..e8d726896 100644 --- a/bundles/remote_services/rsa_spi/include/remote_interceptor.h +++ b/bundles/remote_services/rsa_spi/include/remote_interceptor.h @@ -22,8 +22,8 @@ #include -#define REMOTE_INTERCEPTOR_SERVICE_NAME "remote.interceptor" -#define REMOTE_INTERCEPTOR_SERVICE_VERSION "1.0.0" +#define CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_NAME "remote.interceptor" +#define CELIX_RSA_REMOTE_INTERCEPTOR_SERVICE_VERSION "1.0.0" typedef struct remote_interceptor { void *handle; diff --git a/bundles/remote_services/rsa_spi/include/remote_proxy.h b/bundles/remote_services/rsa_spi/include/remote_proxy.h index 2643d01bd..78239d68e 100644 --- a/bundles/remote_services/rsa_spi/include/remote_proxy.h +++ b/bundles/remote_services/rsa_spi/include/remote_proxy.h @@ -30,8 +30,8 @@ #include "endpoint_listener.h" #include "remote_service_admin.h" -#define OSGI_RSA_REMOTE_PROXY_FACTORY "remote_proxy_factory" -#define OSGI_RSA_REMOTE_PROXY_TIMEOUT "remote_proxy_timeout" +#define CELIX_RSA_REMOTE_PROXY_FACTORY "remote_proxy_factory" +#define CELIX_RSA_REMOTE_PROXY_TIMEOUT "remote_proxy_timeout" typedef celix_status_t (*sendToHandle)(remote_service_admin_t *remote_service_admin_ptr, endpoint_description_t *endpointDescription, char *request, char **reply, int* replyStatus); typedef celix_status_t (*createProxyService)(void *handle, endpoint_description_t *endpointDescription, remote_service_admin_t *rsa, sendToHandle sendToCallback, celix_properties_t *properties, void **service); diff --git a/bundles/remote_services/rsa_spi/include/remote_service_admin.h b/bundles/remote_services/rsa_spi/include/remote_service_admin.h index 0bca98d3e..ef342b924 100644 --- a/bundles/remote_services/rsa_spi/include/remote_service_admin.h +++ b/bundles/remote_services/rsa_spi/include/remote_service_admin.h @@ -32,7 +32,7 @@ #include "export_registration.h" #include "import_registration.h" -#define OSGI_RSA_REMOTE_SERVICE_ADMIN "remote_service_admin" +#define CELIX_RSA_REMOTE_SERVICE_ADMIN "remote_service_admin" typedef struct import_registration_factory import_registration_factory_t; diff --git a/bundles/remote_services/rsa_spi/include/rsa_request_handler_service.h b/bundles/remote_services/rsa_spi/include/rsa_request_handler_service.h index c94c19265..f13c50e8c 100644 --- a/bundles/remote_services/rsa_spi/include/rsa_request_handler_service.h +++ b/bundles/remote_services/rsa_spi/include/rsa_request_handler_service.h @@ -27,9 +27,9 @@ extern "C" { #include #include -#define RSA_REQUEST_HANDLER_SERVICE_NAME "rsa_request_handler_service" -#define RSA_REQUEST_HANDLER_SERVICE_VERSION "1.0.0" -#define RSA_REQUEST_HANDLER_SERVICE_USE_RANGE "[1.0.0,2)" +#define CELIX_RSA_REQUEST_HANDLER_SERVICE_NAME "rsa_request_handler_service" +#define CELIX_RSA_REQUEST_HANDLER_SERVICE_VERSION "1.0.0" +#define CELIX_RSA_REQUEST_HANDLER_SERVICE_USE_RANGE "[1.0.0,2)" /** * @brief The service handle RPC request diff --git a/bundles/remote_services/rsa_spi/include/rsa_request_sender_service.h b/bundles/remote_services/rsa_spi/include/rsa_request_sender_service.h index ba0cc62a0..8f0a0f4c3 100644 --- a/bundles/remote_services/rsa_spi/include/rsa_request_sender_service.h +++ b/bundles/remote_services/rsa_spi/include/rsa_request_sender_service.h @@ -28,9 +28,9 @@ extern "C" { #include #include -#define RSA_REQUEST_SENDER_SERVICE_NAME "rsa_request_sender_service" -#define RSA_REQUEST_SENDER_SERVICE_VERSION "1.0.0" -#define RSA_REQUEST_SENDER_SERVICE_USE_RANGE "[1.0.0,2)" +#define CELIX_RSA_REQUEST_SENDER_SERVICE_NAME "rsa_request_sender_service" +#define CELIX_RSA_REQUEST_SENDER_SERVICE_VERSION "1.0.0" +#define CELIX_RSA_REQUEST_SENDER_SERVICE_USE_RANGE "[1.0.0,2)" /** * @brief The service send RPC request diff --git a/bundles/remote_services/rsa_spi/include/rsa_rpc_factory.h b/bundles/remote_services/rsa_spi/include/rsa_rpc_factory.h index 7534274c1..d1a112808 100644 --- a/bundles/remote_services/rsa_spi/include/rsa_rpc_factory.h +++ b/bundles/remote_services/rsa_spi/include/rsa_rpc_factory.h @@ -31,17 +31,11 @@ extern "C" { /** * @brief The RPC type indicates which protocol is used to (de)serialize the raw data. */ -#define RSA_RPC_TYPE_KEY "celix.remote.admin.rpc_type" +#define CELIX_RSA_RPC_TYPE_KEY "celix.remote.admin.rpc_type" -/** - * @brief The prefix for RPC type value, and the RPC type value belongs to `service.exported.configs`. - * A whole RPC type value as follows: celix.remote.admin.rpc_type.json. - */ -#define RSA_RPC_TYPE_PREFIX "celix.remote.admin.rpc_type." - -#define RSA_RPC_FACTORY_NAME "rsa_rpc_factory" -#define RSA_RPC_FACTORY_VERSION "1.0.0" -#define RSA_RPC_FACTORY_USE_RANGE "[1.0.0,2.0.0)" +#define CELIX_RSA_RPC_FACTORY_NAME "rsa_rpc_factory" +#define CELIX_RSA_RPC_FACTORY_VERSION "1.0.0" +#define CELIX_RSA_RPC_FACTORY_USE_RANGE "[1.0.0,2.0.0)" /** * @brief The service use to create remote service endpoint and remote service proxy diff --git a/bundles/remote_services/topology_manager/CMakeLists.txt b/bundles/remote_services/topology_manager/CMakeLists.txt index 1ed7420be..ca742341e 100644 --- a/bundles/remote_services/topology_manager/CMakeLists.txt +++ b/bundles/remote_services/topology_manager/CMakeLists.txt @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +find_package(libuuid REQUIRED) + add_celix_bundle(rsa_topology_manager SOURCES src/topology_manager.c @@ -24,10 +26,11 @@ add_celix_bundle(rsa_topology_manager SYMBOLIC_NAME "apache_celix_rs_topology_manager" GROUP "Celix/RSA" NAME "Apache Celix RS Topology Manager" + FILENAME celix_rsa_topology_manager ) target_include_directories(rsa_topology_manager PRIVATE src) target_include_directories(rsa_topology_manager PRIVATE include) -target_link_libraries(rsa_topology_manager PRIVATE Celix::log_helper Celix::c_rsa_spi) +target_link_libraries(rsa_topology_manager PRIVATE Celix::rsa_common Celix::log_helper Celix::c_rsa_spi libuuid::libuuid) celix_deprecated_utils_headers(rsa_topology_manager) celix_deprecated_framework_headers(rsa_topology_manager) @@ -40,3 +43,11 @@ if (ENABLE_TESTING AND BUILD_RSA_REMOTE_SERVICE_ADMIN_DFI AND BUILD_RSA_DISCOVER add_subdirectory(tms_tst) endif () +if (ENABLE_TESTING) + add_library(rsa_topology_manager_cut STATIC src/topology_manager.c src/scope.c) + celix_deprecated_utils_headers(rsa_topology_manager_cut) + celix_deprecated_framework_headers(rsa_topology_manager_cut) + target_include_directories(rsa_topology_manager_cut PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include ${CMAKE_CURRENT_LIST_DIR}/src) + target_link_libraries(rsa_topology_manager_cut PUBLIC Celix::rsa_common Celix::log_helper Celix::c_rsa_spi libuuid::libuuid) + add_subdirectory(gtest) +endif () \ No newline at end of file diff --git a/bundles/remote_services/topology_manager/gtest/CMakeLists.txt b/bundles/remote_services/topology_manager/gtest/CMakeLists.txt new file mode 100644 index 000000000..f063854e6 --- /dev/null +++ b/bundles/remote_services/topology_manager/gtest/CMakeLists.txt @@ -0,0 +1,64 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +add_executable(unit_test_tm + src/TopologyManagerTestSuite.cc +) + +celix_deprecated_utils_headers(unit_test_tm) +celix_deprecated_framework_headers(unit_test_tm) + +target_link_libraries(unit_test_tm PRIVATE + rsa_topology_manager_cut + Celix::c_rsa_spi + Celix::framework + GTest::gtest + GTest::gtest_main +) + +add_test(NAME run_unit_test_tm COMMAND unit_test_tm) +setup_target_for_coverage(unit_test_tm SCAN_DIR ..) + +if (EI_TESTS) + ####unit test with error injection + add_executable(unit_test_tm_with_error_injection + src/TopologyManagerErrorInjectionTestSuite.cc + ) + + celix_deprecated_utils_headers(unit_test_tm_with_error_injection) + celix_deprecated_framework_headers(unit_test_tm_with_error_injection) + + target_link_libraries(unit_test_tm_with_error_injection PRIVATE + rsa_topology_manager_cut + Celix::c_rsa_spi + Celix::framework + Celix::threads_ei +# Celix::bundle_ctx_ei +# Celix::string_hash_map_ei + Celix::long_hash_map_ei + Celix::array_list_ei + Celix::properties_ei + Celix::utils_ei + Celix::malloc_ei + GTest::gtest + GTest::gtest_main + ) + + add_test(NAME run_unit_test_tm_with_error_injection COMMAND unit_test_tm_with_error_injection) + setup_target_for_coverage(unit_test_tm_with_error_injection SCAN_DIR ..) +endif () \ No newline at end of file diff --git a/bundles/remote_services/topology_manager/gtest/src/TopologyManagerErrorInjectionTestSuite.cc b/bundles/remote_services/topology_manager/gtest/src/TopologyManagerErrorInjectionTestSuite.cc new file mode 100644 index 000000000..1faddaec2 --- /dev/null +++ b/bundles/remote_services/topology_manager/gtest/src/TopologyManagerErrorInjectionTestSuite.cc @@ -0,0 +1,267 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include +#include "TopologyManagerTestSuiteBaseClass.h" +#include "celix_compiler.h" +#include "celix_errno.h" +#include "malloc_ei.h" +#include "celix_long_hash_map_ei.h" +#include "celix_array_list_ei.h" +#include "celix_properties_ei.h" +#include "celix_utils_ei.h" +#include "celix_threads_ei.h" + +class TopologyManagerCreatingErrorInjectionTestSuite : public ::testing::Test { +public: + TopologyManagerCreatingErrorInjectionTestSuite() { + auto config = celix_properties_create(); + celix_properties_set(config, CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"); + celix_properties_set(config, CELIX_FRAMEWORK_CACHE_DIR, ".tm_unit_test_cache"); + fw = std::shared_ptr{celix_frameworkFactory_createFramework(config), + [](auto f) { celix_frameworkFactory_destroyFramework(f); }}; + ctx = std::shared_ptr{celix_framework_getFrameworkContext(fw.get()), + [](auto) {/*nop*/}}; + logHelper = std::shared_ptr{celix_logHelper_create(ctx.get(), "tm_unit_test"), + [](auto l) { celix_logHelper_destroy(l); }}; + } + + ~TopologyManagerCreatingErrorInjectionTestSuite() override { + celix_ei_expect_calloc(nullptr, 0, nullptr); + celix_ei_expect_celixThreadMutex_create(nullptr, 0, 0); + celix_ei_expect_celix_longHashMap_create(nullptr, 0, nullptr); + } + + std::shared_ptr fw{}; + std::shared_ptr ctx{}; + std::shared_ptr logHelper{}; +}; + +TEST_F(TopologyManagerCreatingErrorInjectionTestSuite, AllocingMemoryErrorTest) { + celix_ei_expect_calloc((void*)topologyManager_create, 0, nullptr); + void *scope{}; + topology_manager_t *tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(TopologyManagerCreatingErrorInjectionTestSuite, CreatingMutexErrorTest) { + celix_ei_expect_celixThreadMutex_create((void*)topologyManager_create, 0, CELIX_ENOMEM); + void *scope{}; + topology_manager_t *tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(TopologyManagerCreatingErrorInjectionTestSuite, CreatingRsaMapErrorTest) { + celix_ei_expect_celix_longHashMap_create((void*)topologyManager_create, 0, nullptr); + void *scope{}; + topology_manager_t *tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(TopologyManagerCreatingErrorInjectionTestSuite, CreatingDynamicIPEndpointMapErrorTest) { + celix_ei_expect_celix_longHashMap_create((void*)topologyManager_create, 0, nullptr, 2); + void *scope{}; + topology_manager_t *tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(TopologyManagerCreatingErrorInjectionTestSuite, CreatingRsaIfNameMapErrorTest) { + celix_ei_expect_celix_longHashMap_create((void*)topologyManager_create, 0, nullptr, 3); + void *scope{}; + topology_manager_t *tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(TopologyManagerCreatingErrorInjectionTestSuite, CreatingScopeErrorTest) { + celix_ei_expect_calloc((void*)scope_scopeCreate, 0, nullptr); + void *scope{}; + topology_manager_t *tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +TEST_F(TopologyManagerCreatingErrorInjectionTestSuite, CreatingExportedServiceMapErrorTest) { + celix_ei_expect_celix_longHashMap_create((void*)topologyManager_create, 0, nullptr, 4); + void *scope{}; + topology_manager_t *tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(CELIX_ENOMEM, status); +} + +class TopologyManagerErrorInjectionTestSuite : public TopologyManagerTestSuiteBaseClass { +public: + TopologyManagerErrorInjectionTestSuite() = default; + + ~TopologyManagerErrorInjectionTestSuite() override { + celix_ei_expect_calloc(nullptr, 0, nullptr); + celix_ei_expect_celix_longHashMap_put(nullptr, 0, 0); + celix_ei_expect_celix_longHashMap_create(nullptr, 0, nullptr); + celix_ei_expect_celix_arrayList_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_copy(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_set(nullptr, 0, 0); + celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); + celix_ei_expect_celix_arrayList_add(nullptr, 0, 0); + } + + void TestExportServiceFailure(void (*errorInject)(void)) { + errorInject(); + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, + void* exportedSvc, service_reference_pt eplSvcRef CELIX_UNUSED, void* eplSvc CELIX_UNUSED, celix_bundle_context_t* ctx CELIX_UNUSED) { + //first add the exported service, then the rsa + auto status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true, nullptr, + [](void *handle CELIX_UNUSED, endpoint_description_t *endpoint CELIX_UNUSED, char *matchedFilter CELIX_UNUSED) -> celix_status_t { + ADD_FAILURE() << "Should not be called"; + return CELIX_SUCCESS; + }); + } +}; + +TEST_F(TopologyManagerErrorInjectionTestSuite, AllocingRsaSvcEntryMemoryErrorTest) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef CELIX_UNUSED, + void* exportedSvc CELIX_UNUSED, service_reference_pt eplSvcRef CELIX_UNUSED, void* eplSvc CELIX_UNUSED, celix_bundle_context_t* ctx CELIX_UNUSED) { + celix_ei_expect_calloc((void*)&topologyManager_rsaAdded, 0, nullptr); + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, PutingRsaSvcEntryToMapErrorTest) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef CELIX_UNUSED, + void* exportedSvc CELIX_UNUSED, service_reference_pt eplSvcRef CELIX_UNUSED, void* eplSvc CELIX_UNUSED, celix_bundle_context_t* ctx CELIX_UNUSED) { + celix_ei_expect_celix_longHashMap_put((void*)&topologyManager_rsaAdded, 0, CELIX_ENOMEM); + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_ENOMEM, status); + + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, PutingExportedRegistrationToMapErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_longHashMap_put((void*)&topologyManager_rsaAdded, 0, CELIX_ENOMEM, 2); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, CreatingDynamicIpEndpointMapErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_longHashMap_create((void*)&topologyManager_rsaAdded, 2, nullptr); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, PutingDynamicIpEndpointToRsaMapErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_longHashMap_put((void*)&topologyManager_rsaAdded, 2, CELIX_ENOMEM); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, CreateDynamicIpEndpointListErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_arrayList_create((void*)&topologyManager_rsaAdded, 1, nullptr); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, PutingDynamicIpEndpointListToMapErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_longHashMap_put((void*)&topologyManager_rsaAdded, 1, CELIX_ENOMEM); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, CreatingRsaIfNameListErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_arrayList_create((void*)&topologyManager_rsaAdded, 3, nullptr); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, CopyRsaIfNamesStringErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_utils_strdup((void*)&topologyManager_rsaAdded, 3, nullptr, 2); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, CopyRsaIfNameErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_utils_strdup((void*)&topologyManager_rsaAdded, 3, nullptr, 3); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, AddingIfNameToListErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_arrayList_add((void*)&topologyManager_rsaAdded, 3, CELIX_ENOMEM); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, PutingIfNameListToMapErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_longHashMap_put((void*)&topologyManager_rsaAdded, 3, CELIX_ENOMEM); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, CreatingDynamicIpEndpointErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_properties_copy(CELIX_EI_UNKNOWN_CALLER, 0, nullptr); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, SettingDynamicIpEndpointIfNamePropertyErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_properties_set((void*)&topologyManager_rsaAdded, 3, CELIX_ENOMEM); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, SettingDynamicIpEndpointEpUuidPropertyErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_properties_set((void*)&topologyManager_rsaAdded, 3, CELIX_ENOMEM, 2); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, SettingDynamicIpEndpointIPAddressPropertyErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_properties_set((void*)&topologyManager_rsaAdded, 3, CELIX_ENOMEM, 3); + }); +} + +TEST_F(TopologyManagerErrorInjectionTestSuite, AddDynamicIpEndpointToListErrorTest) { + TestExportServiceFailure([]() { + celix_ei_expect_celix_arrayList_add((void*)&topologyManager_rsaAdded, 2, CELIX_ENOMEM, 2); + }); +} + + + diff --git a/bundles/remote_services/topology_manager/gtest/src/TopologyManagerTestSuite.cc b/bundles/remote_services/topology_manager/gtest/src/TopologyManagerTestSuite.cc new file mode 100644 index 000000000..6f3d028a1 --- /dev/null +++ b/bundles/remote_services/topology_manager/gtest/src/TopologyManagerTestSuite.cc @@ -0,0 +1,472 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "TopologyManagerTestSuiteBaseClass.h" + +class TopologyManagerTestSuite : public TopologyManagerTestSuiteBaseClass { +public: + TopologyManagerTestSuite() = default; + + ~TopologyManagerTestSuite() = default; +}; + +TEST_F(TopologyManagerTestSuite, ExportService1Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the rsa, then the epl and then the exported service + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }); +} + +TEST_F(TopologyManagerTestSuite, ExportService2Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the rsa, then the exported service and then the epl + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }); +} + +TEST_F(TopologyManagerTestSuite, ExportService3Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the exported service, then the rsa and then the epl + auto status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }); +} + +TEST_F(TopologyManagerTestSuite, ExportServiceWithDynamicIP1Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the rsa, then the epl and then the exported service + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true); +} + +TEST_F(TopologyManagerTestSuite, ExportServiceWithDynamicIP2Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the rsa, then the exported service and then the epl + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true); +} + +TEST_F(TopologyManagerTestSuite, ExportServiceWithDynamicIP3Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the exported service, then the rsa and then the epl + auto status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true); +} + +TEST_F(TopologyManagerTestSuite, ExportMutilServiceWithDynamicIPTest) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + //first add the rsa, then the exported service and then the epl + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + struct TmTestService { + void* handle; + } exportedSvc2{}; + auto exportedSvcProps = celix_properties_create(); + celix_properties_set(exportedSvcProps, "service.exported.interfaces", "*"); + auto exportedSvcId = celix_bundleContext_registerService(ctx, &exportedSvc2, "tmTestService2", exportedSvcProps); + EXPECT_TRUE(exportedSvcId > 0); + service_reference_pt svc2Ref{}; + status = bundleContext_getServiceReference(ctx, "tmTestService2", &svc2Ref); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, svc2Ref, &exportedSvc2); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, svc2Ref, &exportedSvc2); + EXPECT_EQ(CELIX_SUCCESS, status); + status = bundleContext_ungetServiceReference(ctx, svc2Ref); + EXPECT_EQ(CELIX_SUCCESS, status); + celix_bundleContext_unregisterService(ctx, exportedSvcId); + + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true); +} + +TEST_F(TopologyManagerTestSuite, ExportServiceFailed1Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the rsa, then the exported service and then the epl + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_BUNDLE_EXCEPTION, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, false, + [](remote_service_admin_t* admin, char* serviceId, celix_properties_t* properties, celix_array_list_t** registrations) -> celix_status_t { + (void)admin; + (void)properties; + (void)serviceId; + (void)registrations; + return CELIX_BUNDLE_EXCEPTION; + }, + [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + ADD_FAILURE() << "Should not be called"; + return CELIX_SUCCESS; + }); +} + +TEST_F(TopologyManagerTestSuite, ExportServiceFailed2Test) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the exported service, then the rsa and then the epl + auto status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, false, + [](remote_service_admin_t* admin, char* serviceId, celix_properties_t* properties, celix_array_list_t** registrations) -> celix_status_t { + (void)admin; + (void)properties; + (void)serviceId; + (void)registrations; + return CELIX_BUNDLE_EXCEPTION; + }, + [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + ADD_FAILURE() << "Should not be called"; + return CELIX_SUCCESS; + }); +} + +TEST_F(TopologyManagerTestSuite, ExportEmptyRegistrationListTest) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the rsa, then the exported service and then the epl + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true, + [](remote_service_admin_t* admin, char* serviceId, celix_properties_t* properties, celix_array_list_t** registrations) -> celix_status_t { + (void)admin; + (void)properties; + (void)serviceId; + *registrations = celix_arrayList_create(); + return CELIX_SUCCESS; + }, + [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + ADD_FAILURE() << "Should not be called"; + return CELIX_SUCCESS; + }); +} + +TEST_F(TopologyManagerTestSuite, DynamicIpEndpointRsaPortNotSpecifiedTest) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + //first add the rsa, then the exported service and then the epl + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true, + [](remote_service_admin_t* admin, char* serviceId, celix_properties_t* properties, celix_array_list_t** registrations) -> celix_status_t { + (void)properties; + celix_array_list_t* references{}; + service_reference_pt reference{}; + char filter[256]; + snprintf(filter, 256, "(%s=%s)", (char *) CELIX_FRAMEWORK_SERVICE_ID, serviceId); + auto status = bundleContext_getServiceReferences(admin->ctx, nullptr, filter, &references); + EXPECT_EQ(CELIX_SUCCESS, status); + reference = (service_reference_pt)celix_arrayList_get(references, 0); + EXPECT_TRUE(reference != nullptr); + auto exportReg = (export_registration_t*)malloc(sizeof(export_registration_t)); + auto endpointProps = celix_properties_create(); + unsigned int size = 0; + char **keys; + serviceReference_getPropertyKeys(reference, &keys, &size); + for (unsigned int i = 0; i < size; i++) { + char *key = keys[i]; + const char *value{}; + if (serviceReference_getProperty(reference, key, &value) == CELIX_SUCCESS + && strcmp(key, (char*) CELIX_RSA_SERVICE_EXPORTED_INTERFACES) != 0 + && strcmp(key, (char*) CELIX_RSA_SERVICE_EXPORTED_CONFIGS) != 0) { + celix_properties_set(endpointProps, key, value); + } + } + const char *fwUuid = celix_bundleContext_getProperty(admin->ctx, CELIX_FRAMEWORK_UUID, nullptr); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_SERVICE_ID, serviceId); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_ID, "319bddfa-0252-4654-a3bd-298354d30207"); + celix_properties_set(endpointProps, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(endpointProps, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, "tm_test_config_type"); + status = endpointDescription_create(endpointProps, &exportReg->exportReference.endpoint); + EXPECT_EQ(CELIX_SUCCESS, status); + exportReg->exportReference.reference = reference; + *registrations = celix_arrayList_create(); + celix_arrayList_add(*registrations, exportReg); + + bundleContext_ungetServiceReference(admin->ctx, reference); + free(keys); + celix_arrayList_destroy(references); + return CELIX_SUCCESS; + }, + [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + ADD_FAILURE() << "Should not be called"; + return CELIX_SUCCESS; + }); +} + +TEST_F(TopologyManagerTestSuite, DynamicIpRsaNetworkInterfaceNotSpecifiedTest) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + unsetenv("CELIX_RSA_INTERFACES_OF_PORT_" TEST_RSA_PORT); + //first add the rsa, then the exported service and then the epl + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerAdded(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_endpointListenerRemoved(tm, eplSvcRef, eplSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }, true,nullptr, + [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + ADD_FAILURE() << "Should not be called"; + return CELIX_SUCCESS; + }); +} + +TEST_F(TopologyManagerTestSuite, EndpointListenerNotSupportInterfaceSpecificEndpointsTest) { + TestExportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx) { + (void)ctx; + (void)eplSvc; + (void)eplSvcRef; + //first add the rsa, then the epl and then the exported service + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + endpoint_listener_t epl{}; + epl.handle = nullptr; + epl.endpointAdded = [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + ADD_FAILURE() << "Should not be called"; + return CELIX_SUCCESS; + }; + epl.endpointRemoved = [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + return CELIX_SUCCESS; + }; + const char *fwUuid = celix_bundleContext_getProperty(ctx, CELIX_FRAMEWORK_UUID, nullptr); + char scope[256] = {0}; + (void)snprintf(scope, sizeof(scope), "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, + CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + auto elpProps = celix_properties_create(); + celix_properties_set(elpProps, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, scope); + auto eplId = celix_bundleContext_registerService(ctx, &epl, CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, elpProps); + EXPECT_TRUE(eplId > 0); + char filter[256]; + snprintf(filter, 256, "(%s=%ld)", (char *) CELIX_FRAMEWORK_SERVICE_ID, eplId); + celix_array_list_t* references{}; + status = bundleContext_getServiceReferences(ctx, nullptr, filter, &references); + EXPECT_EQ(CELIX_SUCCESS, status); + auto eplRef = (service_reference_pt)celix_arrayList_get(references, 0); + EXPECT_TRUE(eplRef != nullptr); + status = topologyManager_endpointListenerAdded(tm, eplRef, &epl); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_addExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_removeExportedService(tm, exportedSvcRef, exportedSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_endpointListenerRemoved(tm, eplRef, &epl); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = bundleContext_ungetServiceReference(ctx, eplRef); + EXPECT_EQ(CELIX_SUCCESS, status); + celix_arrayList_destroy(references); + celix_bundleContext_unregisterService(ctx, eplId); + }, true); +} + +TEST_F(TopologyManagerTestSuite, ImportService1Test) { + TestImportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, endpoint_description_t *importEndpoint) { + //first add the rsa and then the import endpoint + auto status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_addImportedService(tm, importEndpoint, nullptr); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_removeImportedService(tm, importEndpoint, nullptr); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + }); +} + +TEST_F(TopologyManagerTestSuite, ImportService2Test) { + TestImportService([](topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, endpoint_description_t *importEndpoint) { + //first add the import endpoint and then the rsa + auto status = topologyManager_addImportedService(tm, importEndpoint, nullptr); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_rsaAdded(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + + status = topologyManager_rsaRemoved(tm, rsaSvcRef, rsaSvc); + EXPECT_EQ(CELIX_SUCCESS, status); + status = topologyManager_removeImportedService(tm, importEndpoint, nullptr); + EXPECT_EQ(CELIX_SUCCESS, status); + }); +} \ No newline at end of file diff --git a/bundles/remote_services/topology_manager/gtest/src/TopologyManagerTestSuiteBaseClass.h b/bundles/remote_services/topology_manager/gtest/src/TopologyManagerTestSuiteBaseClass.h new file mode 100644 index 000000000..27540175e --- /dev/null +++ b/bundles/remote_services/topology_manager/gtest/src/TopologyManagerTestSuiteBaseClass.h @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef CELIX_TOPOLOGYMANAGERTESTSUITEBASECLASS_H +#define CELIX_TOPOLOGYMANAGERTESTSUITEBASECLASS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "celix_errno.h" +#include "celix_constants.h" +#include "celix_bundle_context.h" +#include "celix_framework_factory.h" +#include "celix_log_helper.h" + +extern "C" { +#include "remote_constants.h" +#include "remote_service_admin.h" +#include "topology_manager.h" + +struct import_registration { + endpoint_description_t *endpoint; +}; + +struct export_reference { + endpoint_description_t *endpoint; + service_reference_pt reference; +}; +struct export_registration { + export_reference_t exportReference; +}; + +struct remote_service_admin { + celix_bundle_context_t* ctx; + bool dynamicIpSupport; +}; +} + +#define TEST_RSA_PORT "8080" + +class TopologyManagerTestSuiteBaseClass : public ::testing::Test { +public: + TopologyManagerTestSuiteBaseClass() { + auto config = celix_properties_create(); + celix_properties_set(config, CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"); + celix_properties_set(config, CELIX_FRAMEWORK_CACHE_DIR, ".tm_unit_test_cache"); + fw = std::shared_ptr{celix_frameworkFactory_createFramework(config), [](auto f) {celix_frameworkFactory_destroyFramework(f);}}; + ctx = std::shared_ptr{celix_framework_getFrameworkContext(fw.get()), [](auto){/*nop*/}}; + logHelper = std::shared_ptr{celix_logHelper_create(ctx.get(), "tm_unit_test"), [](auto l) {celix_logHelper_destroy(l);}}; + + void* scope = nullptr; + topology_manager_t* tmPtr{}; + auto status = topologyManager_create(ctx.get(), logHelper.get(), &tmPtr, &scope); + EXPECT_EQ(status, CELIX_SUCCESS); + tm = std::shared_ptr{tmPtr, [](auto t) {topologyManager_destroy(t);}}; + } + + ~TopologyManagerTestSuiteBaseClass() = default; + + void TestExportService(void (*testBody)(topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, service_reference_pt exportedSvcRef, + void* exportedSvc, service_reference_pt eplSvcRef, void* eplSvc, celix_bundle_context_t* ctx), bool testDynamicIp = false, + celix_status_t (*exportService)(remote_service_admin_t* admin, char* serviceId, celix_properties_t* properties, celix_array_list_t** registrations) = nullptr, + celix_status_t (*endpointAdded)(void *handle, endpoint_description_t *endpoint, char *matchedFilter) = nullptr) { + if (testDynamicIp) { + setenv("CELIX_RSA_INTERFACES_OF_PORT_" TEST_RSA_PORT, "eth0", true); + } + remote_service_admin_t rsa{}; + rsa.ctx = ctx.get(); + rsa.dynamicIpSupport = testDynamicIp; + remote_service_admin_service_t rsaSvc{}; + rsaSvc.admin = &rsa; + rsaSvc.exportService = exportService != nullptr ? exportService : [](remote_service_admin_t* admin, char* serviceId, + celix_properties_t* properties, celix_array_list_t** registrations) -> celix_status_t { + (void)properties; + celix_array_list_t* references{}; + service_reference_pt reference{}; + char filter[256]; + snprintf(filter, 256, "(%s=%s)", (char *) CELIX_FRAMEWORK_SERVICE_ID, serviceId); + auto status = bundleContext_getServiceReferences(admin->ctx, nullptr, filter, &references); + EXPECT_EQ(CELIX_SUCCESS, status); + reference = (service_reference_pt)celix_arrayList_get(references, 0); + EXPECT_TRUE(reference != nullptr); + auto exportReg = (export_registration_t*)malloc(sizeof(export_registration_t)); + auto endpointProps = celix_properties_create(); + unsigned int size = 0; + char **keys; + serviceReference_getPropertyKeys(reference, &keys, &size); + for (unsigned int i = 0; i < size; i++) { + char *key = keys[i]; + const char *value{}; + if (serviceReference_getProperty(reference, key, &value) == CELIX_SUCCESS + && strcmp(key, (char*) CELIX_RSA_SERVICE_EXPORTED_INTERFACES) != 0 + && strcmp(key, (char*) CELIX_RSA_SERVICE_EXPORTED_CONFIGS) != 0) { + celix_properties_set(endpointProps, key, value); + } + } + const char *fwUuid = celix_bundleContext_getProperty(admin->ctx, CELIX_FRAMEWORK_UUID, nullptr); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_SERVICE_ID, serviceId); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_ID, "319bddfa-0252-4654-a3bd-298354d30207"); + celix_properties_set(endpointProps, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(endpointProps, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, "tm_test_config_type"); + if (admin->dynamicIpSupport) { + celix_properties_set(endpointProps, CELIX_RSA_PORT, TEST_RSA_PORT); + } + status = endpointDescription_create(endpointProps, &exportReg->exportReference.endpoint); + EXPECT_EQ(CELIX_SUCCESS, status); + exportReg->exportReference.reference = reference; + *registrations = celix_arrayList_create(); + celix_arrayList_add(*registrations, exportReg); + + bundleContext_ungetServiceReference(admin->ctx, reference); + free(keys); + celix_arrayList_destroy(references); + return CELIX_SUCCESS; + }; + rsaSvc.exportRegistration_close = [](remote_service_admin_t* admin, export_registration_t* registration) -> celix_status_t { + (void)admin; + endpointDescription_destroy(registration->exportReference.endpoint); + free(registration); + return CELIX_SUCCESS; + }; + rsaSvc.exportRegistration_getExportReference = [](export_registration_t* registration, export_reference_t** reference) -> celix_status_t { + *reference = (export_reference_t*)calloc(1, sizeof(export_reference_t)); + (*reference)->endpoint = registration->exportReference.endpoint; + (*reference)->reference = registration->exportReference.reference; + return CELIX_SUCCESS; + }; + rsaSvc.exportReference_getExportedEndpoint = [](export_reference_t* reference, endpoint_description_t** endpoint) -> celix_status_t { + *endpoint = reference->endpoint; + return CELIX_SUCCESS; + }; + auto rsaProps = celix_properties_create(); + if (testDynamicIp) { + celix_properties_setBool(rsaProps, CELIX_RSA_DYNAMIC_IP_SUPPORT, true); + } + auto rsaId = celix_bundleContext_registerService(ctx.get(), &rsaSvc, CELIX_RSA_REMOTE_SERVICE_ADMIN, rsaProps); + EXPECT_TRUE(rsaId > 0); + + struct TmTestService { + void* handle; + } exportedService{}; + auto exportedSvcProps = celix_properties_create(); + celix_properties_set(exportedSvcProps, "service.exported.interfaces", "*"); + auto exportedSvcId = celix_bundleContext_registerService(ctx.get(), &exportedService, "tmTestService", exportedSvcProps); + EXPECT_TRUE(exportedSvcId > 0); + + endpoint_listener_t epl{}; + epl.handle = nullptr; + epl.endpointAdded = endpointAdded != nullptr ? endpointAdded : [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + return CELIX_SUCCESS; + }; + epl.endpointRemoved = [](void *handle, endpoint_description_t *endpoint, char *matchedFilter) -> celix_status_t { + (void)handle; + (void)endpoint; + (void)matchedFilter; + return CELIX_SUCCESS; + }; + const char *fwUuid = celix_bundleContext_getProperty(ctx.get(), CELIX_FRAMEWORK_UUID, nullptr); + char scope[256] = {0}; + (void)snprintf(scope, sizeof(scope), "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, + CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, fwUuid); + auto elpProps = celix_properties_create(); + celix_properties_set(elpProps, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, scope); + if (testDynamicIp) { + celix_properties_setBool(elpProps, CELIX_RSA_DISCOVERY_INTERFACE_SPECIFIC_ENDPOINTS_SUPPORT, true); + } + auto eplId = celix_bundleContext_registerService(ctx.get(), &epl, CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, elpProps); + EXPECT_TRUE(eplId > 0); + + service_reference_pt rsaSvcRef{}; + auto status = bundleContext_getServiceReference(ctx.get(), CELIX_RSA_REMOTE_SERVICE_ADMIN, &rsaSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + service_reference_pt exportedSvcRef{}; + status = bundleContext_getServiceReference(ctx.get(), "tmTestService", &exportedSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + service_reference_pt eplSvcRef{}; + status = bundleContext_getServiceReference(ctx.get(), CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, &eplSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + + testBody(tm.get(), rsaSvcRef, &rsaSvc, exportedSvcRef, &exportedService, eplSvcRef, &epl, ctx.get()); + + status = bundleContext_ungetServiceReference(ctx.get(), exportedSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + status = bundleContext_ungetServiceReference(ctx.get(), eplSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + status = bundleContext_ungetServiceReference(ctx.get(), rsaSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + + celix_bundleContext_unregisterService(ctx.get(), eplId); + celix_bundleContext_unregisterService(ctx.get(), exportedSvcId); + celix_bundleContext_unregisterService(ctx.get(), rsaId); + + if (testDynamicIp) { + unsetenv("CELIX_RSA_INTERFACES_OF_PORT_" TEST_RSA_PORT); + } + } + + void TestImportService(void (*testBody)(topology_manager_t* tm, service_reference_pt rsaSvcRef, void* rsaSvc, endpoint_description_t *importEndpoint)) { + remote_service_admin_t rsa{}; + rsa.ctx = ctx.get(); + remote_service_admin_service_t rsaSvc{}; + rsaSvc.admin = &rsa; + rsaSvc.importService = [](remote_service_admin_t* admin, endpoint_description_t* endpoint, import_registration_t** registration) -> celix_status_t { + (void)admin; + auto importReg = (import_registration_t*)calloc(1, sizeof(import_registration_t)); + importReg->endpoint = endpoint; + *registration = importReg; + return CELIX_SUCCESS; + }; + rsaSvc.importRegistration_close = [](remote_service_admin_t* admin, import_registration_t* registration) -> celix_status_t { + (void)admin; + free(registration); + return CELIX_SUCCESS; + }; + auto rsaId = celix_bundleContext_registerService(ctx.get(), &rsaSvc, CELIX_RSA_REMOTE_SERVICE_ADMIN, nullptr); + EXPECT_TRUE(rsaId > 0); + + auto endpointProps = celix_properties_create(); + celix_properties_set(endpointProps, CELIX_FRAMEWORK_SERVICE_NAME, "tmTestService"); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "1fb0bb2a-95ad-4cf9-8e79-072ec8bd4a85"); + celix_properties_setLong(endpointProps, CELIX_RSA_ENDPOINT_SERVICE_ID, 100); + celix_properties_set(endpointProps, CELIX_RSA_ENDPOINT_ID, "319bddfa-0252-4654-a3bd-298354d30207"); + celix_properties_set(endpointProps, CELIX_RSA_SERVICE_IMPORTED, "true"); + celix_properties_set(endpointProps, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, "tm_test_config_type"); + endpoint_description_t* endpoint{}; + auto status = endpointDescription_create(endpointProps, &endpoint); + EXPECT_EQ(CELIX_SUCCESS, status); + + service_reference_pt rsaSvcRef{}; + status = bundleContext_getServiceReference(ctx.get(), CELIX_RSA_REMOTE_SERVICE_ADMIN, &rsaSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + + testBody(tm.get(), rsaSvcRef, &rsaSvc, endpoint); + + status = bundleContext_ungetServiceReference(ctx.get(), rsaSvcRef); + EXPECT_EQ(CELIX_SUCCESS, status); + + endpointDescription_destroy(endpoint); + celix_bundleContext_unregisterService(ctx.get(), rsaId); + } + + std::shared_ptr fw{}; + std::shared_ptr ctx{}; + std::shared_ptr logHelper{}; + std::shared_ptr tm{}; +}; + +#ifdef __cplusplus +} +#endif + +#endif //CELIX_TOPOLOGYMANAGERTESTSUITEBASECLASS_H diff --git a/bundles/remote_services/topology_manager/src/activator.c b/bundles/remote_services/topology_manager/src/activator.c index 79ed7c94a..d113ad3f5 100644 --- a/bundles/remote_services/topology_manager/src/activator.c +++ b/bundles/remote_services/topology_manager/src/activator.c @@ -36,11 +36,11 @@ #include "topology_manager.h" #include "endpoint_listener.h" #include "remote_constants.h" +#include "remote_service_admin.h" #include "listener_hook_service.h" #include "celix_log_helper.h" #include "scope.h" #include "tm_scope.h" -#include "topology_manager.h" struct activator { celix_bundle_context_t *context; @@ -130,7 +130,7 @@ static celix_status_t bundleActivator_createEPLTracker(struct activator *activat status = serviceTrackerCustomizer_create(activator->manager, topologyManager_endpointListenerAdding, topologyManager_endpointListenerAdded, topologyManager_endpointListenerModified, topologyManager_endpointListenerRemoved, &customizer); if (status == CELIX_SUCCESS) { - status = serviceTracker_create(activator->context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, customizer, tracker); + status = serviceTracker_create(activator->context, (char *) CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, customizer, tracker); } return status; } @@ -140,7 +140,7 @@ static celix_status_t bundleActivator_createRSATracker(struct activator *activat service_tracker_customizer_t *customizer = NULL; status = serviceTrackerCustomizer_create(activator->manager, topologyManager_rsaAdding, topologyManager_rsaAdded, topologyManager_rsaModified, topologyManager_rsaRemoved, &customizer); if (status == CELIX_SUCCESS) { - status = serviceTracker_create(activator->context, OSGI_RSA_REMOTE_SERVICE_ADMIN, customizer, tracker); + status = serviceTracker_create(activator->context, CELIX_RSA_REMOTE_SERVICE_ADMIN, customizer, tracker); } return status; } @@ -172,25 +172,25 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context return CELIX_ILLEGAL_STATE; } - size_t len = 14 + strlen(CELIX_FRAMEWORK_SERVICE_NAME) + strlen(OSGI_RSA_ENDPOINT_FRAMEWORK_UUID) + strlen(uuid); + size_t len = 14 + strlen(CELIX_FRAMEWORK_SERVICE_NAME) + strlen(CELIX_RSA_ENDPOINT_FRAMEWORK_UUID) + strlen(uuid); char *scope = malloc(len); if (!scope) { return CELIX_ENOMEM; } - snprintf(scope, len, "(&(%s=*)(!(%s=%s)))", CELIX_FRAMEWORK_SERVICE_NAME, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + snprintf(scope, len, "(&(%s=*)(!(%s=%s)))", CELIX_FRAMEWORK_SERVICE_NAME, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); celix_logHelper_log(activator->celix_logHelper, CELIX_LOG_LEVEL_INFO, "TOPOLOGY_MANAGER: endpoint listener scope is %s", scope); celix_properties_t *props = celix_properties_create(); // topology manager should ingore itself endpoint listener service celix_properties_set(props, "TOPOLOGY_MANAGER", "true"); - celix_properties_set(props, (char *) OSGI_ENDPOINT_LISTENER_SCOPE, scope); + celix_properties_set(props, (char *) CELIX_RSA_ENDPOINT_LISTENER_SCOPE, scope); // We can release the scope, as celix_properties_set makes a copy of the key & value... free(scope); - bundleContext_registerService(context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, endpointListener, props, &activator->endpointListenerService); + bundleContext_registerService(context, (char *) CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, endpointListener, props, &activator->endpointListenerService); listener_hook_service_pt hookService = malloc(sizeof(*hookService)); hookService->handle = activator->manager; diff --git a/bundles/remote_services/topology_manager/src/topology_manager.c b/bundles/remote_services/topology_manager/src/topology_manager.c index a152e6691..877280684 100644 --- a/bundles/remote_services/topology_manager/src/topology_manager.c +++ b/bundles/remote_services/topology_manager/src/topology_manager.c @@ -29,7 +29,12 @@ #include #include +#include + #include "topology_manager.h" +#include "celix_build_assert.h" +#include "celix_long_hash_map.h" +#include "celix_stdlib_cleanup.h" #include "bundle_context.h" #include "celix_compiler.h" #include "celix_constants.h" @@ -47,14 +52,30 @@ #include "hash_map.h" #include "celix_array_list.h" + +//The prefix of the config property which is used to store the interfaces of a port. e.g. CELIX_RSA_INTERFACES_OF_PORT_8080. The value is a comma-separated list of interface names. +#define CELIX_RSA_INTERFACES_OF_PORT_PREFIX "CELIX_RSA_INTERFACES_OF_PORT_" + +typedef struct celix_rsa_service_entry { + remote_service_admin_service_t* rsa; + bool dynamicIpSupport; +} celix_rsa_service_entry_t; + +typedef struct celix_exported_service_entry { + service_reference_pt reference; + celix_long_hash_map_t* registrations; //key:rsa service id, val:celix_array_list_t +} celix_exported_service_entry_t; + struct topology_manager { celix_bundle_context_t *context; - celix_array_list_t *rsaList; + celix_long_hash_map_t* rsaMap;//key:rsa service id, val:celix_rsa_service_entry_t* + celix_long_hash_map_t* dynamicIpEndpoints;//key:rsa service id, val: celix_long_hash_map_t> + celix_long_hash_map_t* networkIfNames;//key:server port, val:celix_array_list_t. a list of network interface names hash_map_pt listenerList; - hash_map_pt exportedServices; + celix_long_hash_map_t* exportedServices;//key:service id, val:celix_exported_service_entry_t* hash_map_pt importedServices; @@ -73,40 +94,76 @@ celix_status_t topologyManager_importScopeChanged(void *handle, char *service_na static celix_status_t topologyManager_notifyListenersEndpointAdded(topology_manager_pt manager, remote_service_admin_service_t *rsa, celix_array_list_t *registrations); static celix_status_t topologyManager_notifyListenersEndpointRemoved(topology_manager_pt manager, remote_service_admin_service_t *rsa, export_registration_t *export); +static celix_status_t topologyManager_getEndpointDescriptionForExportRegistration(remote_service_admin_service_t *rsa, export_registration_t *export, endpoint_description_t **endpoint); static celix_status_t topologyManager_addImportedService_nolock(void *handle, endpoint_description_t *endpoint, char *matchedFilter); static celix_status_t topologyManager_removeImportedService_nolock(void *handle, endpoint_description_t *endpoint, char *matchedFilter); -static celix_status_t topologyManager_addExportedService_nolock(void * handle, service_reference_pt reference, void * service); -static celix_status_t topologyManager_removeExportedService_nolock(void * handle, service_reference_pt reference, void * service); +static celix_status_t topologyManager_addExportedService_nolock(void * handle, service_reference_pt reference); +static void topologyManager_removeExportedService_nolock(void * handle, service_reference_pt reference); celix_status_t topologyManager_create(celix_bundle_context_t *context, celix_log_helper_t *logHelper, topology_manager_pt *manager, void **scope) { celix_status_t status = CELIX_SUCCESS; - *manager = calloc(1, sizeof(**manager)); - - if (!*manager) { + celix_autofree topology_manager_t* tm = *manager = calloc(1, sizeof(**manager)); + if (tm == NULL) { + celix_logHelper_error(logHelper, "TOPOLOGY_MANAGER: Error allocating memory for topology_manager_t."); return CELIX_ENOMEM; } + tm->context = context; + tm->loghelper = logHelper; + tm->closed = false; + + status = celixThreadMutex_create(&tm->lock, NULL); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(logHelper, "TOPOLOGY_MANAGER: Error creating mutex."); + return status; + } + celix_autoptr(celix_thread_mutex_t) lock = &tm->lock; + celix_autoptr(celix_long_hash_map_t) rsaMap = tm->rsaMap = celix_longHashMap_create(); + if (rsaMap == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "TOPOLOGY_MANAGER: Error creating long hash map for rsa services."); + return CELIX_ENOMEM; + } + celix_autoptr(celix_long_hash_map_t) dynamicIpEndpoints = tm->dynamicIpEndpoints = celix_longHashMap_create(); + if (dynamicIpEndpoints == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "TOPOLOGY_MANAGER: Error creating long hash map for dynamic ip endpoints."); + return CELIX_ENOMEM; + } + celix_autoptr(celix_long_hash_map_t) networkIfNames = tm->networkIfNames = celix_longHashMap_create(); + if (networkIfNames == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "TOPOLOGY_MANAGER: Error creating long hash map for network interface names."); + return CELIX_ENOMEM; + } + celix_autoptr(celix_long_hash_map_t) exportedServices = tm->exportedServices = celix_longHashMap_create(); + if (exportedServices == NULL) { + celix_logHelper_logTssErrors(logHelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(logHelper, "TOPOLOGY_MANAGER: Error creating long hash map for exported services."); + return CELIX_ENOMEM; + } - (*manager)->context = context; - (*manager)->rsaList = NULL; - - celixThreadMutex_create(&(*manager)->lock, NULL); - - (*manager)->rsaList = celix_arrayList_create(); + //TODO remove deprecated hashMap (*manager)->listenerList = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL); - (*manager)->exportedServices = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL); (*manager)->importedServices = hashMap_create(NULL, NULL, NULL, NULL); - (*manager)->closed = false; - - status = scope_scopeCreate(*manager, &(*manager)->scope); - assert(status == CELIX_SUCCESS); - scope_setExportScopeChangedCallback((*manager)->scope, topologyManager_exportScopeChanged); - scope_setImportScopeChangedCallback((*manager)->scope, topologyManager_importScopeChanged); - *scope = (*manager)->scope; - - (*manager)->loghelper = logHelper; + status = scope_scopeCreate(tm, &tm->scope); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(logHelper, "TOPOLOGY_MANAGER: Error creating scope."); + hashMap_destroy(tm->importedServices, false, false); + hashMap_destroy(tm->listenerList, false, false); + return status; + } + scope_setExportScopeChangedCallback(tm->scope, topologyManager_exportScopeChanged); + scope_setImportScopeChangedCallback(tm->scope, topologyManager_importScopeChanged); + *scope = tm->scope; + celix_steal_ptr(exportedServices); + celix_steal_ptr(networkIfNames); + celix_steal_ptr(dynamicIpEndpoints); + celix_steal_ptr(rsaMap); + celix_steal_ptr(lock); + celix_steal_ptr(tm); return status; } @@ -119,9 +176,22 @@ celix_status_t topologyManager_destroy(topology_manager_pt manager) { celixThreadMutex_lock(&manager->lock); hashMap_destroy(manager->importedServices, false, false); - hashMap_destroy(manager->exportedServices, false, false); hashMap_destroy(manager->listenerList, false, false); - celix_arrayList_destroy(manager->rsaList); + + assert(celix_longHashMap_size(manager->exportedServices) == 0); + celix_longHashMap_destroy(manager->exportedServices); + CELIX_LONG_HASH_MAP_ITERATE(manager->networkIfNames, iter) { + celix_array_list_t* ifNames = iter.value.ptrValue; + for (int i = 0; i < celix_arrayList_size(ifNames); ++i) { + free(celix_arrayList_get(ifNames, i)); + } + celix_arrayList_destroy(ifNames); + } + celix_longHashMap_destroy(manager->networkIfNames); + assert(celix_longHashMap_size(manager->dynamicIpEndpoints) == 0); + celix_longHashMap_destroy(manager->dynamicIpEndpoints); + assert(celix_longHashMap_size(manager->rsaMap) == 0); + celix_longHashMap_destroy(manager->rsaMap); celixThreadMutex_unlock(&manager->lock); celixThreadMutex_destroy(&manager->lock); @@ -183,16 +253,318 @@ celix_status_t topologyManager_rsaAdding(void * handle, service_reference_pt ref return status; } -celix_status_t topologyManager_rsaAdded(void * handle, service_reference_pt unusedRef CELIX_UNUSED, void * service) { +static celix_array_list_t* topologyManager_getNetworkInterfacesForPort(topology_manager_t* tm, unsigned int port) { + celix_status_t status = CELIX_SUCCESS; + celix_array_list_t* ifNames = celix_longHashMap_get(tm->networkIfNames, port); + if (ifNames == NULL) { + char ifNamesKey[64]; + CELIX_BUILD_ASSERT(sizeof(ifNamesKey) >= (sizeof(CELIX_RSA_INTERFACES_OF_PORT_PREFIX) + 10));//10 is max int len + (void)snprintf(ifNamesKey, sizeof(ifNamesKey), "%s%u", CELIX_RSA_INTERFACES_OF_PORT_PREFIX, port); + const char* ifNamesStr = celix_bundleContext_getProperty(tm->context, ifNamesKey, NULL); + if (ifNamesStr == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error getting interface names from config properties."); + return NULL; + } + celix_autoptr(celix_array_list_t) _ifNames = celix_arrayList_create(); + if (_ifNames == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error creating array list for interface names."); + return NULL; + } + celix_autofree char* ifNamesStrCopy = celix_utils_strdup(ifNamesStr); + if (ifNamesStrCopy == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error copying interface names string."); + return NULL; + } + char* savePtr = NULL; + char* token = strtok_r(ifNamesStrCopy, ",", &savePtr); + while (token != NULL && status == CELIX_SUCCESS) { + celix_autofree char* ifname = celix_utils_strdup(token); + if (ifname == NULL) { + status = CELIX_ENOMEM; + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error copying interface name."); + continue; + } + status = celix_arrayList_add(_ifNames, ifname); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error adding interface name to array list."); + continue; + } + celix_steal_ptr(ifname); + token = strtok_r(NULL, ",", &savePtr); + } + + CELIX_DO_IF(status, status = celix_longHashMap_put(tm->networkIfNames, port, _ifNames)); + + if (status != CELIX_SUCCESS) { + for (int i = 0; i < celix_arrayList_size(_ifNames); ++i) { + free(celix_arrayList_get(_ifNames, i)); + } + return NULL; + } + ifNames = celix_steal_ptr(_ifNames); + } + return ifNames; +} + +static endpoint_description_t* topologyManager_createEndpointWithNetworkInterface(topology_manager_t* tm, const char* ifname, + endpoint_description_t* exportedRegEndpoint) { + celix_autoptr(endpoint_description_t) endpoint = endpointDescription_clone(exportedRegEndpoint); + if (endpoint == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error cloning endpoint description."); + return NULL; + } + celix_status_t status = celix_properties_set(endpoint->properties, CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE, ifname); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(tm->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error setting property %s.", CELIX_RSA_EXPORTED_ENDPOINT_EXPOSURE_INTERFACE); + return NULL; + } + uuid_t endpointUuid; + uuid_generate(endpointUuid); + char endpointUuidStr[37]; + uuid_unparse_lower(endpointUuid, endpointUuidStr); + status = celix_properties_set(endpoint->properties, CELIX_RSA_ENDPOINT_ID, endpointUuidStr); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(tm->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error setting property %s.", CELIX_RSA_ENDPOINT_ID); + return NULL; + } + endpoint->id = celix_properties_get(endpoint->properties, CELIX_RSA_ENDPOINT_ID, ""); + status = celix_properties_set(endpoint->properties, CELIX_RSA_IP_ADDRESSES, "");//need to be filled in by discovery implementation + if (status) { + celix_logHelper_logTssErrors(tm->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error setting property %s.", CELIX_RSA_IP_ADDRESSES); + return NULL; + } + return celix_steal_ptr(endpoint); +} + +static celix_status_t topologyManager_generateEndpointsForDynamicIpExportedRegistration(topology_manager_t* tm, endpoint_description_t* exportedRegEndpoint, + celix_array_list_t* endpoints) { + celix_status_t status = CELIX_SUCCESS; + int port = celix_properties_getAsLong(exportedRegEndpoint->properties, CELIX_RSA_PORT, -1); + if (port < 0) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error getting port from dynamic ip endpoint description."); + return CELIX_ILLEGAL_ARGUMENT; + } + celix_array_list_t* ifNames = topologyManager_getNetworkInterfacesForPort(tm, port); + if (ifNames == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error getting network interface names for port %d.", port); + return CELIX_ILLEGAL_STATE; + } + + int size = celix_arrayList_size(ifNames); + for (int i = 0; i < size; ++i) { + const char* ifname = celix_arrayList_get(ifNames, i); + celix_autoptr(endpoint_description_t) endpoint = topologyManager_createEndpointWithNetworkInterface(tm, ifname, exportedRegEndpoint); + if (endpoint == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error creating endpoint for service %s on %s", exportedRegEndpoint->serviceName, ifname); + continue; + } + status = celix_arrayList_add(endpoints, endpoint); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error adding endpoint for service %s on %s", exportedRegEndpoint->serviceName, ifname); + continue; + } + celix_steal_ptr(endpoint); + } + return CELIX_SUCCESS; +} + +static void topologyManager_notifyListenersDynamicIpEndpointAdded(topology_manager_t* tm, celix_array_list_t* endpoints) { + celix_status_t status = CELIX_SUCCESS; + + hash_map_iterator_pt iter = hashMapIterator_create(tm->listenerList); + while (hashMapIterator_hasNext(iter)) { + service_reference_pt reference = hashMapIterator_nextKey(iter); + + const char *interfaceSpecEndpointSupport = NULL; + serviceReference_getProperty(reference, CELIX_RSA_DISCOVERY_INTERFACE_SPECIFIC_ENDPOINTS_SUPPORT, &interfaceSpecEndpointSupport); + if (interfaceSpecEndpointSupport == NULL || strcmp(interfaceSpecEndpointSupport, "true") != 0) { + continue; + } + + const char* scope = NULL; + serviceReference_getProperty(reference, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, &scope); + celix_autoptr(celix_filter_t) filter = celix_filter_create(scope); + if (filter == NULL) { + celix_logHelper_logTssErrors(tm->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error creating filter for endpoint listener."); + continue; + } + + endpoint_listener_t *epl = NULL; + status = bundleContext_getService(tm->context, reference, (void **) &epl); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error getting endpoint listener."); + continue; + } + int size = celix_arrayList_size(endpoints); + for (int i = 0; i < size; i++) { + endpoint_description_t* endpoint = celix_arrayList_get(endpoints, i); + if (celix_filter_match(filter, endpoint->properties)) { + status = epl->endpointAdded(epl->handle, endpoint, (char*)scope); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Failed to add endpoint to endpoint listener."); + } + } + } + bundleContext_ungetService(tm->context, reference, NULL); + } + hashMapIterator_destroy(iter); + + return; +} + +static void topologyManager_notifyListenersDynamicIpEndpointRemoved(topology_manager_t* tm, celix_array_list_t* endpoints) { + celix_status_t status = CELIX_SUCCESS; + + hash_map_iterator_pt iter = hashMapIterator_create(tm->listenerList); + while (hashMapIterator_hasNext(iter)) { + endpoint_listener_t *epl = NULL; + service_reference_pt reference = hashMapIterator_nextKey(iter); + + status = bundleContext_getService(tm->context, reference, (void **) &epl); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error getting endpoint listener."); + continue; + } + int size = celix_arrayList_size(endpoints); + for (int i = 0; i < size; i++) { + endpoint_description_t* endpoint = celix_arrayList_get(endpoints, i); + status = epl->endpointRemoved(epl->handle, endpoint, NULL); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Failed to remove endpoint to endpoint listener."); + } + } + bundleContext_ungetService(tm->context, reference, NULL); + } + hashMapIterator_destroy(iter); + + return; +} + +static celix_long_hash_map_t* topologyManager_getDynamicIpEndpointMapForRsa(topology_manager_t* tm, long rsaSvcId) { + celix_autoptr(celix_long_hash_map_t) endpointMap = celix_longHashMap_get(tm->dynamicIpEndpoints, rsaSvcId); + if (endpointMap != NULL) { + return celix_steal_ptr(endpointMap); + } + + endpointMap = celix_longHashMap_create(); + if (endpointMap == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error creating long hash map for exported services."); + return NULL; + } + celix_status_t status = celix_longHashMap_put(tm->dynamicIpEndpoints, rsaSvcId, endpointMap); + if (status != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(tm->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error adding exported services to map."); + return NULL; + } + return celix_steal_ptr(endpointMap); +} + +static void topologyManager_addDynamicIpEndpointsForExportedService(topology_manager_t* tm, long rsaSvcId, long exportedSvcId, + celix_array_list_t *registrations) { + celix_status_t status = CELIX_SUCCESS; + int regSize = celix_arrayList_size(registrations); + if (regSize == 0) { + return; + } + celix_long_hash_map_t* endpointMap = topologyManager_getDynamicIpEndpointMapForRsa(tm, rsaSvcId); + if (endpointMap == NULL) { + return; + } + + celix_array_list_t* endpointList = celix_arrayList_create(); + if (endpointList == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error creating array list for dynamic ip endpoints."); + return; + } + status = celix_longHashMap_put(endpointMap, exportedSvcId, endpointList); + if (status != CELIX_SUCCESS) { + celix_arrayList_destroy(endpointList); + celix_logHelper_logTssErrors(tm->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error adding dynamic ip endpoints list to map."); + return; + } + + celix_rsa_service_entry_t* rsaSvcEntry = celix_longHashMap_get(tm->rsaMap, rsaSvcId); + assert(rsaSvcEntry != NULL);//It must be not null, because the rsa service is already added to the rsaMap. + for (int i = 0; i < regSize; ++i) { + export_registration_t* exportReg = celix_arrayList_get(registrations, i); + endpoint_description_t* exportedRegEndpoint = NULL; + status = topologyManager_getEndpointDescriptionForExportRegistration(rsaSvcEntry->rsa, exportReg, &exportedRegEndpoint); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error getting endpoint description for exported registration."); + continue; + } + status = topologyManager_generateEndpointsForDynamicIpExportedRegistration(tm, exportedRegEndpoint, endpointList); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error generating endpoints for dynamic ip exported registration"); + } + } + + if (celix_arrayList_size(endpointList) > 0) { + topologyManager_notifyListenersDynamicIpEndpointAdded(tm, endpointList); + } + + return; +} + +static void topologyManager_removeDynamicIpEndpointsForExportedService(topology_manager_t* tm, long rsaSvcId, long exportedSvcId) { + celix_long_hash_map_t* endpointMap = celix_longHashMap_get(tm->dynamicIpEndpoints, rsaSvcId); + if (endpointMap == NULL) { + return; + } + celix_array_list_t* endpointList = celix_longHashMap_get(endpointMap, exportedSvcId); + if (endpointList != NULL) { + topologyManager_notifyListenersDynamicIpEndpointRemoved(tm, endpointList); + for (int i = 0; i < celix_arrayList_size(endpointList); ++i) { + endpoint_description_t* endpoint = celix_arrayList_get(endpointList, i); + endpointDescription_destroy(endpoint); + } + celix_longHashMap_remove(endpointMap, exportedSvcId); + celix_arrayList_destroy(endpointList); + } + + if (celix_longHashMap_size(endpointMap) == 0) { + celix_longHashMap_remove(tm->dynamicIpEndpoints, rsaSvcId); + celix_longHashMap_destroy(endpointMap); + } + return; +} + +celix_status_t topologyManager_rsaAdded(void * handle, service_reference_pt rsaSvcRef, void * service) { topology_manager_pt manager = (topology_manager_pt) handle; celix_properties_t *serviceProperties = NULL; remote_service_admin_service_t *rsa = (remote_service_admin_service_t *) service; celix_logHelper_log(manager->loghelper, CELIX_LOG_LEVEL_INFO, "TOPOLOGY_MANAGER: Added RSA"); + bool dynamicIpSupport = false; + const char *dynamicIpSupportStr = NULL; + serviceReference_getProperty(rsaSvcRef, CELIX_RSA_DYNAMIC_IP_SUPPORT, &dynamicIpSupportStr); + if (dynamicIpSupportStr != NULL && celix_utils_stringEquals(dynamicIpSupportStr, "true")) { + dynamicIpSupport = true; + } - celixThreadMutex_lock(&manager->lock); + celix_autofree celix_rsa_service_entry_t* rsaSvcEntry = calloc(1, sizeof(*rsaSvcEntry)); + if (rsaSvcEntry == NULL) { + return CELIX_ENOMEM; + } + rsaSvcEntry->dynamicIpSupport = dynamicIpSupport; + rsaSvcEntry->rsa = rsa; - celix_arrayList_add(manager->rsaList, rsa); + celix_auto(celix_mutex_lock_guard_t) lockGuard = celixMutexLockGuard_init(&manager->lock); + + long rsaSvcId = serviceReference_getServiceId(rsaSvcRef); + celix_status_t ret = celix_longHashMap_put(manager->rsaMap, rsaSvcId, rsaSvcEntry); + if (ret != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(manager->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(manager->loghelper, "TOPOLOGY_MANAGER: Error adding rsa service entry to map."); + return ret; + } + celix_steal_ptr(rsaSvcEntry); // add already imported services to new rsa hash_map_iterator_pt importedServicesIterator = hashMapIterator_create(manager->importedServices); @@ -203,7 +575,6 @@ celix_status_t topologyManager_rsaAdded(void * handle, service_reference_pt unus if (scope_allowImport(manager->scope, endpoint)) { import_registration_t *import = NULL; celix_status_t status = rsa->importService(rsa->admin, endpoint, &import); - if (status == CELIX_SUCCESS) { hash_map_pt imports = hashMapEntry_getValue(entry); @@ -220,31 +591,37 @@ celix_status_t topologyManager_rsaAdded(void * handle, service_reference_pt unus hashMapIterator_destroy(importedServicesIterator); // add already exported services to new rsa - hash_map_iterator_pt exportedServicesIterator = hashMapIterator_create(manager->exportedServices); - - while (hashMapIterator_hasNext(exportedServicesIterator)) { - hash_map_entry_pt entry = hashMapIterator_nextEntry(exportedServicesIterator); - service_reference_pt reference = hashMapEntry_getKey(entry); - const char* serviceId = NULL; - - serviceReference_getProperty(reference, CELIX_FRAMEWORK_SERVICE_ID, &serviceId); + CELIX_LONG_HASH_MAP_ITERATE(manager->exportedServices, iter) { + celix_exported_service_entry_t* svcEntry = iter.value.ptrValue; + service_reference_pt reference = svcEntry->reference; + long serviceId = iter.key; + char serviceIdStr[32]; + (void)snprintf(serviceIdStr, sizeof(serviceIdStr), "%li", serviceId); scope_getExportProperties(manager->scope, reference, &serviceProperties); - celix_array_list_t *endpoints = NULL; - celix_status_t status = rsa->exportService(rsa->admin, (char*)serviceId, serviceProperties, &endpoints); - - if (status == CELIX_SUCCESS) { - hash_map_pt exports = hashMapEntry_getValue(entry); - assert(exports != NULL);// It must not be NULL, It has been created in function topologyManager_addExportedService_nolock - hashMap_put(exports, rsa, endpoints); - topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints); + celix_autoptr(celix_array_list_t) registrations = NULL; + celix_status_t status = rsa->exportService(rsa->admin, serviceIdStr, serviceProperties, ®istrations); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(manager->loghelper, "TOPOLOGY_MANAGER: Error exporting service."); + continue; + } + if (celix_longHashMap_put(svcEntry->registrations, rsaSvcId, registrations) != CELIX_SUCCESS) { + celix_logHelper_error(manager->loghelper, "TOPOLOGY_MANAGER: Error adding exported endpoints to map."); + for (int i = 0; i < celix_arrayList_size(registrations); ++i) { + export_registration_t* export = celix_arrayList_get(registrations, i); + rsa->exportRegistration_close(rsa->admin, export); + } + continue; } + if (dynamicIpSupport) { + topologyManager_addDynamicIpEndpointsForExportedService(manager, rsaSvcId,serviceId, registrations); + } else { + topologyManager_notifyListenersEndpointAdded(manager, rsa, registrations); + } + celix_steal_ptr(registrations); } - hashMapIterator_destroy(exportedServicesIterator); - celixThreadMutex_unlock(&manager->lock); - return CELIX_SUCCESS; } @@ -260,29 +637,30 @@ celix_status_t topologyManager_rsaRemoved(void * handle, service_reference_pt re celix_status_t status = CELIX_SUCCESS; topology_manager_pt manager = (topology_manager_pt) handle; remote_service_admin_service_t *rsa = (remote_service_admin_service_t *) service; + long rsaSvcId = serviceReference_getServiceId(reference); celixThreadMutex_lock(&manager->lock); - hash_map_iterator_pt exportedSvcIter = hashMapIterator_create(manager->exportedServices); - - while (hashMapIterator_hasNext(exportedSvcIter)) { + CELIX_LONG_HASH_MAP_ITERATE(manager->exportedServices, iter) { + celix_exported_service_entry_t* svcEntry = iter.value.ptrValue; + service_reference_pt exportSvcRef = svcEntry->reference; + long exportedSvcId = serviceReference_getServiceId(exportSvcRef); - hash_map_entry_pt entry = hashMapIterator_nextEntry(exportedSvcIter); - hash_map_pt exports = hashMapEntry_getValue(entry); + topologyManager_removeDynamicIpEndpointsForExportedService(manager, rsaSvcId, exportedSvcId); - celix_array_list_t *exports_list = (celix_array_list_t *)hashMap_remove(exports, rsa); + celix_array_list_t *exports_list = (celix_array_list_t *)celix_longHashMap_get(svcEntry->registrations, rsaSvcId); if (exports_list != NULL) { int exportsIter = 0; int exportListSize = celix_arrayList_size(exports_list); - for (exportsIter = 0; exports_list != NULL && exportsIter < exportListSize; exportsIter++) { + for (exportsIter = 0; exportsIter < exportListSize; exportsIter++) { export_registration_t *export = celix_arrayList_get(exports_list, exportsIter); topologyManager_notifyListenersEndpointRemoved(manager, rsa, export); rsa->exportRegistration_close(rsa->admin, export); } celix_arrayList_destroy(exports_list); + celix_longHashMap_remove(svcEntry->registrations, rsaSvcId); } } - hashMapIterator_destroy(exportedSvcIter); hash_map_iterator_pt importedSvcIter = hashMapIterator_create(manager->importedServices); @@ -301,7 +679,8 @@ celix_status_t topologyManager_rsaRemoved(void * handle, service_reference_pt re } hashMapIterator_destroy(importedSvcIter); - celix_arrayList_remove(manager->rsaList, rsa); + free(celix_longHashMap_get(manager->rsaMap, rsaSvcId)); + celix_longHashMap_remove(manager->rsaMap, rsaSvcId); celixThreadMutex_unlock(&manager->lock); @@ -314,30 +693,30 @@ celix_status_t topologyManager_exportScopeChanged(void *handle, char *filterStr) celix_status_t status = CELIX_SUCCESS; topology_manager_pt manager = (topology_manager_pt) handle; service_registration_t *reg = NULL; - const char* serviceId = NULL; bool found; celix_properties_t *props; celix_autoptr(celix_filter_t) filter = celix_filter_create(filterStr); if (filter == NULL) { - printf("filter creating failed\n"); + celix_logHelper_error(manager->loghelper,"filter creating failed\n"); return CELIX_ENOMEM; } // add already exported services to new rsa - celixThreadMutex_lock(&manager->lock); + celix_auto(celix_mutex_lock_guard_t) lockGuard = celixMutexLockGuard_init(&manager->lock); - hash_map_iterator_pt exportedServicesIterator = hashMapIterator_create(manager->exportedServices); - int size = hashMap_size(manager->exportedServices); - service_reference_pt *srvRefs = (service_reference_pt *) calloc(size, sizeof(service_reference_pt)); - char **srvIds = (char **) calloc(size, sizeof(char*)); + int size = celix_longHashMap_size(manager->exportedServices); + celix_autofree service_reference_pt *srvRefs = (service_reference_pt *) calloc(size, sizeof(service_reference_pt)); + if (srvRefs == NULL) { + return CELIX_ENOMEM; + } int nrFound = 0; found = false; - while (hashMapIterator_hasNext(exportedServicesIterator)) { - hash_map_entry_pt entry = hashMapIterator_nextEntry(exportedServicesIterator); - service_reference_pt reference = hashMapEntry_getKey(entry); + CELIX_LONG_HASH_MAP_ITERATE(manager->exportedServices, iter) { + celix_exported_service_entry_t* svcEntry = iter.value.ptrValue; + service_reference_pt reference = svcEntry->reference; reg = NULL; serviceReference_getServiceRegistration(reference, ®); if (reg != NULL) { @@ -345,30 +724,20 @@ celix_status_t topologyManager_exportScopeChanged(void *handle, char *filterStr) serviceRegistration_getProperties(reg, &props); status = filter_match(filter, props, &found); if (found) { - srvRefs[nrFound] = reference; - serviceReference_getProperty(reference, CELIX_FRAMEWORK_SERVICE_ID, &serviceId); - srvIds[nrFound++] = (char*)serviceId; + srvRefs[nrFound++] = reference; } } } - hashMapIterator_destroy(exportedServicesIterator); - if (nrFound > 0) { for (int i = 0; i < nrFound; i++) { // Question: can srvRefs become invalid meanwhile?? const char* export = NULL; - serviceReference_getProperty(srvRefs[i], (char *) OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &export); + serviceReference_getProperty(srvRefs[i], (char *) CELIX_RSA_SERVICE_EXPORTED_INTERFACES, &export); if (export) { - celix_status_t substatus = topologyManager_removeExportedService_nolock(manager, srvRefs[i], srvIds[i]); - - if (substatus != CELIX_SUCCESS) { - celix_logHelper_log(manager->loghelper, CELIX_LOG_LEVEL_ERROR, "TOPOLOGY_MANAGER: Removal of exported service (%s) failed.", srvIds[i]); - } else { - substatus = topologyManager_addExportedService_nolock(manager, srvRefs[i], srvIds[i]); - } - + topologyManager_removeExportedService_nolock(manager, srvRefs[i]); + celix_status_t substatus = topologyManager_addExportedService_nolock(manager, srvRefs[i]); if (substatus != CELIX_SUCCESS) { status = substatus; } @@ -376,12 +745,6 @@ celix_status_t topologyManager_exportScopeChanged(void *handle, char *filterStr) } } - free(srvRefs); - free(srvIds); - - // should unlock until here ?, avoid srvRefs[i] is released during topologyManager_removeExportedService - celixThreadMutex_unlock(&manager->lock); - return status; } @@ -439,11 +802,10 @@ static celix_status_t topologyManager_addImportedService_nolock(void *handle, en hashMap_put(manager->importedServices, endpoint, imports); if (scope_allowImport(manager->scope, endpoint)) { - int size = celix_arrayList_size(manager->rsaList); - - for (int iter = 0; iter < size; iter++) { + CELIX_LONG_HASH_MAP_ITERATE(manager->rsaMap, iter) { + celix_rsa_service_entry_t* rsaSvcEntry = iter.value.ptrValue; import_registration_t *import = NULL; - remote_service_admin_service_t *rsa = celix_arrayList_get(manager->rsaList, iter); + remote_service_admin_service_t *rsa = rsaSvcEntry->rsa; celix_status_t substatus = rsa->importService(rsa->admin, endpoint, &import); if (substatus == CELIX_SUCCESS) { hashMap_put(imports, rsa, import); @@ -523,7 +885,30 @@ celix_status_t topologyManager_removeImportedService(void *handle, endpoint_desc return status; } -static celix_status_t topologyManager_addExportedService_nolock(void * handle, service_reference_pt reference, void * service CELIX_UNUSED) { +static celix_exported_service_entry_t* exportedServiceEntry_create(topology_manager_t* tm, service_reference_pt reference) { + celix_autofree celix_exported_service_entry_t* svcEntry = calloc(1, sizeof(*svcEntry)); + if (svcEntry == NULL) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error allocating exported service entry."); + return NULL; + } + svcEntry->reference = reference; + celix_autoptr(celix_long_hash_map_t) registrations = svcEntry->registrations = celix_longHashMap_create(); + if (registrations == NULL) { + celix_logHelper_logTssErrors(tm->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error creating hash map for exported service registrations."); + return NULL; + } + celix_steal_ptr(registrations); + return celix_steal_ptr(svcEntry); +} + +static void exportedServiceEntry_destroy(celix_exported_service_entry_t* entry) { + celix_longHashMap_destroy(entry->registrations); + free(entry); + return; +} + +static celix_status_t topologyManager_addExportedService_nolock(void * handle, service_reference_pt reference) { topology_manager_pt manager = handle; celix_status_t status = CELIX_SUCCESS; long serviceId = serviceReference_getServiceId(reference); @@ -532,41 +917,66 @@ static celix_status_t topologyManager_addExportedService_nolock(void * handle, s celix_properties_t *serviceProperties = NULL; const char *export = NULL; - serviceReference_getProperty(reference, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &export); + serviceReference_getProperty(reference, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, &export); assert(export != NULL); celix_logHelper_log(manager->loghelper, CELIX_LOG_LEVEL_DEBUG, "TOPOLOGY_MANAGER: Add exported service (%li).", serviceId); scope_getExportProperties(manager->scope, reference, &serviceProperties); - hash_map_pt exports = hashMap_create(NULL, NULL, NULL, NULL); - assert(exports != NULL); - hashMap_put(manager->exportedServices, reference, exports); - int size = celix_arrayList_size(manager->rsaList); - - if (size == 0) { - celix_logHelper_log(manager->loghelper, CELIX_LOG_LEVEL_WARNING, "TOPOLOGY_MANAGER: No RSA available yet."); - } - - for (int iter = 0; iter < size; iter++) { - remote_service_admin_service_t *rsa = celix_arrayList_get(manager->rsaList, iter); + celix_exported_service_entry_t* svcEntry = exportedServiceEntry_create(manager, reference); + if (svcEntry == NULL) { + celix_logHelper_error(manager->loghelper, "TOPOLOGY_MANAGER: Error allocating exported service entry."); + return CELIX_ENOMEM; + } + status = celix_longHashMap_put(manager->exportedServices, serviceId, svcEntry); + if (status != CELIX_SUCCESS) { + exportedServiceEntry_destroy(svcEntry); + celix_logHelper_logTssErrors(manager->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(manager->loghelper, "TOPOLOGY_MANAGER: Error adding exported service entry to map."); + return status; + } - celix_array_list_t *endpoints = NULL; - celix_status_t substatus = rsa->exportService(rsa->admin, serviceIdStr, serviceProperties, &endpoints); + if (celix_longHashMap_size(manager->rsaMap) == 0) { + celix_logHelper_log(manager->loghelper, CELIX_LOG_LEVEL_WARNING, "TOPOLOGY_MANAGER: No RSA available yet."); + } - if (substatus == CELIX_SUCCESS) { - hashMap_put(exports, rsa, endpoints); - topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints); - } else { - status = substatus; - } + CELIX_LONG_HASH_MAP_ITERATE(manager->rsaMap, iter) { + long rsaSvcId = iter.key; + celix_rsa_service_entry_t* rsaSvcEntry = iter.value.ptrValue; + remote_service_admin_service_t *rsa = rsaSvcEntry->rsa; + + celix_autoptr(celix_array_list_t) registrationList = NULL; + celix_status_t substatus = rsa->exportService(rsa->admin, serviceIdStr, serviceProperties, ®istrationList); + if (substatus != CELIX_SUCCESS) { + status = substatus; + celix_logHelper_error(manager->loghelper, "TOPOLOGY_MANAGER: Error exporting service."); + continue; + } + substatus = celix_longHashMap_put(svcEntry->registrations, rsaSvcId, registrationList); + if (substatus != CELIX_SUCCESS) { + celix_logHelper_logTssErrors(manager->loghelper, CELIX_LOG_LEVEL_ERROR); + celix_logHelper_error(manager->loghelper, "TOPOLOGY_MANAGER: Error adding exported endpoints to map."); + for (int i = 0; i < celix_arrayList_size(registrationList); ++i) { + export_registration_t* reg = celix_arrayList_get(registrationList, i); + rsa->exportRegistration_close(rsa->admin, reg); + } + status = substatus; + continue; + } + if (rsaSvcEntry->dynamicIpSupport) { + topologyManager_addDynamicIpEndpointsForExportedService(manager, rsaSvcId, serviceId, registrationList); + } else { + topologyManager_notifyListenersEndpointAdded(manager, rsa, registrationList); + } + celix_steal_ptr(registrationList); } return status; } -celix_status_t topologyManager_addExportedService(void * handle, service_reference_pt reference, void * service) { +celix_status_t topologyManager_addExportedService(void * handle, service_reference_pt reference, void * service CELIX_UNUSED) { topology_manager_pt manager = handle; celix_status_t status = CELIX_SUCCESS; @@ -574,53 +984,52 @@ celix_status_t topologyManager_addExportedService(void * handle, service_referen celixThreadMutex_lock(&manager->lock); - status = topologyManager_addExportedService_nolock(handle, reference, service); + status = topologyManager_addExportedService_nolock(handle, reference); celixThreadMutex_unlock(&manager->lock); return status; } -static celix_status_t topologyManager_removeExportedService_nolock(void * handle, service_reference_pt reference, void * service CELIX_UNUSED) { +static void topologyManager_removeExportedService_nolock(void * handle, service_reference_pt reference) { topology_manager_pt manager = handle; - celix_status_t status = CELIX_SUCCESS; long serviceId = serviceReference_getServiceId(reference); celix_logHelper_log(manager->loghelper, CELIX_LOG_LEVEL_DEBUG, "TOPOLOGY_MANAGER: Remove exported service (%li).", serviceId); - hash_map_pt exports = hashMap_get(manager->exportedServices, reference); - if (exports) { - hash_map_iterator_pt iter = hashMapIterator_create(exports); - while (hashMapIterator_hasNext(iter)) { - hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); - remote_service_admin_service_t *rsa = hashMapEntry_getKey(entry); - celix_array_list_t *exportRegistrations = hashMap_remove(exports, rsa); - if (exportRegistrations != NULL) { - int size = celix_arrayList_size(exportRegistrations); - for (int exportsIter = 0; exportsIter < size; exportsIter++) { - export_registration_t *export = celix_arrayList_get(exportRegistrations, exportsIter); - topologyManager_notifyListenersEndpointRemoved(manager, rsa, export); - rsa->exportRegistration_close(rsa->admin, export); - } - celix_arrayList_destroy(exportRegistrations); - } - - hashMapIterator_destroy(iter); - iter = hashMapIterator_create(exports); + celix_exported_service_entry_t* svcEntry = celix_longHashMap_get(manager->exportedServices, serviceId); + if (svcEntry == NULL) { + celix_logHelper_debug(manager->loghelper, "TOPOLOGY_MANAGER: No exported service entry found for service id %li", serviceId); + return; + } - } - hashMapIterator_destroy(iter); - } - exports = hashMap_remove(manager->exportedServices, reference); + CELIX_LONG_HASH_MAP_ITERATE(svcEntry->registrations, iter) { + long rsaSvcId = iter.key; + celix_rsa_service_entry_t* rsaSvcEntry = celix_longHashMap_get(manager->rsaMap, rsaSvcId); + assert(rsaSvcEntry != NULL);//It must be not null, because the rsa will be removed from manager->exportedServices when rsa is removed + remote_service_admin_service_t* rsa = rsaSvcEntry->rsa; + + topologyManager_removeDynamicIpEndpointsForExportedService(manager, rsaSvcId, serviceId); + + celix_array_list_t *exportRegistrations = iter.value.ptrValue; + if (exportRegistrations != NULL) { + int size = celix_arrayList_size(exportRegistrations); + for (int exportsIter = 0; exportsIter < size; exportsIter++) { + export_registration_t *export = celix_arrayList_get(exportRegistrations, exportsIter); + topologyManager_notifyListenersEndpointRemoved(manager, rsa, export); + rsa->exportRegistration_close(rsa->admin, export); + } + celix_arrayList_destroy(exportRegistrations); + } + } - if (exports != NULL) { - hashMap_destroy(exports, false, false); - } + celix_longHashMap_remove(manager->exportedServices, serviceId); + exportedServiceEntry_destroy(svcEntry); - return status; + return; } -celix_status_t topologyManager_removeExportedService(void * handle, service_reference_pt reference, void * service) { +celix_status_t topologyManager_removeExportedService(void * handle, service_reference_pt reference, void * service CELIX_UNUSED) { topology_manager_pt manager = handle; celix_status_t status = CELIX_SUCCESS; @@ -628,7 +1037,7 @@ celix_status_t topologyManager_removeExportedService(void * handle, service_refe celixThreadMutex_lock(&manager->lock); - status = topologyManager_removeExportedService_nolock(handle, reference, service); + topologyManager_removeExportedService_nolock(handle, reference); celixThreadMutex_unlock(&manager->lock); @@ -659,6 +1068,27 @@ celix_status_t topologyManager_endpointListenerAdding(void* handle, service_refe return status; } +static void topologyManager_notifyDynamicIpEndpointsToListener(topology_manager_t* tm, endpoint_listener_t* listener, + char* scope, celix_filter_t* filter) { + CELIX_LONG_HASH_MAP_ITERATE(tm->dynamicIpEndpoints, iter) { + celix_long_hash_map_t* endpointMap = iter.value.ptrValue; + CELIX_LONG_HASH_MAP_ITERATE(endpointMap, iter2) { + celix_array_list_t* endpointList = (celix_array_list_t*)iter2.value.ptrValue; + int size = celix_arrayList_size(endpointList); + for (int i = 0; i < size; ++i) { + endpoint_description_t* endpoint = celix_arrayList_get(endpointList, i); + if (celix_filter_match(filter, endpoint->properties)) { + celix_status_t status = listener->endpointAdded(listener->handle, endpoint, scope); + if (status != CELIX_SUCCESS) { + celix_logHelper_error(tm->loghelper, "TOPOLOGY_MANAGER: Error adding endpoint to listener. %d", status); + } + } + } + } + } + return; +} + celix_status_t topologyManager_endpointListenerAdded(void* handle, service_reference_pt reference, void* service) { celix_status_t status = CELIX_SUCCESS; topology_manager_pt manager = handle; @@ -677,29 +1107,28 @@ celix_status_t topologyManager_endpointListenerAdded(void* handle, service_refer hashMap_put(manager->listenerList, reference, NULL); - serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + serviceReference_getProperty(reference, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, &scope); celix_autoptr(celix_filter_t) filter = celix_filter_create(scope); - hash_map_iterator_pt refIter = hashMapIterator_create(manager->exportedServices); - while (hashMapIterator_hasNext(refIter)) { - hash_map_pt rsaExports = hashMapIterator_nextValue(refIter); - hash_map_iterator_pt rsaIter = hashMapIterator_create(rsaExports); + CELIX_LONG_HASH_MAP_ITERATE(manager->exportedServices, iter) { + celix_exported_service_entry_t* svcEntry = iter.value.ptrValue; + CELIX_LONG_HASH_MAP_ITERATE(svcEntry->registrations, iter2) { + long rsaSvcId = iter2.key; + celix_rsa_service_entry_t* rsaSvcEntry = celix_longHashMap_get(manager->rsaMap, rsaSvcId); + celix_array_list_t *registrations = iter2.value.ptrValue; - while (hashMapIterator_hasNext(rsaIter)) { - hash_map_entry_pt entry = hashMapIterator_nextEntry(rsaIter); - remote_service_admin_service_t *rsa = hashMapEntry_getKey(entry); - celix_array_list_t *registrations = hashMapEntry_getValue(entry); + if (rsaSvcEntry->dynamicIpSupport) { + continue;//Dynamic ip endpoints are added later + } int arrayListSize = celix_arrayList_size(registrations); - int cnt = 0; - - for (; cnt < arrayListSize; cnt++) { + for (int cnt = 0; cnt < arrayListSize; cnt++) { export_registration_t *export = celix_arrayList_get(registrations, cnt); endpoint_description_t *endpoint = NULL; - status = topologyManager_getEndpointDescriptionForExportRegistration(rsa, export, &endpoint); + status = topologyManager_getEndpointDescriptionForExportRegistration(rsaSvcEntry->rsa, export, &endpoint); if (status == CELIX_SUCCESS) { bool matchResult = false; filter_match(filter, endpoint->properties, &matchResult); @@ -710,9 +1139,14 @@ celix_status_t topologyManager_endpointListenerAdded(void* handle, service_refer } } } - hashMapIterator_destroy(rsaIter); } - hashMapIterator_destroy(refIter); + + const char *interfaceSpecEndpointSupport = NULL; + serviceReference_getProperty(reference, CELIX_RSA_DISCOVERY_INTERFACE_SPECIFIC_ENDPOINTS_SUPPORT, &interfaceSpecEndpointSupport); + if (interfaceSpecEndpointSupport != NULL && strcmp(interfaceSpecEndpointSupport, "true") == 0) { + topologyManager_notifyDynamicIpEndpointsToListener(manager, (endpoint_listener_t *) service, (char *) scope, + filter); + } celixThreadMutex_unlock(&manager->lock); @@ -755,7 +1189,7 @@ static celix_status_t topologyManager_notifyListenersEndpointAdded(topology_mana endpoint_listener_t *epl = NULL; service_reference_pt reference = hashMapIterator_nextKey(iter); - serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + serviceReference_getProperty(reference, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, &scope); status = bundleContext_getService(manager->context, reference, (void **) &epl); if (status == CELIX_SUCCESS) { @@ -795,7 +1229,7 @@ static celix_status_t topologyManager_notifyListenersEndpointRemoved(topology_ma const char* scope = NULL; service_reference_pt reference = hashMapIterator_nextKey(iter); - serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + serviceReference_getProperty(reference, CELIX_RSA_ENDPOINT_LISTENER_SCOPE, &scope); substatus = bundleContext_getService(manager->context, reference, (void **) &epl); @@ -825,13 +1259,13 @@ static celix_status_t topologyManager_extendFilter(topology_manager_pt manager, return CELIX_BUNDLE_EXCEPTION; } - int len = 10 + strlen(filter) + strlen(OSGI_RSA_ENDPOINT_FRAMEWORK_UUID) + strlen(uuid); + int len = 10 + strlen(filter) + strlen(CELIX_RSA_ENDPOINT_FRAMEWORK_UUID) + strlen(uuid); *updatedFilter = malloc(len); if (!*updatedFilter) { return CELIX_ENOMEM; } - snprintf(*updatedFilter, len, "(&%s(!(%s=%s)))", filter, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + snprintf(*updatedFilter, len, "(&%s(!(%s=%s)))", filter, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); return status; } diff --git a/bundles/remote_services/topology_manager/src/topology_manager.h b/bundles/remote_services/topology_manager/src/topology_manager.h index 5c2cd9388..9c841750d 100644 --- a/bundles/remote_services/topology_manager/src/topology_manager.h +++ b/bundles/remote_services/topology_manager/src/topology_manager.h @@ -33,7 +33,6 @@ #include "celix_log_helper.h" #include "scope.h" -#define OSGI_RSA_REMOTE_SERVICE_ADMIN "remote_service_admin" typedef struct topology_manager topology_manager_t; typedef struct topology_manager *topology_manager_pt; diff --git a/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c index 8c1574e89..5a8029ae2 100644 --- a/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c +++ b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c @@ -73,14 +73,14 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context } char* scope = NULL; - int rc = asprintf(&scope, "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + int rc = asprintf(&scope, "(&(%s=*)(%s=%s))", CELIX_FRAMEWORK_SERVICE_NAME, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); status = rc < 0 ? CELIX_ENOMEM : CELIX_SUCCESS; celix_properties_t *props = NULL; if (status == CELIX_SUCCESS) { props = celix_properties_create(); celix_properties_set(props, "DISCOVERY", "true"); - celix_properties_set(props, (char *) OSGI_ENDPOINT_LISTENER_SCOPE, scope); + celix_properties_set(props, (char *) CELIX_RSA_ENDPOINT_LISTENER_SCOPE, scope); } if (status == CELIX_SUCCESS) { @@ -91,7 +91,7 @@ celix_status_t celix_bundleActivator_start(void * userData, celix_bundle_context endpointListener->endpointAdded = discovery_endpointAdded; endpointListener->endpointRemoved = discovery_endpointRemoved; - status = bundleContext_registerService(context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, endpointListener, props, &act->endpointListenerService); + status = bundleContext_registerService(context, (char *) CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, endpointListener, props, &act->endpointListenerService); if (status == CELIX_SUCCESS) { act->endpointListener = endpointListener; diff --git a/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp index d70bda87b..009f77af7 100644 --- a/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp +++ b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp @@ -90,7 +90,7 @@ extern "C" { rc = bundle_getContext(bundle, &context); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_getServiceReference(context, (char *)OSGI_RSA_REMOTE_SERVICE_ADMIN, &rsaRef); + rc = bundleContext_getServiceReference(context, (char *)CELIX_RSA_REMOTE_SERVICE_ADMIN, &rsaRef); EXPECT_EQ(CELIX_SUCCESS, rc); EXPECT_TRUE(rsaRef != NULL); @@ -185,7 +185,7 @@ extern "C" { EXPECT_EQ(celix_arrayList_size(bundles), 4); //rsa, calculator, topman, test bundle celix_arrayList_destroy(bundles); - rc = bundleContext_getServiceReference(context, (char *)OSGI_RSA_REMOTE_SERVICE_ADMIN, &rsaRef); + rc = bundleContext_getServiceReference(context, (char *)CELIX_RSA_REMOTE_SERVICE_ADMIN, &rsaRef); EXPECT_EQ(CELIX_SUCCESS, rc); EXPECT_TRUE(rsaRef != NULL); @@ -206,7 +206,7 @@ extern "C" { rc = bundleContext_getService(context, testRef, (void **)&testImport); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_getServiceReference(context, (char*)OSGI_ENDPOINT_LISTENER_SERVICE, &eplRef); + rc = bundleContext_getServiceReference(context, (char*) CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, &eplRef); EXPECT_EQ(CELIX_SUCCESS, rc); EXPECT_TRUE(eplRef != NULL); @@ -478,10 +478,10 @@ extern "C" { endpoint_description_t *endpoint = NULL; celix_properties_t *props = celix_properties_create(); - celix_properties_set(props, OSGI_RSA_ENDPOINT_SERVICE_ID, "42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); - celix_properties_set(props, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); + celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); + celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); celix_properties_set(props, "service.version", "1.0.0"); celix_properties_set(props, "zone", "a_zone"); @@ -530,10 +530,10 @@ extern "C" { endpoint_description_t *endpoint = NULL; celix_properties_t *props = celix_properties_create(); - celix_properties_set(props, OSGI_RSA_ENDPOINT_SERVICE_ID, "42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); - celix_properties_set(props, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); + celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); + celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); celix_properties_set(props, "service.version", "1.0.0"); celix_properties_set(props, "zone", "a_zone"); @@ -581,10 +581,10 @@ extern "C" { endpoint_description_t *endpoint = NULL; celix_properties_t *props = celix_properties_create(); - celix_properties_set(props, OSGI_RSA_ENDPOINT_SERVICE_ID, "42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); - celix_properties_set(props, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); + celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); + celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); celix_properties_set(props, "service.version", "1.0.0"); //TODO find out standard in osgi spec celix_properties_set(props, "zone", "a_zone"); @@ -627,10 +627,10 @@ extern "C" { endpoint_description_t *endpoint = NULL; celix_properties_t *props = celix_properties_create(); - celix_properties_set(props, OSGI_RSA_ENDPOINT_SERVICE_ID, "42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); - celix_properties_set(props, OSGI_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); - celix_properties_set(props, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); + celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_FRAMEWORK_UUID, "eec5404d-51d0-47ef-8d86-c825a8beda42"); + celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); + celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); celix_properties_set(props, "service.version", "1.0.0"); celix_properties_set(props, "zone", "a_zone"); diff --git a/examples/conan_test_package/my_rsa_activator.c b/examples/conan_test_package/my_rsa_activator.c index 8ba78934c..449b50604 100644 --- a/examples/conan_test_package/my_rsa_activator.c +++ b/examples/conan_test_package/my_rsa_activator.c @@ -56,7 +56,7 @@ static celix_status_t remoteServiceAdmin_getImportedEndpoints(remote_service_adm } static celix_status_t remoteServiceAdmin_importService(remote_service_admin_t *admin, endpoint_description_t *endpointDescription, import_registration_t **out) { - const char *importConfigs = celix_properties_get(endpointDescription->properties, OSGI_RSA_SERVICE_IMPORTED_CONFIGS, NULL); + const char *importConfigs = celix_properties_get(endpointDescription->properties, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, NULL); celix_logHelper_info(admin->loghelper, "%s called: %s\n", __FUNCTION__, importConfigs); return CELIX_ILLEGAL_ARGUMENT; } @@ -107,7 +107,7 @@ static celix_status_t my_rsa_start(my_remote_service_admin_activator_t* activato activator->adminService.importRegistration_getException = importRegistration_getException; activator->adminService.importRegistration_getImportReference = importRegistration_getImportReference; - activator->svcIdRsa = celix_bundleContext_registerService(ctx, &activator->adminService, OSGI_RSA_REMOTE_SERVICE_ADMIN, NULL); + activator->svcIdRsa = celix_bundleContext_registerService(ctx, &activator->adminService, CELIX_RSA_REMOTE_SERVICE_ADMIN, NULL); } return status; diff --git a/libs/error_injector/mdnsresponder/CMakeLists.txt b/libs/error_injector/mdnsresponder/CMakeLists.txt index 4360e5cae..91777945c 100644 --- a/libs/error_injector/mdnsresponder/CMakeLists.txt +++ b/libs/error_injector/mdnsresponder/CMakeLists.txt @@ -22,5 +22,5 @@ find_package(DNSSD) target_include_directories(mdnsresponder_ei PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) target_link_libraries(mdnsresponder_ei PUBLIC Celix::error_injector DNSSD::DNSSD) -target_link_options(mdnsresponder_ei INTERFACE LINKER:--wrap,DNSServiceCreateConnection LINKER:--wrap,DNSServiceProcessResult LINKER:--wrap,DNSServiceRegister LINKER:--wrap,TXTRecordSetValue LINKER:--wrap,DNSServiceBrowse) +target_link_options(mdnsresponder_ei INTERFACE LINKER:--wrap,DNSServiceCreateConnection LINKER:--wrap,DNSServiceProcessResult LINKER:--wrap,DNSServiceRegister LINKER:--wrap,TXTRecordSetValue LINKER:--wrap,DNSServiceBrowse LINKER:--wrap,DNSServiceResolve LINKER:--wrap,DNSServiceGetAddrInfo) add_library(Celix::mdnsresponder_ei ALIAS mdnsresponder_ei) diff --git a/libs/error_injector/mdnsresponder/include/mdnsresponder_ei.h b/libs/error_injector/mdnsresponder/include/mdnsresponder_ei.h index 30a542519..e072fde55 100644 --- a/libs/error_injector/mdnsresponder/include/mdnsresponder_ei.h +++ b/libs/error_injector/mdnsresponder/include/mdnsresponder_ei.h @@ -30,6 +30,8 @@ CELIX_EI_DECLARE(DNSServiceProcessResult, DNSServiceErrorType); CELIX_EI_DECLARE(DNSServiceRegister, DNSServiceErrorType); CELIX_EI_DECLARE(TXTRecordSetValue, DNSServiceErrorType); CELIX_EI_DECLARE(DNSServiceBrowse, DNSServiceErrorType); +CELIX_EI_DECLARE(DNSServiceResolve, DNSServiceErrorType); +CELIX_EI_DECLARE(DNSServiceGetAddrInfo, DNSServiceErrorType); #ifdef __cplusplus } diff --git a/libs/error_injector/mdnsresponder/src/mdnsresponder_ei.cc b/libs/error_injector/mdnsresponder/src/mdnsresponder_ei.cc index abdda5c5f..d542edca2 100644 --- a/libs/error_injector/mdnsresponder/src/mdnsresponder_ei.cc +++ b/libs/error_injector/mdnsresponder/src/mdnsresponder_ei.cc @@ -55,4 +55,20 @@ DNSServiceErrorType __wrap_DNSServiceBrowse(DNSServiceRef *__sdRef, DNSServiceFl CELIX_EI_IMPL(DNSServiceBrowse); return __real_DNSServiceBrowse(__sdRef, __flags, __interfaceIndex, __regtype, __domain, __callBack, __context); } + +DNSServiceErrorType __real_DNSServiceResolve(DNSServiceRef *sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char *name,const char *regtype,const char *domain,DNSServiceResolveReply callBack,void *context); +CELIX_EI_DEFINE(DNSServiceResolve, DNSServiceErrorType) +DNSServiceErrorType __wrap_DNSServiceResolve(DNSServiceRef *sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char *name,const char *regtype,const char *domain,DNSServiceResolveReply callBack,void *context) { + CELIX_EI_IMPL(DNSServiceResolve); + return __real_DNSServiceResolve(sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context); +} + +DNSServiceErrorType __real_DNSServiceGetAddrInfo(DNSServiceRef *sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceProtocol protocol,const char *hostname,DNSServiceGetAddrInfoReply callBack,void *context); +CELIX_EI_DEFINE(DNSServiceGetAddrInfo, DNSServiceErrorType) +DNSServiceErrorType __wrap_DNSServiceGetAddrInfo(DNSServiceRef *sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceProtocol protocol,const char *hostname,DNSServiceGetAddrInfoReply callBack,void *context) { + CELIX_EI_IMPL(DNSServiceGetAddrInfo); + return __real_DNSServiceGetAddrInfo(sdRef, flags, interfaceIndex, protocol, hostname, callBack, context); +} + + } \ No newline at end of file diff --git a/libs/framework/error_injector/CMakeLists.txt b/libs/framework/error_injector/CMakeLists.txt index 636a68539..229a383a8 100644 --- a/libs/framework/error_injector/CMakeLists.txt +++ b/libs/framework/error_injector/CMakeLists.txt @@ -16,4 +16,5 @@ # under the License. add_subdirectory(celix_bundle_ctx) -add_subdirectory(celix_bundle) \ No newline at end of file +add_subdirectory(celix_bundle) +add_subdirectory(celix_dm_component) \ No newline at end of file diff --git a/libs/framework/error_injector/celix_bundle_ctx/CMakeLists.txt b/libs/framework/error_injector/celix_bundle_ctx/CMakeLists.txt index 33873f032..4bf883232 100644 --- a/libs/framework/error_injector/celix_bundle_ctx/CMakeLists.txt +++ b/libs/framework/error_injector/celix_bundle_ctx/CMakeLists.txt @@ -31,5 +31,6 @@ target_link_options(bundle_ctx_ei INTERFACE LINKER:--wrap,celix_bundleContext_registerServiceAsync LINKER:--wrap,celix_bundleContext_registerServiceFactoryAsync LINKER:--wrap,celix_bundleContext_scheduleEvent + LINKER:--wrap,celix_bundleContext_getDependencyManager ) add_library(Celix::bundle_ctx_ei ALIAS bundle_ctx_ei) diff --git a/libs/framework/error_injector/celix_bundle_ctx/include/celix_bundle_context_ei.h b/libs/framework/error_injector/celix_bundle_ctx/include/celix_bundle_context_ei.h index 96be32d12..0af9a8f27 100644 --- a/libs/framework/error_injector/celix_bundle_ctx/include/celix_bundle_context_ei.h +++ b/libs/framework/error_injector/celix_bundle_ctx/include/celix_bundle_context_ei.h @@ -24,6 +24,7 @@ extern "C" { #endif #include "celix_error_injector.h" #include "celix_errno.h" +#include "celix_bundle_context.h" CELIX_EI_DECLARE(celix_bundleContext_getProperty, const char*); CELIX_EI_DECLARE(celix_bundleContext_registerServiceWithOptionsAsync, long); @@ -34,6 +35,7 @@ CELIX_EI_DECLARE(bundleContext_retainServiceReference, celix_status_t); CELIX_EI_DECLARE(celix_bundleContext_registerServiceAsync, long); CELIX_EI_DECLARE(celix_bundleContext_registerServiceFactoryAsync, long); CELIX_EI_DECLARE(celix_bundleContext_scheduleEvent, long); +CELIX_EI_DECLARE(celix_bundleContext_getDependencyManager, celix_dependency_manager_t*); #ifdef __cplusplus } diff --git a/libs/framework/error_injector/celix_bundle_ctx/src/celix_bundle_context_ei.cc b/libs/framework/error_injector/celix_bundle_ctx/src/celix_bundle_context_ei.cc index 6c465e327..5319214bf 100644 --- a/libs/framework/error_injector/celix_bundle_ctx/src/celix_bundle_context_ei.cc +++ b/libs/framework/error_injector/celix_bundle_ctx/src/celix_bundle_context_ei.cc @@ -102,4 +102,11 @@ long __wrap_celix_bundleContext_scheduleEvent(celix_bundle_context_t *__ctx, con return __real_celix_bundleContext_scheduleEvent(__ctx, __options); } +celix_dependency_manager_t* __real_celix_bundleContext_getDependencyManager(celix_bundle_context_t *__ctx); +CELIX_EI_DEFINE(celix_bundleContext_getDependencyManager, celix_dependency_manager_t*) +celix_dependency_manager_t* __wrap_celix_bundleContext_getDependencyManager(celix_bundle_context_t *__ctx) { + CELIX_EI_IMPL(celix_bundleContext_getDependencyManager); + return __real_celix_bundleContext_getDependencyManager(__ctx); +} + } \ No newline at end of file diff --git a/libs/framework/error_injector/celix_dm_component/CMakeLists.txt b/libs/framework/error_injector/celix_dm_component/CMakeLists.txt new file mode 100644 index 000000000..a1e1d5ccb --- /dev/null +++ b/libs/framework/error_injector/celix_dm_component/CMakeLists.txt @@ -0,0 +1,28 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +add_library(dm_component_ei STATIC src/celix_dm_component_ei.cc) + +target_include_directories(dm_component_ei PUBLIC include) +target_link_libraries(dm_component_ei PUBLIC Celix::error_injector) +target_link_libraries(dm_component_ei PRIVATE Celix::framework) + +target_link_options(dm_component_ei INTERFACE + LINKER:--wrap,celix_dmComponent_create + LINKER:--wrap,celix_dmServiceDependency_create + ) +add_library(Celix::dm_component_ei ALIAS dm_component_ei) diff --git a/libs/framework/error_injector/celix_dm_component/include/celix_dm_component_ei.h b/libs/framework/error_injector/celix_dm_component/include/celix_dm_component_ei.h new file mode 100644 index 000000000..22b9e5216 --- /dev/null +++ b/libs/framework/error_injector/celix_dm_component/include/celix_dm_component_ei.h @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef CELIX_CELIX_DM_COMPONENT_EI_H +#define CELIX_CELIX_DM_COMPONENT_EI_H +#ifdef __cplusplus +extern "C" { +#endif +#include "celix_error_injector.h" +#include "celix_dm_component.h" +#include "celix_dm_service_dependency.h" + +CELIX_EI_DECLARE(celix_dmComponent_create, celix_dm_component_t*); +CELIX_EI_DECLARE(celix_dmServiceDependency_create, celix_dm_service_dependency_t*); + +#ifdef __cplusplus +} +#endif + +#endif //CELIX_CELIX_DM_COMPONENT_EI_H diff --git a/libs/framework/error_injector/celix_dm_component/src/celix_dm_component_ei.cc b/libs/framework/error_injector/celix_dm_component/src/celix_dm_component_ei.cc new file mode 100644 index 000000000..cb5f9ca66 --- /dev/null +++ b/libs/framework/error_injector/celix_dm_component/src/celix_dm_component_ei.cc @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include "celix_dm_component_ei.h" +#include "celix_error_injector.h" + +extern "C" { + +celix_dm_component_t* __real_celix_dmComponent_create(bundle_context_t *context, const char* name); +CELIX_EI_DEFINE(celix_dmComponent_create, celix_dm_component_t*) +celix_dm_component_t* __wrap_celix_dmComponent_create(bundle_context_t *context, const char* name) { + CELIX_EI_IMPL(celix_dmComponent_create); + return __real_celix_dmComponent_create(context, name); +} + +celix_dm_service_dependency_t* __real_celix_dmServiceDependency_create(); +CELIX_EI_DEFINE(celix_dmServiceDependency_create, celix_dm_service_dependency_t*) +celix_dm_service_dependency_t* __wrap_celix_dmServiceDependency_create() { + CELIX_EI_IMPL(celix_dmServiceDependency_create); + return __real_celix_dmServiceDependency_create(); +} + +} \ No newline at end of file diff --git a/libs/framework/include/celix_dm_component.h b/libs/framework/include/celix_dm_component.h index 1c4a228fd..5154daef6 100644 --- a/libs/framework/include/celix_dm_component.h +++ b/libs/framework/include/celix_dm_component.h @@ -28,6 +28,7 @@ #include "celix_array_list.h" #include "celix_dm_info.h" #include "celix_framework_export.h" +#include "celix_cleanup.h" #ifdef __cplusplus extern "C" { @@ -86,6 +87,8 @@ CELIX_FRAMEWORK_EXPORT const char* celix_dmComponent_getUUID(celix_dm_component_ */ CELIX_FRAMEWORK_EXPORT void celix_dmComponent_destroy(celix_dm_component_t* cmp); +CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_dm_component_t, celix_dmComponent_destroy); + /** * Destroys a DM Component on the event thread. * Will call doneCallback (if not NULL) when done. diff --git a/libs/utils/error_injector/celix_properties/CMakeLists.txt b/libs/utils/error_injector/celix_properties/CMakeLists.txt index 2ddcf2fd0..60ae24b09 100644 --- a/libs/utils/error_injector/celix_properties/CMakeLists.txt +++ b/libs/utils/error_injector/celix_properties/CMakeLists.txt @@ -23,5 +23,6 @@ target_link_libraries(properties_ei PUBLIC Celix::error_injector Celix::utils) target_link_options(properties_ei INTERFACE LINKER:--wrap,celix_properties_create LINKER:--wrap,celix_properties_copy + LINKER:--wrap,celix_properties_set ) add_library(Celix::properties_ei ALIAS properties_ei) diff --git a/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h b/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h index fd4d1730e..cd94c140a 100644 --- a/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h +++ b/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h @@ -28,6 +28,7 @@ extern "C" { CELIX_EI_DECLARE(celix_properties_create, celix_properties_t*); CELIX_EI_DECLARE(celix_properties_copy, celix_properties_t*); +CELIX_EI_DECLARE(celix_properties_set, celix_status_t); #ifdef __cplusplus } diff --git a/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc b/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc index eea81d814..40b06000f 100644 --- a/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc +++ b/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc @@ -34,4 +34,11 @@ celix_properties_t *__wrap_celix_properties_copy(const celix_properties_t *prope return __real_celix_properties_copy(properties); } +celix_status_t __real_celix_properties_set(celix_properties_t *properties, const char *key, const char *value); +CELIX_EI_DEFINE(celix_properties_set, celix_status_t) +celix_status_t __wrap_celix_properties_set(celix_properties_t *properties, const char *key, const char *value) { + CELIX_EI_IMPL(celix_properties_set); + return __real_celix_properties_set(properties, key, value); +} + } \ No newline at end of file diff --git a/libs/utils/error_injector/celix_string_hash_map/include/celix_string_hash_map_ei.h b/libs/utils/error_injector/celix_string_hash_map/include/celix_string_hash_map_ei.h index ca45ff5bd..e0b3280b7 100644 --- a/libs/utils/error_injector/celix_string_hash_map/include/celix_string_hash_map_ei.h +++ b/libs/utils/error_injector/celix_string_hash_map/include/celix_string_hash_map_ei.h @@ -17,8 +17,8 @@ * under the License. */ -#ifndef CELIX_CELIX_LONG_HASH_MAP_EI_H -#define CELIX_CELIX_LONG_HASH_MAP_EI_H +#ifndef CELIX_CELIX_STRING_HASH_MAP_EI_H +#define CELIX_CELIX_STRING_HASH_MAP_EI_H #ifdef __cplusplus extern "C" { #endif @@ -41,4 +41,4 @@ CELIX_EI_DECLARE(celix_stringHashMap_putBool, celix_status_t); } #endif -#endif //CELIX_CELIX_LONG_HASH_MAP_EI_H +#endif //CELIX_CELIX_STRING_HASH_MAP_EI_H diff --git a/libs/utils/error_injector/celix_string_hash_map/src/celix_string_hash_map_ei.cc b/libs/utils/error_injector/celix_string_hash_map/src/celix_string_hash_map_ei.cc index b63417feb..3647dabc1 100644 --- a/libs/utils/error_injector/celix_string_hash_map/src/celix_string_hash_map_ei.cc +++ b/libs/utils/error_injector/celix_string_hash_map/src/celix_string_hash_map_ei.cc @@ -55,4 +55,11 @@ celix_status_t __wrap_celix_stringHashMap_putDouble(celix_string_hash_map_t* map return __real_celix_stringHashMap_putDouble(map, key, value); } +celix_status_t __real_celix_stringHashMap_putBool(celix_string_hash_map_t* map, long key, bool value); +CELIX_EI_DEFINE(celix_stringHashMap_putBool, celix_status_t) +celix_status_t __wrap_celix_stringHashMap_putBool(celix_string_hash_map_t* map, long key, bool value) { + CELIX_EI_IMPL(celix_stringHashMap_putBool); + return __real_celix_stringHashMap_putBool(map, key, value); +} + } \ No newline at end of file diff --git a/libs/utils/include/celix_errno.h b/libs/utils/include/celix_errno.h index e942afb05..8189192b3 100644 --- a/libs/utils/include/celix_errno.h +++ b/libs/utils/include/celix_errno.h @@ -124,7 +124,8 @@ CELIX_UTILS_EXPORT bool celix_utils_isCustomerStatusCode(celix_status_t code); #define CELIX_FACILITY_FRAMEWORK 1 /*! - * The facility of the http suppoter error code + * The facility of the http status error code + * @see https://en.wikipedia.org/wiki/List_of_HTTP_status_codes * */ #define CELIX_FACILITY_HTTP 2 @@ -135,6 +136,12 @@ CELIX_UTILS_EXPORT bool celix_utils_isCustomerStatusCode(celix_status_t code); */ #define CELIX_FACILITY_ZIP 3 +/*! + * The facility of the libcurl error code + * + */ +#define CELIX_FACILITY_CURL 4 + /*! * Make the error code accroding to the specification * \param fac Facility