static void testInsert() { // test general case Hash_T h0 = Hash_new(0); EXPECT_EQ_UINT32(0, h0->nElements); EXPECT_EQ_UINT32(0, h0->tableSize); int key1 = 123; char* value1 = "1"; h0 = Hash_insert(h0, Atom_newFromInt64(key1), value1); EXPECT_NOT_NULL(h0); EXPECT_EQ_UINT32(1, h0->nElements); EXPECT_EQ_UINT32(1, h0->tableSize); int key2 = -27; char value2[] = "value2"; h0 = Hash_insert(h0, Atom_newFromInt64(key2), value2); EXPECT_NOT_NULL(h0); EXPECT_EQ_UINT32(2, h0->nElements); EXPECT_EQ_UINT32(3, h0->tableSize); char * key3 = "abc"; int16_t value3 = 1056; Str_T s = Str_newFromInt16(value3); h0 = Hash_insert(h0, Atom_newFromString(key3), Str_str(s)); EXPECT_NOT_NULL(h0); EXPECT_EQ_UINT32(3, h0->nElements); EXPECT_EQ_UINT32(3, h0->tableSize); Str_free(&s); Hash_free(&h0); EXPECT_NULL(h0); }
void HashSet_insert (T set, Poly_t x) { if (Hash_lookup (set->hash, x)) return; Hash_insert (set->hash, x, (Poly_t)1); return; }
/* * _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); }
/* * _hash_removeall * * callback for hash_for_each that inserts entries into the new hash. * * Returns 1 for success, 0 on failure, -1 on fatal error */ static int _hash_reinsert(void *data, const void *key, void *arg) { hash_t newhash; assert(data && key && arg); newhash = *((hash_t *)arg); Hash_insert(newhash, key, data); return 1; }
/* * _event_node_timeout_data_add * * Create entries for the event_node_timeout_data list and index * * Returns 0 on success, -1 on error */ static int _event_node_timeout_data_add(const char *nodename, u_int32_t time_now) { struct cerebrod_event_node_timeout_data *ntd; #if CEREBRO_DEBUG int rv; /* Should be called with lock already set */ rv = Pthread_mutex_trylock(&event_node_timeout_data_lock); if (rv != EBUSY) CEREBROD_EXIT(("mutex not locked: rv=%d", rv)); #endif /* CEREBRO_DEBUG */ ntd = (struct cerebrod_event_node_timeout_data *)Malloc(sizeof(struct cerebrod_event_node_timeout_data)); ntd->nodename = (char *)nodename; ntd->last_received_time = time_now; ntd->timeout_occurred = 0; List_append(event_node_timeout_data, ntd); Hash_insert(event_node_timeout_data_index, ntd->nodename, ntd); event_node_timeout_data_index_numnodes++; return 0; }
extern void Config_section_set(Config_section_T section, const char *varname, Config_value_T value) { Hash_insert(section->vars, varname, (Config_value_T) value); }
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); }
/* * 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; }
/* * 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; }
int main(void) { Lexer_source_T ls; Lexer_T l; Config_parser_T cp; Config_T c; struct Greyd_state gs; struct Con con; Blacklist_T bl1, bl2, bl3; struct sockaddr_storage src; int ret; char *conf = "hostname = \"greyd.org\"\n" "banner = \"greyd IP-based SPAM blocker\"\n" "section grey {\n" " enable = 1,\n" " traplist_name = \"test traplist\",\n" " traplist_message = \"you have been trapped\",\n" " grey_expiry = 3600,\n" " stutter = 15\n" "}\n" "section firewall {\n" " driver = \"../drivers/fw_dummy.so\"\n" "}\n" "section database {\n" " driver = \"../drivers/bdb.so\",\n" " path = \"/tmp/greyd_test_grey.db\"\n" "}"; /* Empty existing database file. */ ret = unlink("/tmp/greyd_test_grey.db"); if(ret < 0 && errno != ENOENT) { printf("Error unlinking test Berkeley DB: %s\n", strerror(errno)); } TEST_START(49); c = Config_create(); ls = Lexer_source_create_from_str(conf, strlen(conf)); l = Config_lexer_create(ls); cp = Config_parser_create(l); Config_parser_start(cp, c); /* * Set up the greyd state and blacklists. */ memset(&gs, 0, sizeof(gs)); gs.config = c; gs.max_cons = 4; gs.max_black = 4; gs.blacklists = Hash_create(5, NULL); bl1 = Blacklist_create("blacklist_1", "You (%A) are on blacklist 1", BL_STORAGE_TRIE); bl2 = Blacklist_create("blacklist_2", "You (%A) are on blacklist 2", BL_STORAGE_TRIE); bl3 = Blacklist_create("blacklist_3_with_an_enormously_big_long_long_epic_epicly_long_large_name", "Your address %A\\nis on blacklist 3", BL_STORAGE_TRIE); Hash_insert(gs.blacklists, bl1->name, bl1); Hash_insert(gs.blacklists, bl2->name, bl2); Hash_insert(gs.blacklists, bl3->name, bl3); Blacklist_add(bl1, "10.10.10.1/32"); Blacklist_add(bl1, "10.10.10.2/32"); Blacklist_add(bl2, "10.10.10.1/32"); Blacklist_add(bl2, "10.10.10.2/32"); Blacklist_add(bl2, "2001::fad3:1/128"); Blacklist_add(bl3, "10.10.10.2/32"); Blacklist_add(bl3, "10.10.10.3/32"); Blacklist_add(bl3, "2001::fad3:1/128"); /* * Start testing the connection management. */ memset(&src, 0, sizeof(src)); ((struct sockaddr_in *) &src)->sin_family = AF_INET; inet_pton(AF_INET, "10.10.10.1", &((struct sockaddr_in *) &src)->sin_addr); memset(&con, 0, sizeof(con)); Con_init(&con, 0, &src, &gs); TEST_OK(con.state == 0, "init state ok"); TEST_OK(con.last_state == 0, "last state ok"); TEST_OK(List_size(con.blacklists) == 2, "blacklist matches ok"); TEST_OK(!strcmp(con.src_addr, "10.10.10.1"), "src addr ok"); TEST_OK(con.out_buf != NULL, "out buf ok"); TEST_OK(con.out_p == con.out_buf, "out buf pointer ok"); TEST_OK(con.out_size == CON_OUT_BUF_SIZE, "out buf size ok"); TEST_OK(!strcmp(con.lists, "blacklist_1 blacklist_2"), "list summary ok"); /* The size of the banner. */ TEST_OK(con.out_remaining == 75, "out buf remaining ok"); TEST_OK(gs.clients == 1, "clients ok"); TEST_OK(gs.black_clients == 1, "blacklisted clients ok"); /* * Test the closing of a connection. */ Con_close(&con, &gs); TEST_OK(List_size(con.blacklists) == 0, "blacklist empty ok"); TEST_OK(con.out_buf == NULL, "out buf ok"); TEST_OK(con.out_p == NULL, "out buf pointer ok"); TEST_OK(con.out_size == 0, "out buf size ok"); TEST_OK(con.lists == NULL, "lists ok"); TEST_OK(gs.clients == 0, "clients ok"); TEST_OK(gs.black_clients == 0, "blacklisted clients ok"); /* Test recycling a connection. */ memset(&src, 0, sizeof(src)); ((struct sockaddr_in6 *) &src)->sin6_family = AF_INET6; inet_pton(AF_INET6, "2001::fad3:1", &((struct sockaddr_in6 *) &src)->sin6_addr); Con_init(&con, 0, &src, &gs); TEST_OK(con.state == 0, "init state ok"); TEST_OK(con.last_state == 0, "last state ok"); TEST_OK(List_size(con.blacklists) == 2, "blacklist matches ok"); TEST_OK(!strcmp(con.src_addr, "2001::fad3:1"), "src addr ok"); TEST_OK(con.out_buf != NULL, "out buf ok"); TEST_OK(con.out_p == con.out_buf, "out buf pointer ok"); TEST_OK(con.out_size == CON_OUT_BUF_SIZE, "out buf size ok"); /* * As the 3rd blacklist's name is really long, the summarize lists * function should truncate with a "...". */ TEST_OK(!strcmp(con.lists, "blacklist_2 ..."), "list summary ok"); /* The size of the banner. */ TEST_OK(con.out_remaining == 75, "out buf remaining ok"); TEST_OK(gs.clients == 1, "clients ok"); TEST_OK(gs.black_clients == 1, "blacklisted clients ok"); /* * Test the rejection message building. */ Con_build_reply(&con, "451"); TEST_OK(!strcmp(con.out_p, "451-You (2001::fad3:1) are on blacklist 2\n" "451-Your address 2001::fad3:1\n" "451 is on blacklist 3\n"), "Blacklisted error response ok"); TEST_OK(con.out_remaining == 94, "out buf remaining ok"); /* * Test the writing of the buffer without stuttering. */ time_t now = time(NULL); int con_pipe[2], to_write, nread; char in[CON_OUT_BUF_SIZE]; pipe(con_pipe); con.fd = con_pipe[1]; con.w = now; to_write = con.out_remaining; Con_handle_write(&con, &now, &gs); nread = read(con_pipe[0], in, to_write); in[nread] = '\0'; TEST_OK(!strcmp(in, "451-You (2001::fad3:1) are on blacklist 2\n" "451-Your address 2001::fad3:1\n" "451 is on blacklist 3\n"), "Con write without stuttering ok"); /* * Test the writing with stuttering. Note the reply is longer due * to the stutering adding in \r before each \n if there isn't one * already. */ Con_build_reply(&con, "451"); gs.max_cons = 100; gs.max_black = 100; con.w = now; while(con.out_remaining > 0) { Con_handle_write(&con, &now, &gs); now += con.stutter + 1; } memset(in, 0, sizeof(in)); nread = read(con_pipe[0], in, to_write + 3); in[nread] = '\0'; TEST_OK(!strcmp(in, "451-You (2001::fad3:1) are on blacklist 2\r\n" "451-Your address 2001::fad3:1\r\n" "451 is on blacklist 3\r\n"), "Con write with stuttering ok"); /* Test recycling a connection, which is not on a blacklist. */ Con_close(&con, &gs); memset(&src, 0, sizeof(src)); ((struct sockaddr_in6 *) &src)->sin6_family = AF_INET6; inet_pton(AF_INET6, "fa40::fad3:1", &((struct sockaddr_in6 *) &src)->sin6_addr); Con_init(&con, 0, &src, &gs); TEST_OK(List_size(con.blacklists) == 0, "not on blacklist ok"); /* * Note custom error codes only apply for blacklist connections, so expect * a 451 for this greylisted connections. */ Con_build_reply(&con, "551"); TEST_OK(!strcmp(con.out_p, "451 Temporary failure, please try again later.\r\n"), "greylisted error response ok"); Con_close(&con, &gs); List_destroy(&con.blacklists); /* * Test the connection reading function. */ memset(&src, 0, sizeof(src)); ((struct sockaddr_in *) &src)->sin_family = AF_INET; inet_pton(AF_INET, "10.10.10.1", &((struct sockaddr_in *) &src)->sin_addr); pipe(con_pipe); memset(&con, 0, sizeof(con)); Con_init(&con, con_pipe[0], &src, &gs); char *out = "EHLO greyd.org\r\n"; write(con_pipe[1], out, strlen(out)); Con_handle_read(&con, &now, &gs); /* This should change the state. */ TEST_OK(con.state == CON_STATE_HELO_IN, "Initial state set ok"); Con_handle_read(&con, &now, &gs); TEST_OK(!strcmp(con.in_buf, "EHLO greyd.org"), "con read ok"); TEST_OK(!strcmp(con.helo, "greyd.org"), "helo parsed ok"); TEST_OK(con.state = CON_STATE_HELO_OUT, "state helo out ok"); char *mail_from = "MAIL FROM: <*****@*****.**>\r\n"; write(con_pipe[1], mail_from, strlen(mail_from)); Con_next_state(&con, &now, &gs); TEST_OK(con.state = CON_STATE_MAIL_IN, "state mail in ok"); Con_handle_read(&con, &now, &gs); TEST_OK(!strcmp(con.mail, "*****@*****.**"), "MAIL FROM parsed ok"); TEST_OK(con.state = CON_STATE_MAIL_OUT, "state mail out ok"); char *rcpt = "RCPT TO: [email protected]\r\n"; write(con_pipe[1], rcpt, strlen(rcpt)); Con_next_state(&con, &now, &gs); TEST_OK(con.state = CON_STATE_RCPT_IN, "state rcpt in ok"); Con_handle_read(&con, &now, &gs); TEST_OK(!strcmp(con.rcpt, "*****@*****.**"), "RCPT parsed ok"); TEST_OK(con.state = CON_STATE_RCPT_OUT, "state rcpt out ok"); char *data = "DATA\r\n"; write(con_pipe[1], data, strlen(data)); Con_next_state(&con, &now, &gs); TEST_OK(con.state = CON_STATE_RCPT_IN, "state rcpt in ok"); /* this will goto spam. */ Con_handle_read(&con, &now, &gs); TEST_OK(con.state = CON_STATE_DATA_OUT, "state data out ok"); char *msg = "This is a spam message\r\ndeliver me!\r\n.\r\n"; write(con_pipe[1], msg, strlen(msg)); Con_next_state(&con, &now, &gs); TEST_OK(con.state = CON_STATE_MESSAGE, "state message ok"); Con_handle_read(&con, &now, &gs); TEST_OK(con.state = CON_STATE_CLOSE, "state close ok"); /* This should close the connection. */ Con_next_state(&con, &now, &gs); /* Cleanup. */ List_destroy(&con.blacklists); Hash_destroy(&gs.blacklists); Blacklist_destroy(&bl1); Blacklist_destroy(&bl2); Blacklist_destroy(&bl3); Config_destroy(&c); Config_parser_destroy(&cp); TEST_COMPLETE; }