void cerebrod_event_update_node_received_time(struct cerebrod_node_data *nd, u_int32_t received_time) { struct cerebrod_event_node_timeout *ntd; #if CEREBRO_DEBUG int rv; #endif /* CEREBRO_DEBUG */ assert(nd); assert(received_time); if (!event_index) return; #if CEREBRO_DEBUG /* Should be called with lock already set */ rv = Pthread_mutex_trylock(&nd->node_data_lock); if (rv != EBUSY) CEREBROD_EXIT(("mutex not locked: rv=%d", rv)); #endif /* CEREBRO_DEBUG */ Pthread_mutex_lock(&event_node_timeout_data_lock); if ((ntd = Hash_find(event_node_timeout_data_index, nd->nodename))) { ntd->last_received_time = received_time; ntd->timeout_occurred = 0; } Pthread_mutex_unlock(&event_node_timeout_data_lock); }
/* * _hostrange_output * * Output metric data in hostrange format. The algorithm involves * using the metric_value as a hash key. Each hash item will then * store the hosts with the same metric_value/key. */ static void _hostrange_output(List l) { #if CEREBRO_DEBUG const char *func = __FUNCTION__; #endif /* CEREBRO_DEBUG */ struct node_metric_data *data = NULL; ListIterator litr = NULL; unsigned int count; hash_t h; assert(l); count = List_count(l); #if CEREBRO_DEBUG if (!count) err_exit("%s: invalid count", func); #endif /* CEREBRO_DEBUG */ h = Hash_create(count, (hash_key_f)hash_key_string, (hash_cmp_f)strcmp, (hash_del_f)_hostrange_data_destroy); litr = List_iterator_create(l); while ((data = list_next(litr))) { char buf[CEREBRO_STAT_BUFLEN]; struct hostrange_data *hd; _metric_value_str(data->metric_value_type, data->metric_value_len, data->metric_value, buf, CEREBRO_STAT_BUFLEN); if (!(hd = Hash_find(h, buf))) { hd = Malloc(sizeof(struct hostrange_data)); hd->hl = Hostlist_create(NULL); hd->key = Strdup(buf); Hash_insert(h, hd->key, hd); } Hostlist_push(hd->hl, data->nodename); } Hash_for_each(h, _hostrange_output_data, NULL); /* No need to destroy list iterator, caller will destroy List */ Hash_destroy(h); }
/* * cerebrod_monitor_modules_update * * Send metric data to the appropriate monitor modules, if necessary. * The struct cerebrod_node_data lock should already be locked. */ void cerebrod_monitor_modules_update(const char *nodename, struct cerebrod_node_data *nd, const char *metric_name, struct cerebrod_message_metric *mm) { struct cerebrod_monitor_module_info *monitor_module; struct cerebrod_monitor_module_list *ml; #if CEREBRO_DEBUG int rv; #endif /* CEREBRO_DEBUG */ assert(nodename && nd && metric_name && mm); if (!monitor_index) return; #if CEREBRO_DEBUG /* Should be called with lock already set */ rv = Pthread_mutex_trylock(&nd->node_data_lock); if (rv != EBUSY) CEREBROD_EXIT(("mutex not locked: rv=%d", rv)); #endif /* CEREBRO_DEBUG */ if ((ml = Hash_find(monitor_index, metric_name))) { ListIterator itr = NULL; Pthread_mutex_lock(&(ml->monitor_list_lock)); itr = List_iterator_create(ml->monitor_list); Pthread_mutex_unlock(&(ml->monitor_list_lock)); while ((monitor_module = list_next(itr))) { Pthread_mutex_lock(&monitor_module->monitor_lock); monitor_module_metric_update(monitor_handle, monitor_module->index, nodename, metric_name, mm->metric_value_type, mm->metric_value_len, mm->metric_value); Pthread_mutex_unlock(&monitor_module->monitor_lock); } Pthread_mutex_lock(&(ml->monitor_list_lock)); List_iterator_destroy(itr); Pthread_mutex_unlock(&(ml->monitor_list_lock)); } }
static void _delete_event_connection_fd(int fd) { struct cerebrod_event_connection_data *ecd; ListIterator eitr; #if CEREBRO_DEBUG int rv; #endif /* CEREBRO_DEBUG */ assert(fd >= 0); #if CEREBRO_DEBUG /* Should be called with lock already set */ rv = Pthread_mutex_trylock(&event_connections_lock); if (rv != EBUSY) CEREBROD_EXIT(("mutex not locked: rv=%d", rv)); #endif /* CEREBRO_DEBUG */ eitr = List_iterator_create(event_connections); while ((ecd = list_next(eitr))) { if (ecd->fd == fd) { List connections; if ((connections = Hash_find(event_connections_index, ecd->event_name))) { ListIterator citr; int *fdPtr; citr = List_iterator_create(connections); while ((fdPtr = list_next(citr))) { if (*fdPtr == fd) { List_delete(citr); break; } } List_iterator_destroy(citr); } List_delete(eitr); break; } } List_iterator_destroy(eitr); }
void *thread_operator(void *attr){ int rc; int my_id = (int) attr; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); void *socket = zmq_socket(server_pool.context, ZMQ_REP); zmq_connect(socket, ZMQ_INPROC_ADDR); pthread_cleanup_push((void (*)(void *)) zmq_close, socket); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); zmq_msg_t reply_msgs[DCS_SERVER_REPLY_COUNT]; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); for(int i = 0; i < DCS_SERVER_REPLY_COUNT; i++){ zmq_msg_init_size(&reply_msgs[i], DCS_SERVER_REPLY_SIZE); memcpy(zmq_msg_data(&reply_msgs[i]), &server_replys[i], DCS_SERVER_REPLY_SIZE); } pthread_cleanup_push(thread_operator_msg_clean, reply_msgs); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); if(!server_pool.no_barr){ rc = pthread_barrier_wait(&server_pool.proxy_barr); if(rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) syslog(LOG_ERR, "Thread #%d cannot wait on barrier.", my_id); } while(1){ int reply_id = DCS_SERVER_REPLY_OK; zmq_msg_t client_msg; char *message; size_t msg_size; unsigned char digest[MSG_DIGEST_SIZE]; char *domain; char *md5sum; char *sep; HASH_ELEMENT *comp; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); zmq_msg_init(&client_msg); pthread_cleanup_push((void (*)(void *)) zmq_msg_close, &client_msg); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); zmq_msg_recv(&client_msg, socket, 0); message = (char *) zmq_msg_data(&client_msg); msg_size = zmq_msg_size(&client_msg); DEBUGMSG(syslog(LOG_DEBUG, "msg_size = %d\n", msg_size)); if(msg_size >= MSG_DIGEST_SIZE + 1 + 1 + 2){ //~ проверка размера сообщения здесь!!! //~ decrypt and verify message here! //~ message = func(message) memset(digest, '\0', MSG_DIGEST_SIZE); rc = msg_digest(message + MSG_DIGEST_SIZE, MSG_SALT_PATH, msg_size - MSG_DIGEST_SIZE, digest); if(rc){ DEBUGMSG(syslog(LOG_DEBUG, "msg_digest failed!!!")); } if(memcmp(message, digest, MSG_DIGEST_SIZE) == 0){ message += MSG_DIGEST_SIZE; DEBUGMSG(syslog(LOG_DEBUG, "Thread #%d catch message: '%s'\n", my_id, message + 1)); switch(*message){ case DCS_CLIENT_REQ_MD5: message++; sep = strchr(message, MSG_SEPARATOR); if(sep){ *sep = '\0'; domain = message; md5sum = sep + 1; /* Проверки на длину md5-сум!!! */ comp = Hash_find(&server_pool.hash, domain, (size_t) (unsigned int) sep - (unsigned int) message); if(comp){ if(memcmp(md5sum, comp->val, HASH_ELEMENT_VAL_SIZE) != 0){ /* Суммы различны, подать сюда полный список деталей! */ reply_id = DCS_SERVER_REPLY_FULL; DEBUGMSG(syslog(LOG_DEBUG, "Суммы различны\n")); } else{ //~ Суммы совпали, всё хорошо. reply_id = DCS_SERVER_REPLY_OK; } } else{ /* Компьютера в хэше нет. */ reply_id = DCS_SERVER_REPLY_FULL; DEBUGMSG(syslog(LOG_DEBUG, "Компьютера в хэше нет\n")); } } break; case DCS_CLIENT_REQ_FULL: message++; sep = strchr(message, MSG_SEPARATOR); if(sep){ *sep = '\0'; domain = message; size_t domain_size; CL_Detail *details; size_t details_count; unsigned char *hwdata = (unsigned char *) sep + 1; msg_size -= (MSG_DIGEST_SIZE + 2 + ( (size_t) (unsigned int) sep - (unsigned int) message)); domain_size = (size_t) ((unsigned int) sep - (unsigned int) message); /* Считаем md5 */ MD5_CTX mdcontext; MD5Init(&mdcontext); MD5Update(&mdcontext, hwdata, msg_size); MD5Final(digest, &mdcontext); /* Ищем комп в хэше */ comp = Hash_find(&server_pool.hash, domain, domain_size); if(!comp){ /* Компьютера в хэше нет - новый компьютер. */ DEBUGMSG(syslog(LOG_DEBUG, "Новая машина!")); //~ details = (CL_Detail *) calloc(sizeof(CL_Detail), 40); details = (CL_Detail *) malloc(sizeof(CL_Detail) * 40); unsigned char *hwdata_p = hwdata; for(int i = 0; i < 40; i++){ details[i].vendor_id = get_uint16_from(hwdata_p); hwdata_p += sizeof(details[i].vendor_id); details[i].device_id = get_uint16_from(hwdata_p); hwdata_p += sizeof(details[i].device_id); details[i].subsystem_id = get_uint32_from(hwdata_p); hwdata_p += sizeof(details[i].subsystem_id); details[i].class_code = get_uint32_from(hwdata_p); hwdata_p += sizeof(details[i].class_code); details[i].revision = get_uint8_from(hwdata_p); hwdata_p += sizeof(details[i].revision); memcpy(&details[i].bus_addr, hwdata_p, sizeof(details[i].bus_addr)); hwdata_p += sizeof(details[i].bus_addr); details[i].serial_length = get_uint32_from(hwdata_p); hwdata_p += sizeof(details[i].serial_length); DEBUGMSG(syslog(LOG_DEBUG, "Detail: %.4x:%.4x:%.8x (rev %.2x) [class: %.6x] Bus: '%s', SL '%u'", details[i].vendor_id, details[i].device_id, details[i].subsystem_id, details[i].revision, details[i].class_code, details[i].bus_addr, details[i].serial_length )); memcpy(&details[i].serial, hwdata_p, details[i].serial_length); hwdata_p += details[i].serial_length; details[i].serial[details[i].serial_length] = '\0'; details[i].params_length = get_uint32_from(hwdata_p); hwdata_p += sizeof(details[i].params_length); DEBUGMSG(syslog(LOG_DEBUG, "HERE4! params_length: %d", details[i].params_length)); details[i].params = (char *) calloc(sizeof(char), details[i].params_length); memcpy(details[i].params, hwdata_p, details[i].params_length); hwdata_p += details[i].params_length; details[i].params[details[i].params_length] = '\0'; DEBUGMSG(syslog(LOG_DEBUG, "Detail: %.4x:%.4x:%.8x (%.2x) [%.6x]: '%s', '%s'", details[i].vendor_id, details[i].device_id, details[i].subsystem_id, details[i].revision, details[i].class_code, details[i].serial, details[i].params )); if((unsigned int) (hwdata_p - hwdata) >= msg_size){ details_count = i + 1; details = (CL_Detail *) realloc(details, sizeof(CL_Detail) * details_count); break; } } /* Хэшируем результат */ comp = Hash_insert(&server_pool.hash, domain, domain_size, (char *) digest, MSG_DIGEST_SIZE); if(!comp){ DEBUGMSG(syslog(LOG_DEBUG, "Hash insert error: %d\n", errno)); break; } } else{ /* Есть в кэше, проверим md5 */ if(memcmp(comp->val, digest, HASH_ELEMENT_VAL_SIZE) == 0){ DEBUGMSG(syslog(LOG_DEBUG, "Суммы одинаковые, наверное ошибочный запрос\n")); } else{ /* Суммы различны (так и должно быть) - обновляем! */ memcpy(comp->val, digest, HASH_ELEMENT_VAL_SIZE); } } sync_comp(comp, details, details_count); } break; default: DEBUGMSG(syslog(LOG_DEBUG, "default = %02x\n", *message)); break; } } else{ DEBUGMSG(syslog(LOG_DEBUG, "memcmp failed!")); } } pthread_cleanup_pop(1); /* zmq_msg_close() */ DEBUGMSG(syslog(LOG_DEBUG, "Reply %d: '%.2x'\n", reply_id, *((unsigned int *) zmq_msg_data(&reply_msgs[reply_id])))); zmq_msg_send(&reply_msgs[reply_id], socket, 0); } pthread_cleanup_pop(0); /* thread_operator_msg_clean */ pthread_cleanup_pop(0); /* zmq_close */ pthread_exit(NULL); }
void cerebrod_event_modules_update(const char *nodename, struct cerebrod_node_data *nd, const char *metric_name, struct cerebrod_message_metric *mm) { struct cerebrod_event_module_info *event_module; struct cerebrod_event_module_list *el; #if CEREBRO_DEBUG int rv; #endif /* CEREBRO_DEBUG */ assert(nodename && nd && metric_name && mm); if (!event_index) return; #if CEREBRO_DEBUG /* Should be called with lock already set */ rv = Pthread_mutex_trylock(&nd->node_data_lock); if (rv != EBUSY) CEREBROD_EXIT(("mutex not locked: rv=%d", rv)); #endif /* CEREBRO_DEBUG */ /* * This function may be called by multiple threads by the listener. * * The event_index is setup at the beginning and is only read, not * written to. However, the lists stored inside the event_index * need to called w/ thread safety (due to the nature of the list * API). * */ if ((el = Hash_find(event_index, metric_name))) { struct cerebro_event *event = NULL; ListIterator itr = NULL; int rv; Pthread_mutex_lock(&(el->event_list_lock)); itr = List_iterator_create(el->event_list); Pthread_mutex_unlock(&(el->event_list_lock)); while ((event_module = list_next(itr))) { Pthread_mutex_lock(&event_module->event_lock); if ((rv = event_module_metric_update(event_handle, event_module->index, nodename, metric_name, mm->metric_value_type, mm->metric_value_len, mm->metric_value, &event)) < 0) { CEREBROD_DBG(("event_module_metric_update")); goto loop_next; } if (rv && event) cerebrod_queue_event(event, event_module->index); loop_next: Pthread_mutex_unlock(&event_module->event_lock); } Pthread_mutex_lock(&(el->event_list_lock)); List_iterator_destroy(itr); Pthread_mutex_unlock(&(el->event_list_lock)); } }
/* * Under almost any circumstance, don't return a -1 error, cerebro can * go on without loading monitor modules. The listener_data_init_lock * should already be set. */ int cerebrod_event_modules_setup(void) { int i, event_module_count, event_index_len, event_index_count = 0; struct cerebrod_event_module_list *el = NULL; #if CEREBRO_DEBUG int rv; #endif /* CEREBRO_DEBUG */ assert(listener_data); #if CEREBRO_DEBUG /* Should be called with lock already set */ rv = Pthread_mutex_trylock(&listener_data_init_lock); if (rv != EBUSY) CEREBROD_EXIT(("mutex not locked: rv=%d", rv)); #endif /* CEREBRO_DEBUG */ if (!conf.event_server) return 0; if (!(event_handle = event_modules_load())) { CEREBROD_DBG(("event_modules_load")); goto cleanup; } if ((event_module_count = event_modules_count(event_handle)) < 0) { CEREBROD_DBG(("event_modules_count")); goto cleanup; } if (!event_module_count) { if (conf.debug && conf.event_server_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* No Event Modules Found\n"); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } goto cleanup; } /* Each event module may want multiple metrics and/or offer multiple * event names. We'll assume there will never be more than 2 per * event module, and that will be enough to avoid all hash * collisions. */ event_index_len = event_module_count * 2; event_index = Hash_create(event_index_len, (hash_key_f)hash_key_string, (hash_cmp_f)strcmp, (hash_del_f)_cerebrod_event_module_list_destroy); event_names = List_create((ListDelF)_Free); event_module_timeouts = List_create((ListDelF)_cerebrod_event_module_timeout_data_destroy); event_module_timeout_index = Hash_create(event_module_count, (hash_key_f)hash_key_string, (hash_cmp_f)strcmp, (hash_del_f)list_destroy); for (i = 0; i < event_module_count; i++) { struct cerebrod_event_module *event_module; char *module_name, *module_metric_names, *module_event_names; char *metricPtr, *metricbuf; char *eventnamePtr, *eventbuf; int timeout; module_name = event_module_name(event_handle, i); if (conf.event_module_exclude_len) { int found_exclude = 0; int j; for (j = 0; j < conf.event_module_exclude_len; j++) { if (!strcasecmp(conf.event_module_exclude[j], module_name)) { found_exclude++; break; } } if (found_exclude) { if (conf.debug && conf.event_server_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* Skip Event Module: %s\n", module_name); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } CEREBROD_ERR(("Dropping event module: %s", module_name)); continue; } } if (conf.debug && conf.event_server_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* Setup Event Module: %s\n", module_name); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } if (event_module_setup(event_handle, i) < 0) { CEREBROD_DBG(("event_module_setup failed: %s", module_name)); continue; } if (!(module_metric_names = event_module_metric_names(event_handle, i)) < 0) { CEREBROD_DBG(("event_module_metric_names failed: %s", module_name)); event_module_cleanup(event_handle, i); continue; } if (!(module_event_names = event_module_event_names(event_handle, i)) < 0) { CEREBROD_DBG(("event_module_event_names failed: %s", module_name)); event_module_cleanup(event_handle, i); continue; } if ((timeout = event_module_timeout_length(event_handle, i)) < 0) { CEREBROD_DBG(("event_module_timeout_length failed: %s", module_name)); event_module_cleanup(event_handle, i); continue; } event_module = Malloc(sizeof(struct cerebrod_event_module_info)); event_module->metric_names = Strdup(module_metric_names); event_module->event_names = Strdup(module_event_names); event_module->index = i; Pthread_mutex_init(&(event_module->event_lock), NULL); /* The monitoring module may support multiple metrics */ metricPtr = strtok_r(event_module->metric_names, ",", &metricbuf); while (metricPtr) { if (!(el = Hash_find(event_index, metricPtr))) { el = (struct cerebrod_event_module_list *)Malloc(sizeof(struct cerebrod_event_module_list)); el->event_list = List_create((ListDelF)_cerebrod_event_module_info_destroy); Pthread_mutex_init(&(el->event_list_lock), NULL); List_append(el->event_list, event_module); Hash_insert(event_index, metricPtr, el); event_index_count++; } else List_append(el->event_list, event_module); metricPtr = strtok_r(NULL, ",", &metricbuf); } /* The monitoring module may support multiple event names */ eventnamePtr = strtok_r(event_module->event_names, ",", &eventbuf); while (eventnamePtr) { if (!list_find_first(event_names, (ListFindF)_cerebrod_name_strcmp, eventnamePtr)) { List_append(event_names, eventnamePtr); if (conf.debug && conf.event_server_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* Event Name: %s\n", eventnamePtr); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } } eventnamePtr = strtok_r(NULL, ",", &eventbuf); } if (timeout) { struct cerebrod_event_module_timeout_data *mtd; List modules_list; if (!(mtd = List_find_first(event_module_timeouts, _event_module_timeout_data_find_callback, &timeout))) { char strbuf[64]; mtd = (struct cerebrod_event_module_timeout_data *)Malloc(sizeof(struct cerebrod_event_module_timeout_data)); mtd->timeout = timeout; snprintf(strbuf, 64, "%d", timeout); mtd->timeout_str = Strdup(strbuf); List_append(event_module_timeouts, mtd); if (timeout < event_module_timeout_min) event_module_timeout_min = timeout; } if (!(modules_list = Hash_find(event_module_timeout_index, mtd->timeout_str))) { modules_list = List_create((ListDelF)NULL); List_append(modules_list, event_module); Hash_insert(event_module_timeout_index, mtd->timeout_str, modules_list); } else List_append(modules_list, event_module); } } List_sort(event_module_timeouts, _event_module_timeout_data_compare); if (!event_index_count) goto cleanup; if (_setup_event_node_timeout_data() < 0) goto cleanup; /* * Since the cerebrod listener is started before any of the event * threads (node_timeout, queue_monitor, server), this must be * created in here (which is called by the listener) to avoid a * possible race of modules creating events before the event_queue * is created. */ event_queue = List_create((ListDelF)cerebrod_event_to_send_destroy); return 1; cleanup: if (event_handle) { event_modules_unload(event_handle); event_handle = NULL; } if (event_index) { Hash_destroy(event_index); event_index = NULL; } if (event_names) { List_destroy(event_names); event_names = NULL; } return 0; }
/* * _event_server_service_connection * * Service a connection from a client to receive event packets. Use * wrapper functions minimally, b/c we want to return errors to the * user instead of exitting with errors. * */ static void _event_server_service_connection(int fd) { int recv_len; struct cerebro_event_server_request req; struct cerebrod_event_connection_data *ecd = NULL; char buf[CEREBRO_MAX_PACKET_LEN]; char event_name_buf[CEREBRO_MAX_EVENT_NAME_LEN+1]; char *event_name_ptr = NULL; int32_t version; int *fdptr = NULL; List connections = NULL; assert(fd >= 0); memset(&req, '\0', sizeof(struct cerebro_event_server_request)); if ((recv_len = receive_data(fd, CEREBRO_EVENT_SERVER_REQUEST_PACKET_LEN, buf, CEREBRO_MAX_PACKET_LEN, CEREBRO_EVENT_SERVER_PROTOCOL_CLIENT_TIMEOUT_LEN, NULL)) < 0) goto cleanup; if (recv_len < sizeof(version)) goto cleanup; if (_event_server_request_check_version(buf, recv_len, &version) < 0) { _event_server_err_only_response(fd, version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_VERSION_INVALID); goto cleanup; } if (recv_len != CEREBRO_EVENT_SERVER_REQUEST_PACKET_LEN) { _event_server_err_only_response(fd, version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_PACKET_INVALID); goto cleanup; } if (_event_server_request_unmarshall(&req, buf, recv_len) < 0) { _event_server_err_only_response(fd, version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_PACKET_INVALID); goto cleanup; } _event_server_request_dump(&req); /* Guarantee ending '\0' character */ memset(event_name_buf, '\0', CEREBRO_MAX_EVENT_NAME_LEN+1); memcpy(event_name_buf, req.event_name, CEREBRO_MAX_EVENT_NAME_LEN); if (!strlen(event_name_buf)) { _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_EVENT_INVALID); goto cleanup; } /* Is it the special event-names request */ if (!strcmp(event_name_buf, CEREBRO_EVENT_NAMES)) { pthread_t thread; pthread_attr_t attr; int *arg; Pthread_attr_init(&attr); Pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); Pthread_attr_setstacksize(&attr, CEREBROD_THREAD_STACKSIZE); arg = Malloc(sizeof(int)); *arg = fd; Pthread_create(&thread, &attr, _respond_with_event_names, (void *)arg); Pthread_attr_destroy(&attr); return; } if (!event_names) { _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_EVENT_INVALID); goto cleanup; } /* Event names is not changeable - so no need for a lock */ if (!(event_name_ptr = list_find_first(event_names, _event_names_compare, event_name_buf))) { _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_EVENT_INVALID); goto cleanup; } if (!(ecd = (struct cerebrod_event_connection_data *)malloc(sizeof(struct cerebrod_event_connection_data)))) { CEREBROD_ERR(("malloc: %s", strerror(errno))); _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_INTERNAL_ERROR); goto cleanup; } ecd->event_name = event_name_ptr; ecd->fd = fd; if (!(fdptr = (int *)malloc(sizeof(int)))) { CEREBROD_ERR(("malloc: %s", strerror(errno))); _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_INTERNAL_ERROR); goto cleanup; } *fdptr = fd; Pthread_mutex_lock(&event_connections_lock); if (!list_append(event_connections, ecd)) { CEREBROD_ERR(("list_append: %s", strerror(errno))); _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_INTERNAL_ERROR); goto cleanup; } if (!(connections = Hash_find(event_connections_index, ecd->event_name))) { if (!(connections = list_create((ListDelF)free))) { CEREBROD_ERR(("list_create: %s", strerror(errno))); _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_INTERNAL_ERROR); goto cleanup; } if (!Hash_insert(event_connections_index, ecd->event_name, connections)) { CEREBROD_ERR(("Hash_insert: %s", strerror(errno))); _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_INTERNAL_ERROR); list_destroy(connections); goto cleanup; } } if (!list_append(connections, fdptr)) { CEREBROD_ERR(("list_append: %s", strerror(errno))); _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_INTERNAL_ERROR); goto cleanup; } Pthread_mutex_unlock(&event_connections_lock); /* Clear this pointer so we know it's stored away in a list */ fdptr = NULL; _event_server_err_only_response(fd, req.version, CEREBRO_EVENT_SERVER_PROTOCOL_ERR_SUCCESS); return; cleanup: if (ecd) free(ecd); if (fdptr) free(fdptr); /* ignore potential error, we're in the error path already */ close(fd); return; }
void * cerebrod_event_queue_monitor(void *arg) { List temp_event_queue; _event_queue_monitor_initialize(); /* Don't bother if there isn't an event queue (i.e. no event modules) */ if (!event_queue) return NULL; temp_event_queue = List_create((ListDelF)cerebrod_event_to_send_destroy); /* * achu: The listener and thus event update initialization is * started after this thread is started. So the and event_index may * not be set up the first time this loop is reached. * * However, it must be set after the condition is signaled, b/c the * listener (and thus event update code) and event node timeout * thread begin after the listener is setup. * * Thus, we put the event_queue assert inside the loop. */ for (;;) { struct cerebrod_event_to_send *ets; ListIterator eitr; ListIterator titr; Pthread_mutex_lock(&event_queue_lock); assert(event_queue); while (list_count(event_queue) == 0) Pthread_cond_wait(&event_queue_cond, &event_queue_lock); /* Debug dumping in the below loop can race with the debug * dumping from the listener, b/c of racing on the * event_queue_lock. To avoid this race, we copy the data off * the event_queue, so the event_queue_lock can be freed up. */ eitr = List_iterator_create(event_queue); while ((ets = list_next(eitr))) { List_append(temp_event_queue, ets); List_remove(eitr); } List_iterator_destroy(eitr); Pthread_mutex_unlock(&event_queue_lock); titr = List_iterator_create(temp_event_queue); while ((ets = list_next(titr))) { List connections; _event_dump(ets->event); Pthread_mutex_lock(&event_connections_lock); if ((connections = Hash_find(event_connections_index, ets->event_name))) { char buf[CEREBRO_MAX_PACKET_LEN]; int elen; if ((elen = _event_marshall(ets->event, buf, CEREBRO_MAX_PACKET_LEN)) > 0) { ListIterator citr; int *fd; citr = List_iterator_create(connections); while ((fd = list_next(citr))) { if (fd_write_n(*fd, buf, elen) < 0) { CEREBROD_DBG(("fd_write_n: %s", strerror(errno))); if (errno == EPIPE || errno == EINVAL || errno == EBADF || errno == ENODEV || errno == ENETDOWN || errno == ENETUNREACH) { if (conf.event_server_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* Event Connection Died: errno = %d\n", errno); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } List_delete(citr); } continue; } } List_iterator_destroy(citr); } } Pthread_mutex_unlock(&event_connections_lock); List_delete(titr); } List_iterator_destroy(titr); } List_destroy(temp_event_queue); return NULL; /* NOT REACHED */ }
/* * Under almost any circumstance, don't return a -1 error, cerebro can * go on without loading monitor modules. The listener_data_init_lock * should already be set. */ int cerebrod_monitor_modules_setup(void) { int i, monitor_module_count, monitor_index_len, monitor_index_count = 0; struct cerebrod_monitor_module_list *ml = NULL; #if CEREBRO_DEBUG int rv; #endif /* CEREBRO_DEBUG */ #if CEREBRO_DEBUG /* Should be called with lock already set */ rv = Pthread_mutex_trylock(&listener_data_init_lock); if (rv != EBUSY) CEREBROD_EXIT(("mutex not locked: rv=%d", rv)); #endif /* CEREBRO_DEBUG */ if (!(monitor_handle = monitor_modules_load())) { CEREBROD_DBG(("monitor_modules_load")); goto cleanup; } if ((monitor_module_count = monitor_modules_count(monitor_handle)) < 0) { CEREBROD_DBG(("monitor_modules_count")); goto cleanup; } if (!monitor_module_count) { if (conf.debug && conf.listen_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* No Monitor Modules Found\n"); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } goto cleanup; } /* Each monitor module may wish to monitor multiple metrics. We'll * assume there will never be more than 2 metrics per monitor module, and * that will be enough to avoid all hash collisions. */ monitor_index_len = monitor_module_count * 2; monitor_index = Hash_create(monitor_index_len, (hash_key_f)hash_key_string, (hash_cmp_f)strcmp, (hash_del_f)_cerebrod_monitor_module_list_destroy); for (i = 0; i < monitor_module_count; i++) { struct cerebrod_monitor_module_info *monitor_module; char *module_name, *metric_names; char *metricPtr, *metricbuf; module_name = monitor_module_name(monitor_handle, i); if (conf.monitor_module_exclude_len) { int found_exclude = 0; int j; for (j = 0; j < conf.monitor_module_exclude_len; j++) { if (!strcasecmp(conf.monitor_module_exclude[j], module_name)) { found_exclude++; break; } } if (found_exclude) { if (conf.debug && conf.listen_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* Skip Monitor Module: %s\n", module_name); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } CEREBROD_ERR(("Dropping monitor module: %s", module_name)); continue; } } if (conf.debug && conf.listen_debug) { Pthread_mutex_lock(&debug_output_mutex); fprintf(stderr, "**************************************\n"); fprintf(stderr, "* Setup Monitor Module: %s\n", module_name); fprintf(stderr, "**************************************\n"); Pthread_mutex_unlock(&debug_output_mutex); } if (monitor_module_setup(monitor_handle, i) < 0) { CEREBROD_DBG(("monitor_module_setup failed: %s", module_name)); continue; } if (!(metric_names = monitor_module_metric_names(monitor_handle, i)) < 0) { CEREBROD_DBG(("monitor_module_metric_names failed: %s", module_name)); monitor_module_cleanup(monitor_handle, i); continue; } monitor_module = Malloc(sizeof(struct cerebrod_monitor_module_info)); monitor_module->metric_names = Strdup(metric_names); monitor_module->index = i; Pthread_mutex_init(&(monitor_module->monitor_lock), NULL); /* The monitoring module may support multiple metrics */ metricPtr = strtok_r(monitor_module->metric_names, ",", &metricbuf); while (metricPtr) { if (!(ml = Hash_find(monitor_index, metricPtr))) { ml = (struct cerebrod_monitor_module_list *)Malloc(sizeof(struct cerebrod_monitor_module_list)); ml->monitor_list = List_create((ListDelF)_cerebrod_monitor_module_info_destroy); Pthread_mutex_init(&(ml->monitor_list_lock), NULL); List_append(ml->monitor_list, monitor_module); Hash_insert(monitor_index, metricPtr, ml); monitor_index_count++; } else List_append(ml->monitor_list, monitor_module); metricPtr = strtok_r(NULL, ",", &metricbuf); } } if (!monitor_index_count) goto cleanup; return 1; cleanup: if (monitor_handle) { monitor_modules_unload(monitor_handle); monitor_handle = NULL; } if (monitor_index) { Hash_destroy(monitor_index); monitor_index = NULL; } return 0; }