Exemple #1
0
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);
}
Exemple #2
0
void HashSet_insert (T set, Poly_t x)
{
  if (Hash_lookup (set->hash, x))
    return;

  Hash_insert (set->hash, x, (Poly_t)1);
  return;
}
Exemple #3
0
/* 
 * _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);
}
Exemple #4
0
/*
 * _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);
}
Exemple #7
0
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;
}
Exemple #9
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;
}
Exemple #11
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;
}