/* * 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: Roman Rakus */ #include "ind_manager.h" #include #include #include #include #include #include /* Debugging macros */ #define DEBUG(...) \ _im_debug(manager->broker, __FILE__, __func__, __LINE__, __VA_ARGS__) #include static inline void _im_debug(CMPIBroker *b, const char *file, const char *func, int line, const char *format, ...) { char text[2048] = ""; snprintf(text, 2047, "%s:%d(%s):", file, line, func); va_list args; va_start(args, format); vsnprintf(text+strlen(text), 2047-strlen(text), format, args); va_end(args); CMLogMessage(b, CMPI_DEV_DEBUG, "LMI indication manager", text, NULL); } // Get char * representation of name space from object path #define NS_STR_FROM_OP(op) CMGetCharPtr(CMGetNameSpace((op), NULL)) // Get char * representation of class name from object path #define CN_STR_FROM_OP(op) CMGetCharPtr(CMGetClassName((op), NULL)) typedef struct _IMPolledDiff { CMPIInstance *iold; CMPIInstance *inew; struct _IMPolledDiff *next; } IMPolledDiff; typedef struct _IMPolledDiffs { IMPolledDiff *first; } IMPolledDiffs; typedef enum _IMIDiff { IM_I_SAME, // Instances are the same IM_I_DIFFERENT, // Instances are different in key properties or value types IM_I_CHANGE // Instances are different in non-key properties } IMIDiff; IMIDiff compare_instances(CMPIInstance *, CMPIInstance *, IMManager *); /* For threading purposes */ pthread_t _t_manage; pthread_mutex_t _t_mutex; pthread_cond_t _t_cond; /* * Compare 2 object paths * return true if they are same, false otherwise * is using ft->toString() */ bool compare_objectpaths(CMPIObjectPath *op1, CMPIObjectPath *op2) { return (strcmp(CMGetCharsPtr(CMObjectPathToString(op1, NULL), NULL), CMGetCharsPtr(CMObjectPathToString(op2, NULL), NULL)) == 0); } /* * Compare 2 cmpi data * return true if they are the same, false otherwise * note: inspired by value.c:sfcb_comp_CMPIValue() from sblim-sfcb */ bool compare_values(CMPIValue *v1, CMPIValue *v2, CMPIType type, IMManager *manager) { if (!v1->array && !v2->array) { return true; } if (!v1->array || !v2->array) { // DEBUG("compare values: Null value/pointer of only one: %p %p", v1->array, v2->array); return false; } if (type & CMPI_ARRAY) { CMPICount c = CMGetArrayCount(v1->array, NULL); if (c != CMGetArrayCount(v2->array, NULL)) { // DEBUG("compare values: arrays with different counts"); return false; } while (c--) { CMPIValue val1 = CMGetArrayElementAt(v1->array, c-1, NULL).value; CMPIValue val2 = CMGetArrayElementAt(v2->array, c-1, NULL).value; if (!compare_values(&val1, &val2, type & ~CMPI_ARRAY, manager)) { // DEBUG("compare values: Any part of arrays differ"); return false; } } // DEBUG("compare values: arrays the same"); return true; } switch (type) { case CMPI_boolean: case CMPI_uint8: case CMPI_sint8: // DEBUG("compare values: bytes are same? %d %d", (int)v1->Byte, (int)v2->Byte); return (v1->Byte == v2->Byte); case CMPI_char16: case CMPI_uint16: case CMPI_sint16: // DEBUG("compare values: shorts are same? %d %d", (int)v1->Short, (int)v2->Short); return (v1->Short == v2->Short); case CMPI_uint32: case CMPI_sint32: // DEBUG("compare values: ints are same? %d %d", v1->Int, v2->Int); return (v1->Int == v2->Int); case CMPI_real32: // DEBUG("compare values: floats are same? %a %a", v1->Float, v2->Float); return (v1->Float == v2->Float); case CMPI_uint64: case CMPI_sint64: // DEBUG("compare values: longs are same? %ld %ld", v1->Long, v2->Long); return (v1->Long == v2->Long); case CMPI_real64: // DEBUG("compare values: doubles are same? %a %a", v1->Double, v2->Double); return(v1->Double == v2->Double); case CMPI_instance: // DEBUG("compare values: Instances are same?"); return (compare_instances(v1->inst, v2->inst, manager) == IM_I_SAME); case CMPI_ref: // DEBUG("compare values: references are same?"); return (compare_objectpaths(v1->ref, v2->ref)); case CMPI_string: // DEBUG("compare values: strings are same? %s %s", CMGetCharsPtr(v1->string, NULL), CMGetCharsPtr(v2->string, NULL)); return (strcmp(CMGetCharsPtr(v1->string, NULL), CMGetCharsPtr(v2->string, NULL)) == 0); case CMPI_dateTime: // DEBUG("compare values: dates are same? %s %s", CMGetCharsPtr(CMGetStringFormat(v1->dateTime, NULL), NULL), CMGetCharsPtr(CMGetStringFormat(v2->dateTime, NULL), NULL)); return (strcmp(CMGetCharsPtr( CMGetStringFormat(v1->dateTime, NULL), NULL), CMGetCharsPtr( CMGetStringFormat(v2->dateTime, NULL), NULL)) == 0); default: // DEBUG("compare values: returns default true"); return true; } return true; } /* * Compape 2 instances. * They can be same, different in key properties or different in non-key props */ IMIDiff compare_instances(CMPIInstance *i1, CMPIInstance *i2, IMManager *manager) { CMPIString *prop_name = NULL; // At first compare key properties. They will differ in most cases // Then compare non-key properties CMPIObjectPath *op1 = CMGetObjectPath(i1, NULL); CMPIObjectPath *op2 = CMGetObjectPath(i2, NULL); int pcount1 = CMGetKeyCount(op1, NULL); int pcount2 = CMGetKeyCount(op2, NULL); if (pcount1 != pcount2) { // They differ in count of key properties // DEBUG("compare instances: Different count of properties"); return IM_I_DIFFERENT; } int i; CMPIData data1, data2; // Check key properties one by one for (i = 0; i < pcount1; i++) { data1 = CMGetKeyAt(op1, i, &prop_name, NULL); data2 = CMGetKey(op2, CMGetCharsPtr(prop_name, NULL), NULL); // XXX - is state really CMPI_badValue? if (data2.state == CMPI_badValue || data1.type != data2.type || !compare_values(&data1.value, &data2.value, data1.type, manager)) { // DEBUG("compare instances: Differ in key properties"); return IM_I_DIFFERENT; } } // Check all properties one by one pcount1 = CMGetPropertyCount(i1, NULL); pcount2 = CMGetPropertyCount(i1, NULL); if (pcount1 != pcount2) { // DEBUG("compare instances: Differ in count of properties"); return IM_I_DIFFERENT; } for (i = 0; i < pcount1; i++) { data1 = CMGetPropertyAt(i1, i, &prop_name, NULL); data2 = CMGetProperty(i2, CMGetCharsPtr(prop_name, NULL), NULL); // XXX - is state really CMPI_badValue? if (data2.state == CMPI_badValue || data1.type != data2.type) { // DEBUG("compare instances: bad value or different types"); return IM_I_DIFFERENT; } else if (!compare_values(&data1.value, &data2.value, data1.type, manager)) { // DEBUG("compare instances: differs in this value"); return IM_I_CHANGE; } } // DEBUG("compare instances: They are the same"); return IM_I_SAME; } /* * Remove (free()) the first polled diff from diff list * returns nothing * Does not perform any checks */ void remove_diff(IMPolledDiffs *d) { IMPolledDiff *first = d->first; if (first) { d->first = first->next; free (first); } } /* * add instance pair to the list of diffs * First argument is diffs list. * Returns nothing */ void add_diff(IMPolledDiffs *d, CMPIInstance *newi, CMPIInstance *oldi) { IMPolledDiff *nd = malloc(sizeof(IMPolledDiff)); nd->inew = newi; nd->iold = oldi; nd->next = NULL; if (!d->first) { d->first = nd; } else { IMPolledDiff *last = d->first; while (last->next) last = last->next; last->next = nd; } } /* * Generate diffs based on polled enumerations. * Generated diff will contain: * - pair => there is a change * - old NULL and new value => new instance created * - old value and new NULL => instance deletion */ bool gen_diffs(IMManager *manager, IMPolledDiffs *d) { DEBUG("gen diffs called"); if (!manager || !manager->enums) { return false; } IMEnumerationPair *pair = manager->enums->first; while (pair) { // DEBUG("gen diffs - next pair"); CMPIArray *penum = pair->prev_enum; CMPIArray *tenum = pair->this_enum; if (penum && tenum) { int pcount = CMGetArrayCount(penum, NULL); int tcount = CMGetArrayCount(tenum, NULL); bool p_used[pcount], t_used[tcount]; bzero(p_used, pcount); bzero(t_used, tcount); int pi = 0, ti = 0; CMPIInstance *newi = NULL; CMPIInstance *oldi = NULL; bool do_compare = true; for (pi = 0; pi < pcount; pi++) { DEBUG("gen diffs - outer for: pi=%d, ti=%d, pcount=%d, tcount=%d\n", pi, ti, pcount, tcount); oldi = CMGetArrayElementAt(penum, pi, NULL).value.inst; do_compare = true; for (ti = 0; ti < tcount && do_compare; ti++) { if (t_used[ti] == true) continue; DEBUG("gen diffs - inner for: pi=%d, ti=%d, pcount=%d, tcount=%d\n", pi, ti, pcount, tcount); newi = CMGetArrayElementAt(tenum, ti, NULL).value.inst; // XXX are them really in same order, on the same index? // DEBUG("gen diffs - comparing instances"); // DEBUG("gen diffs - oldi: %s", CMGetCharsPtr(CDToString(manager->broker, oldi, NULL), NULL)); // DEBUG("gen diffs - newi: %s", CMGetCharsPtr(CDToString(manager->broker, newi, NULL), NULL)); switch (compare_instances(oldi, newi, manager)) { case IM_I_SAME: DEBUG("gen diffs - same instances"); do_compare = false; t_used[ti] = true; p_used[pi] = true; break; case IM_I_CHANGE: DEBUG("gen diffs - change in instances"); if (manager->type == IM_IND_MODIFICATION) add_diff(d, newi, oldi); do_compare = false; t_used[ti] = true; p_used[pi] = true; break; case IM_I_DIFFERENT: DEBUG("gen diffs - different instances"); default: break; } } // DEBUG("gen diffs - after inner for: pi=%d, ti=%d, pcount=%d, tcount=%d\n", pi, ti, pcount, tcount); } DEBUG("gen diffs - So now do the sum"); if (manager->type == IM_IND_DELETION) { for (pi = 0; pi < pcount; pi++) { if (p_used[pi] == false) { add_diff(d, NULL, CMGetArrayElementAt(penum, pi, NULL).value.inst); // DEBUG("gen diffs - %d at old instances wasn't used: %s", pi, CMGetCharsPtr(CDToString(manager->broker, CMGetArrayElementAt(penum, pi, NULL).value.inst, NULL), NULL)); } } } if (manager->type == IM_IND_CREATION) { for (ti = 0; ti < tcount; ti++) { if (t_used[ti] == false) { add_diff(d, CMGetArrayElementAt(tenum, ti, NULL).value.inst, NULL); // DEBUG("gen diffs - %d at new instances wasn't used: %s", ti, CMGetCharsPtr(CDToString(manager->broker, CMGetArrayElementAt(tenum, ti, NULL).value.inst, NULL), NULL)); } } } } pair = pair->next; } DEBUG("gen diffs returning true"); return true; } /* helper functions */ /* * Extract object path from select expression * returns match for the first occurence of ISA operator */ CMPIObjectPath *get_object_path(CMPIBroker *broker, CMPISelectExp *se) { CMPISelectCond *sc = CMGetDoc(se, NULL); CMPICount scount = CMGetSubCondCountAndType(sc,NULL,NULL); unsigned int i, j; for (i = 0; i < scount; i++) { CMPISubCond *subcond = CMGetSubCondAt(sc,i,NULL); CMPICount pcount = CMGetPredicateCount(subcond,NULL); for (j = 0; j < pcount; j++) { CMPIPredicate *pred = CMGetPredicateAt(subcond,j,NULL); CMPIType type; CMPIPredOp op; CMPIString *lhs=NULL; CMPIString *rhs=NULL; CMGetPredicateData(pred,&type,&op,&lhs,&rhs); if (op == CMPI_PredOp_Isa) { return CMNewObjectPath(broker, "root/cimv2", CMGetCharsPtr(rhs, NULL), NULL); } } } return NULL; } // compare 2 object paths, return true when equal, false if not // equality is set by comparing class names and object paths bool equal_ops(CMPIObjectPath *op1, CMPIObjectPath *op2) { return (strcmp(NS_STR_FROM_OP(op1), NS_STR_FROM_OP(op2)) == 0 && strcmp(CN_STR_FROM_OP(op1), CN_STR_FROM_OP(op2)) == 0); } // Create new IMEnumerationPair filled with instances from given object path IMEnumerationPair *new_IMEnumerationPair(IMManager *manager, CMPIObjectPath *op, bool is_first_poll) { CMPIEnumeration *aux_e = CBEnumInstances(manager->broker, manager->context2, op, NULL, NULL); if (!aux_e) { return NULL; } CMPIArray *new_e = CMClone(CMToArray(aux_e, NULL), NULL); CMPIArray *new_e2 = is_first_poll ? CMClone(new_e, NULL) : NULL; IMEnumerationPair *new_ime = malloc(sizeof(IMEnumerationPair)); new_ime->this_enum = new_e; new_ime->prev_enum = new_e2; new_ime->next = NULL; new_ime->op = op; return new_ime; } // retrieve enumeration on given object path and add it to the end of list bool add_enumeration(IMManager *manager, CMPIObjectPath *op, bool is_first_poll) { if (!manager || !op) { return false; } if (!manager->enums) { manager->enums = malloc(sizeof(IMEnumerations)); manager->enums->first = NULL; } IMEnumerationPair *e = manager->enums->first; IMEnumerationPair *last = NULL; while (e) { // find last enumeration last = e; e = e->next; } IMEnumerationPair *new_ime = new_IMEnumerationPair(manager, op, is_first_poll); if (!new_ime) { return false; } if (!last) { // there isn't any enumeration yet manager->enums->first = new_ime; } else { last->next = new_ime; } return true; } // Pair enumerations. This enum will become prev enum and new this enum // will be created by new obtained by object path bool pair_enumeration(IMManager *manager, IMEnumerationPair *found, CMPIObjectPath *op) { CMPIEnumeration *aux_e = CBEnumInstances(manager->broker, manager->context2, op, NULL, NULL); if (!aux_e) { return false; } CMPIArray *new_e = CMClone(CMToArray(aux_e, NULL), NULL); if (found->prev_enum) { CMRelease(found->prev_enum); } found->prev_enum = found->this_enum; found->this_enum = new_e; return true; } // return the first enumeration pair that has the same namespace and class name // in object path. Return NULL if there isn't any. IMEnumerationPair *find_enum_by_op(IMEnumerations *enums, CMPIObjectPath *op) { if (!enums) { return NULL; } IMEnumerationPair *ime = enums->first; while (ime) { if (equal_ops(op, ime->op)) { return ime; } ime = ime->next; } return NULL; } bool _im_poll(IMManager *manager, bool is_first_poll, IMError *err) { DEBUG("IM poll called"); if (!manager) { *err = IM_ERR_MANAGER; return false; } if (!manager->filters) { // Nothing to poll DEBUG("IM poll nothing to poll"); return true; } IMFilter *filter = NULL; // go thru all filters and (try to) get object path from each one // Use object path to enumerate instances // Filter out duplicates DEBUG("IM poll will go thru all filters"); for (filter = manager->filters->first; filter; filter = filter->next) { DEBUG("IM poll next filter"); CMPIObjectPath *op = get_object_path(manager->broker, filter->select_exp); DEBUG("IM poll - got OP: %s", CMGetCharsPtr(CDToString(manager->broker, op, NULL), NULL)); IMEnumerationPair *found = find_enum_by_op(manager->enums, op); if (!found) { DEBUG("IM poll will add enum, first poll? %d", is_first_poll); add_enumeration(manager, op, is_first_poll); } else { DEBUG("IM poll will pair enum"); pair_enumeration(manager, found, op); } } DEBUG("IM poll returning true"); return true; } /* * Fill ind_inst with properties and send it */ bool send_creation_indication(CMPIInstance *ind_inst, CMPIInstance *new_inst, IMManager *manager) { DEBUG("Instance creation indication to be send"); if (!manager || !ind_inst || !new_inst) { return false; } CMPIObjectPath *ind_op = CMGetObjectPath(ind_inst, NULL); const char *ns = CMGetCharsPtr(CMGetNameSpace(ind_op, NULL), NULL); #if 0 //TODO - choose which to use CBSetProperty(manager->broker, manager->context2, ind_op, "SourceInstance", new_inst, CMPI_instance); #else CMSetProperty(ind_inst, "SourceInstance", &new_inst, CMPI_instance); #endif CBDeliverIndication(manager->broker, manager->context2, ns, ind_inst); return true; } /* * Fill ind_inst with properties and send it */ bool send_deletion_indication(CMPIInstance *ind_inst, CMPIInstance *old_inst, IMManager *manager) { DEBUG("Instance deletion indication to be send"); if (!manager || !ind_inst || !old_inst) { return false; } CMPIObjectPath *ind_op = CMGetObjectPath(ind_inst, NULL); const char *ns = CMGetCharsPtr(CMGetNameSpace(ind_op, NULL), NULL); CBSetProperty(manager->broker, manager->context2, ind_op, "SourceInstance", old_inst, CMPI_instance); CBDeliverIndication(manager->broker, manager->context2, ns, ind_inst); return true; } /* * Fill ind_inst with properties and send it */ bool send_modification_indication(CMPIInstance *ind_inst, CMPIInstance *new, CMPIInstance *old, IMManager *manager) { DEBUG("Instance modification indication to be send"); if (!manager || !ind_inst || !new || !old) { return false; } CMPIObjectPath *ind_op = CMGetObjectPath(ind_inst, NULL); const char *ns = CMGetCharsPtr(CMGetNameSpace(ind_op, NULL), NULL); CBSetProperty(manager->broker, manager->context2, ind_op, "SourceInstance", new, CMPI_instance); CBSetProperty(manager->broker, manager->context2, ind_op, "PreviousInstance", old, CMPI_instance); CBDeliverIndication(manager->broker, manager->context2, ns, ind_inst); return true; } /* * Will extract class name from select expression * example: SELECT * FROM LMI_AccountInstCreationIndication WHERE ... * will return LMI_AccountInstCreationIndication * returns NULL when not found or on error * Caller has to free memory. */ char *get_classname(CMPISelectExp *se) { if (!se) { return NULL; } char *select = (char*)CMGetCharsPtr(CMGetSelExpString(se, NULL), NULL); char *after_from = strcasestr(select, "from") + strlen("from"); char *start = after_from + strspn(after_from, " "); char *end = index(start,' '); char *cname = malloc(end-start+1); bzero(cname, end-start+1); return memcpy(cname, start, end-start); } /* * Main send indication function. Will decide by type of indication what * to send. * Returns true when everything is OK. False otherwise. */ bool send_indication(CMPIInstance *old, CMPIInstance *new, IMManager *manager) { if (!manager) { return false; } char *cname = get_classname(manager->filters->first->select_exp); CMPIObjectPath *op = CMNewObjectPath( manager->broker, CMGetCharsPtr(CMGetNameSpace(manager->enums->first->op, NULL), NULL), cname, NULL); free(cname); DEBUG("Will send indication with this OP: %s", CMGetCharsPtr(CDToString(manager->broker, op, NULL), NULL)); CMPIInstance *ind_inst = CMNewInstance(manager->broker, op, NULL); DEBUG("Will send indication with this instance): %s", CMGetCharsPtr(CDToString(manager->broker, ind_inst, NULL), NULL), NULL); DEBUG("Old instance: %p - %s", old, CMGetCharsPtr(CDToString(manager->broker, old, NULL), NULL), NULL); DEBUG("New instance: %p - %s", new, CMGetCharsPtr(CDToString(manager->broker, new, NULL), NULL), NULL); switch (manager->type) { case IM_IND_CREATION: if (!new) { return false; } send_creation_indication(ind_inst, new, manager); break; case IM_IND_DELETION: if (!old) { return false; } send_deletion_indication(ind_inst, old, manager); break; case IM_IND_MODIFICATION: if (!old || !new) { return false; } send_modification_indication(ind_inst, new, old, manager); break; } return true; } /* * Run in separate thread */ static void *manage(void *data) { //TODO - make this thread's cancel state and type more specific? // Set the type to PTHREAD_CANCEL_ASYNCHRONOUS? // Switch Enable/Disable state on some places? IMManager *manager = (IMManager *)data; IMError err = IM_ERR_OK; // TODO - How to handle potential errors? bool is_first_poll = true; DEBUG("manage thread started"); #if 0 if (manager->polling) { pthread_mutex_lock(&_t_mutex); if(!_im_poll(manager, &err)) { // make the first poll pthread_mutex_unlock(&_t_mutex); return (void *)err; } pthread_mutex_unlock(&_t_mutex); } #endif IMPolledDiffs diffs = {NULL}; CMPIInstance *iold = NULL, *inew = NULL; DEBUG("manage thread - attaching thread, context2 = %p", manager->context2); CBAttachThread(manager->broker, manager->context2); while (1) { DEBUG("manage thread in infinite loop"); // wait until manager is running pthread_mutex_lock(&_t_mutex); while (!manager->running) { DEBUG("manage thread waiting to indication start"); pthread_cond_wait(&_t_cond, &_t_mutex); } if (manager->polling && is_first_poll) { if (!_im_poll(manager, is_first_poll, &err)) { pthread_mutex_unlock(&_t_mutex); return (void *)err; } is_first_poll = false; } pthread_mutex_unlock(&_t_mutex); DEBUG("manage thread calling spawner"); if(!manager->spawner(manager->data)) { continue; } pthread_mutex_lock(&_t_mutex); if (manager->polling) { // poll enumerations if (!_im_poll(manager, false, &err)) { pthread_mutex_unlock(&_t_mutex); return (void *)err; } // create list of diffs gen_diffs(manager, &diffs); manager->data = &diffs; } DEBUG("manage thread calling gather"); while (manager->gather(&iold, &inew, manager->data)) { send_indication(iold, inew, manager); } pthread_mutex_unlock(&_t_mutex); } } /* * Default gather function using polling * It is going thru all polled instances. If there is some pair (previous enum * and this enum) */ static bool default_gather (CMPIInstance **old_inst, CMPIInstance **new_inst, void* data) { // passed data is a list of diffs // It is going to be called in loop // return true if now we are going to create indication // return false if there will be no indication and loop will break IMPolledDiffs *diffs = (IMPolledDiffs *) data; if (diffs->first) { *new_inst = diffs->first->inew; *old_inst = diffs->first->iold; remove_diff(diffs); return true; } return false; } /* * Remove every polled enums * true if ok, false if not */ static bool remove_all_enums(IMManager *manager, IMError *err) { if (!manager->enums) { return true; } IMEnumerationPair *current = manager->enums->first; IMEnumerationPair *next = NULL; while (current) { next = current->next; CMRelease(current->prev_enum); CMRelease(current->this_enum); CMRelease(current->op); free(current); current = next; } free(manager->enums); manager->enums = NULL; return true; } /* * true if ok * false if not */ static bool remove_all_filters(IMManager *manager, IMError *err) { if (!manager->filters) { pthread_mutex_unlock(&_t_mutex); return true; } IMFilter *current = manager->filters->first; IMFilter *next = NULL; while (current) { next = current->next; CMRelease(current->select_exp); free(current); current = next; } free(manager->filters); manager->filters = NULL; return true; } IMManager* im_create_manager(IMInstGather gather, IMFilterChecker f_checker, bool polling, IMEventSpawner spawner, IMIndType type, CMPIBroker *broker, IMError *err) { if ((!polling && !gather) || (polling && gather) ) { *err = IM_ERR_GATHER; return NULL; } if (!f_checker) { *err = IM_ERR_FILTER_CHECKER; return NULL; } if (!spawner) { *err = IM_ERR_SPAWNER; return NULL; } if (!broker) { *err = IM_ERR_BROKER; return NULL; } IMManager* manager = malloc(sizeof(IMManager)); if (!manager) { *err = IM_ERR_MALLOC; return NULL; } manager->type = type; manager->gather = gather ? gather : default_gather; manager->spawner = spawner; manager->filters = NULL; manager->running = false; manager->polling = polling; manager->broker = broker; manager->f_checker = f_checker; manager->enums = NULL; manager->context = NULL; manager->context2 = NULL; DEBUG("Manager created"); if (pthread_mutex_init(&_t_mutex, NULL) || pthread_cond_init(&_t_cond, NULL)) { *err = IM_ERR_THREAD; free(manager); return NULL; } return manager; } bool im_destroy_manager(IMManager *manager, const CMPIContext *ctx, IMError *err) { if (!manager) { *err = IM_ERR_MANAGER; return false; } if (!ctx) { *err = IM_ERR_CONTEXT; return false; } pthread_mutex_lock(&_t_mutex); manager->context = ctx; if (!im_stop_ind(manager, ctx, err)) { pthread_mutex_unlock(&_t_mutex); return false; } if (!remove_all_filters(manager, err)) { pthread_mutex_unlock(&_t_mutex); return false; } if (!remove_all_enums(manager, err)) { pthread_mutex_unlock(&_t_mutex); return false; } if (pthread_cancel(_t_manage)) { *err = IM_ERR_THREAD; pthread_mutex_unlock(&_t_mutex); return false; } pthread_mutex_unlock(&_t_mutex); DEBUG("Destroying manager"); if (pthread_mutex_destroy(&_t_mutex)) { *err = IM_ERR_THREAD; return false; } free(manager); return true; } bool im_verify_filter(IMManager *manager, const CMPISelectExp *filter, const CMPIContext *ctx, IMError *err) { if (!manager) { *err = IM_ERR_MANAGER; return NULL; } if (!ctx) { *err = IM_ERR_CONTEXT; } if (!filter) { *err = IM_ERR_FILTER; return NULL; } manager->context = ctx; DEBUG("Verifying filter. Manager = %p, filter checker = %p", manager, manager->f_checker); return manager->f_checker(filter); } bool im_add_filter(IMManager *manager, CMPISelectExp *filter, const CMPIContext *ctx, IMError *err) { pthread_mutex_lock(&_t_mutex); if (!manager) { *err = IM_ERR_MANAGER; pthread_mutex_unlock(&_t_mutex); return false; } if (!ctx) { *err = IM_ERR_CONTEXT; pthread_mutex_unlock(&_t_mutex); return false; } if (!filter) { *err = IM_ERR_FILTER; pthread_mutex_unlock(&_t_mutex); return false; } manager->context = ctx; DEBUG("Adding filter"); if (manager->filters) { DEBUG("There are some filters, adding to the list"); IMFilter *current = manager->filters->first; while (current->next) { current = current->next; } IMFilter *next = malloc(sizeof(IMFilter)); if (!next) { *err = IM_ERR_MALLOC; pthread_mutex_unlock(&_t_mutex); return false; } next->next = NULL; next->select_exp = filter; current->next = next; } else { DEBUG("There isn't any filter, creating new list"); IMFilters *filters = malloc(sizeof(IMFilters)); if (!filters) { *err = IM_ERR_MALLOC; pthread_mutex_unlock(&_t_mutex); return false; } IMFilter *next = malloc(sizeof(IMFilter)); if (!next) { *err = IM_ERR_MALLOC; free(filters); pthread_mutex_unlock(&_t_mutex); return false; } filters->first = next; next->next = NULL; next->select_exp = filter; manager->filters = filters; } pthread_mutex_unlock(&_t_mutex); return true; } bool im_remove_filter(IMManager *manager, const CMPISelectExp *filter, const CMPIContext *ctx, IMError *err) { // TODO - maybe remove polled instances (?) if (!manager) { *err = IM_ERR_MANAGER; return false; } if (!ctx) { *err = IM_ERR_CONTEXT; return false; } if (!filter) { *err = IM_ERR_FILTER; return false; } pthread_mutex_lock(&_t_mutex); if (!manager->filters) { pthread_mutex_unlock(&_t_mutex); *err = IM_ERR_NOT_FOUND; return false; } manager->context = ctx; DEBUG("Removing filter"); IMFilter *current = manager->filters->first; IMFilter *prev = NULL; while (current) { if (strcmp(CMGetCharsPtr(CMGetSelExpString(current->select_exp, NULL), NULL), CMGetCharsPtr(CMGetSelExpString(filter, NULL), NULL)) == 0) { // This one we want to remove CMRelease(current->select_exp); if (prev) { prev->next = current->next; } else { manager->filters->first = current->next; } free(current); pthread_mutex_unlock(&_t_mutex); return true; } prev = current; current = current->next; } *err = IM_ERR_NOT_FOUND; pthread_mutex_unlock(&_t_mutex); return false; } // start indications bool im_start_ind(IMManager *manager, const CMPIContext *ctx, IMError *err) { //TODO - threading //TODO - Here only send thread signal if (!manager) { *err = IM_ERR_MANAGER; return false; } if (!ctx) { *err = IM_ERR_CONTEXT; return false; } manager->context = ctx; manager->context2 = CBPrepareAttachThread(manager->broker, manager->context); DEBUG("Creating second thread"); if (pthread_create(&_t_manage, NULL, manage, manager)) { *err = IM_ERR_THREAD; return false; } DEBUG("Starting indications"); manager->running = true; pthread_cond_signal(&_t_cond); return true; } // stop indications bool im_stop_ind(IMManager *manager, const CMPIContext *ctx, IMError *err) { //TODO - threading if (!manager) { *err = IM_ERR_MANAGER; return false; } if (!ctx) { *err = IM_ERR_CONTEXT; return false; } manager->context = ctx; DEBUG("Stopping indications"); manager->running = false; return true; }