From 8e995d10dcf6741960c2ea7633fcd2b5cc252870 Mon Sep 17 00:00:00 2001 From: Vitezslav Crhonek Date: Mon, 2 Dec 2013 16:11:08 +0100 Subject: Service: Support indications on instance property modification. --- src/service-dbus/CMakeLists.txt | 11 +- ...ServiceInstanceModificationIndicationProvider.c | 140 +++++++++++++++ src/service-dbus/util/serviceutil.c | 193 ++++++++++++++++++++- src/service-dbus/util/serviceutil.h | 20 +++ 4 files changed, 361 insertions(+), 3 deletions(-) create mode 100644 src/service-dbus/LMI_ServiceInstanceModificationIndicationProvider.c (limited to 'src/service-dbus') diff --git a/src/service-dbus/CMakeLists.txt b/src/service-dbus/CMakeLists.txt index 3cc2082..4ba3231 100644 --- a/src/service-dbus/CMakeLists.txt +++ b/src/service-dbus/CMakeLists.txt @@ -23,8 +23,15 @@ add_library(${LIBRARY_NAME} SHARED # Require libgio pkg_check_modules(GIO REQUIRED gio-2.0) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMPI_INCLUDE_DIR} ${GIO_INCLUDE_DIRS}) -target_link_libraries(${LIBRARY_NAME} openlmicommon ${KONKRETCMPI_LIBRARIES} ${GIO_LIBRARIES}) +include_directories(${CMAKE_CURRENT_BINARY_DIR} + ${CMPI_INCLUDE_DIR} + ${GIO_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/src/indmanager) +target_link_libraries(${LIBRARY_NAME} + openlmicommon + openlmiindmanager + ${KONKRETCMPI_LIBRARIES} + ${GIO_LIBRARIES}) # Create registration file cim_registration(${PROVIDER_NAME} ${LIBRARY_NAME} ${MOF} share/openlmi-providers) diff --git a/src/service-dbus/LMI_ServiceInstanceModificationIndicationProvider.c b/src/service-dbus/LMI_ServiceInstanceModificationIndicationProvider.c new file mode 100644 index 0000000..1b0edf4 --- /dev/null +++ b/src/service-dbus/LMI_ServiceInstanceModificationIndicationProvider.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Vitezslav Crhonek +*/ + +#include +#include "LMI_ServiceInstanceModificationIndication.h" + +#include "ind_manager.h" +#include "util/serviceutil.h" + +static const CMPIBroker* _cb = NULL; + +static const char* service_allowed_classes[] = { + LMI_Service_ClassName, + NULL}; + +static IMManager *im = NULL; +static IMError im_err = IM_ERR_OK; +static ServiceIndication si; + +static void LMI_ServiceInstanceModificationIndicationInitialize() +{ + im = im_create_manager(NULL, NULL, true, ind_watcher, + IM_IND_MODIFICATION, _cb, &im_err); + im_register_filter_classes(im, &service_allowed_classes[0], &im_err); +} + +static CMPIStatus LMI_ServiceInstanceModificationIndicationIndicationCleanup( + CMPIIndicationMI* mi, + const CMPIContext* cc, + CMPIBoolean term) +{ + if (!im_destroy_manager(im, cc, &im_err)) + CMReturn(CMPI_RC_ERR_FAILED); + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ServiceInstanceModificationIndicationAuthorizeFilter( + CMPIIndicationMI* mi, + const CMPIContext* cc, + const CMPISelectExp* se, + const char* ns, + const CMPIObjectPath* op, + const char* user) +{ + if (!im_verify_filter(im, se, cc, &im_err) ) + CMReturn(CMPI_RC_ERR_INVALID_QUERY); + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ServiceInstanceModificationIndicationMustPoll( + CMPIIndicationMI* mi, + const CMPIContext* cc, + const CMPISelectExp* se, + const char* ns, + const CMPIObjectPath* op) +{ + CMReturn(CMPI_RC_ERR_NOT_SUPPORTED); +} + +static CMPIStatus LMI_ServiceInstanceModificationIndicationActivateFilter( + CMPIIndicationMI* mi, + const CMPIContext* cc, + const CMPISelectExp* se, + const char* ns, + const CMPIObjectPath* op, + CMPIBoolean firstActivation) +{ + if (!im_verify_filter(im, se, cc, &im_err)) + CMReturn(CMPI_RC_ERR_INVALID_QUERY); + if (!im_add_filter(im, (CMPISelectExp*)se, cc, &im_err)) + CMReturn(CMPI_RC_ERR_FAILED); + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ServiceInstanceModificationIndicationDeActivateFilter( + CMPIIndicationMI* mi, + const CMPIContext* cc, + const CMPISelectExp* se, + const char* ns, + const CMPIObjectPath* op, + CMPIBoolean lastActivation) +{ + if (!im_remove_filter(im, se, cc, &im_err)) + CMReturn(CMPI_RC_ERR_FAILED); + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ServiceInstanceModificationIndicationEnableIndications( + CMPIIndicationMI* mi, + const CMPIContext* cc) +{ + char output[1024]; + + if (ind_init(&si, output, sizeof(output)) != 0) { + lmi_debug("ind_init failed: %s", output); + CMReturn(CMPI_RC_ERR_FAILED); + } + if (!im_start_ind(im, cc, &im_err)) + CMReturn(CMPI_RC_ERR_FAILED); + CMReturn(CMPI_RC_OK); +} + +static CMPIStatus LMI_ServiceInstanceModificationIndicationDisableIndications( + CMPIIndicationMI* mi, + const CMPIContext* cc) +{ + if (!im_stop_ind(im, cc, &im_err)) + CMReturn(CMPI_RC_ERR_FAILED); + ind_destroy(&si); + CMReturn(CMPI_RC_OK); +} + +CMIndicationMIStub( + LMI_ServiceInstanceModificationIndication, + LMI_ServiceInstanceModificationIndication, + _cb, + LMI_ServiceInstanceModificationIndicationInitialize()) + +KONKRET_REGISTRATION( + "root/cimv2", + "LMI_ServiceInstanceModificationIndication", + "LMI_ServiceInstanceModificationIndication", + "indication") diff --git a/src/service-dbus/util/serviceutil.c b/src/service-dbus/util/serviceutil.c index 50b18b9..eed0ad8 100644 --- a/src/service-dbus/util/serviceutil.c +++ b/src/service-dbus/util/serviceutil.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "serviceutil.h" @@ -346,3 +345,195 @@ unsigned int service_operation( g_object_unref(manager_proxy); return 0; } + +/* Indications */ + +pthread_mutex_t m; +pthread_cond_t c; + +void *loop_thread( + void *arg) +{ + ServiceIndication *si = (ServiceIndication *) arg; + + lmi_debug("loop_thread enter"); + + g_main_loop_run(si->loop); + + lmi_debug("loop_thread exit"); + + return NULL; +} + +static void on_signal( + GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + lmi_debug("on_signal enter, object_path: %s", g_dbus_proxy_get_object_path(proxy)); + + pthread_mutex_lock(&m); + pthread_cond_signal(&c); + pthread_mutex_unlock(&m); + + lmi_debug("on_signal exit"); +} + +int ind_init(ServiceIndication *si, char *output, int output_len) +{ + GVariant *result = NULL; + GError *error = NULL; + gchar *tmps = NULL; + int i = 0; + + lmi_debug("ind_init enter"); + + si->context = g_main_context_new(); + g_main_context_push_thread_default(si->context); + + si->loop = NULL; + + si->slist = service_find_all(output, output_len); + if (si->slist == NULL) { + g_main_context_unref(si->context); + return -1; + } + + si->manager_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, + NULL, MANAGER_NAME, MANAGER_OP, MANAGER_INTERFACE, NULL, &error); + if (!si->manager_proxy) { + strncpy(output, error->message, output_len); + g_error_free(error); + g_main_context_unref(si->context); + service_free_slist(si->slist); + return -1; + } + + si->signal_proxy = malloc(si->slist->cnt * sizeof(GDBusProxy *)); + if (!si->signal_proxy) { + strncpy(output, "Insufficient memory", output_len); + g_main_context_unref(si->context); + service_free_slist(si->slist); + return -1; + } + + for (i = 0; i < si->slist->cnt; i++) { + result = g_dbus_proxy_call_sync(si->manager_proxy, "LoadUnit", g_variant_new("(s)", si->slist->name[i]), + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (error) { + strncpy(output, error->message, output_len); + g_error_free(error); + ind_destroy(si); + return -1; + } + g_variant_get(result, "(&o)", &tmps); + + error = NULL; + si->signal_proxy[i] = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, + NULL, MANAGER_NAME, tmps, PROPERTY_INTERFACE, NULL, &error); + g_variant_unref(result); + if (si->signal_proxy[i] == NULL) + { + strncpy(output, error->message, output_len); + g_error_free(error); + ind_destroy(si); + return -1; + } + g_signal_connect(si->signal_proxy[i], "g-signal", G_CALLBACK(on_signal), NULL); + } + + error = NULL; + g_dbus_proxy_call_sync(si->manager_proxy, "Subscribe", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (error) { + strncpy(output, error->message, output_len); + g_error_free(error); + ind_destroy(si); + return -1; + } + + g_main_context_pop_thread_default(si->context); + + si->loop = g_main_loop_new(si->context, FALSE); + + if (pthread_create(&si->p, NULL, loop_thread, si) != 0) { + ind_destroy(si); + return -1; + } + + if (pthread_mutex_init(&m, NULL) != 0) { + strncpy(output, "pthread_mutex_init error", output_len); + return -1; + } + if (pthread_cond_init(&c, NULL) != 0) { + strncpy(output, "pthread_cond_init error", output_len); + return -1; + } + + lmi_debug("ind_init exit"); + + return 0; +} + +bool ind_watcher( + void **data) +{ + lmi_debug("ind_watcher enter"); + + pthread_mutex_lock(&m); + pthread_cond_wait(&c, &m); + pthread_mutex_unlock(&m); + + lmi_debug("ind_watcher exit"); + + return true; +} + +void ind_destroy(ServiceIndication *si) +{ + int i; + GError *error = NULL; + + lmi_debug("ind_destroy enter"); + + if (si->loop) { + g_main_loop_quit(si->loop); + if (pthread_join(si->p, NULL) != 0) { + lmi_debug("pthread_join error"); + } + g_main_loop_unref(si->loop); + } + + if (pthread_cond_destroy(&c) != 0) { + lmi_debug("pthread_cond_destroy error"); + } + if (pthread_mutex_destroy(&m) != 0) { + lmi_debug("pthread_mutex_destroy error"); + } + + g_main_context_unref(si->context); + + for (i = 0; i < si->slist->cnt; i++) { + if (si->signal_proxy[i]) { + g_object_unref(si->signal_proxy[i]); + } + } + free(si->signal_proxy); + + g_dbus_proxy_call_sync(si->manager_proxy, "Unsubscribe", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + if (error) { + lmi_debug("Unsubscribe error: %s", error->message); + g_error_free(error); + } + + g_object_unref(si->manager_proxy); + + service_free_slist(si->slist); + + lmi_debug("ind_destroy exit"); + + return; +} diff --git a/src/service-dbus/util/serviceutil.h b/src/service-dbus/util/serviceutil.h index fbdadad..9bb565c 100644 --- a/src/service-dbus/util/serviceutil.h +++ b/src/service-dbus/util/serviceutil.h @@ -23,7 +23,10 @@ #define SERVICEUTIL_H #include +#include +#include #include "openlmi.h" +#include "LMI_Service.h" #define ARRAY_SIZE(name) (sizeof(name) / sizeof(name[0])) @@ -62,4 +65,21 @@ int service_get_properties(Service *svc, const char *service, char *output, int unsigned int service_operation(const char *service, const char *method, char *output, int output_len); +/* Indications */ + +struct _ServiceIndication { + SList *slist; + GDBusProxy *manager_proxy; + GDBusProxy **signal_proxy; + GMainContext *context; + GMainLoop *loop; + pthread_t p; +}; + +typedef struct _ServiceIndication ServiceIndication; + +int ind_init(ServiceIndication *si, char *output, int output_len); +bool ind_watcher(void **data); +void ind_destroy(ServiceIndication *si); + #endif -- cgit