/* 
 * _forwarding_setup
 *
 * 'index' is the index of the message config and forwarding info.
 * 
 * Returns 0 success, -1 on error
 */
static int
_forwarding_setup(int index)
{
  hostlist_iterator_t itr = NULL;
  char *node;
  int rv = -1;

  assert(index >= 0 && index < conf.forward_message_config_len);

  /* We require a separate hostlist here b/c the hosts input by the
   * user and/or received by the remote hosts need to be mapped to a
   * single hostname.
   */
  if ((forwarding_info[index].fd = _forwarding_setup_socket(index)) < 0)
    goto cleanup;
  if (conf.forward_message_config[index].hosts)
    {
      forwarding_info[index].hosts = Hostlist_create(NULL);
      itr = Hostlist_iterator_create(conf.forward_message_config[index].hosts);
      while ((node = Hostlist_next(itr)))
        {
          char nodebuf[CEREBRO_MAX_NODENAME_LEN+1];
          char *nodeptr;

          if (found_clusterlist_module)
            {
              if (clusterlist_module_get_nodename(clusterlist_handle,
                                                  node,
                                                  nodebuf, 
                                                  CEREBRO_MAX_NODENAME_LEN+1) < 0)
                {
                  CEREBROD_DBG(("clusterlist_module_get_nodename: %s", nodebuf));
                  Hostlist_destroy(forwarding_info[index].hosts);
                  goto cleanup;
                }
              nodeptr = nodebuf;
            }
          else
            nodeptr = node;
              
          Hostlist_push(forwarding_info[index].hosts, nodeptr);
          
          free(node);
        }
    }
  else
    forwarding_info[index].hosts = NULL;
  Pthread_mutex_init(&(forwarding_info[index].lock), NULL);
  rv = 0;
 cleanup:
  if (itr)
    Hostlist_iterator_destroy(itr);
  return rv;
}
Exemple #2
0
/* 
 * _get_userspace_metric_value
 *
 * Get the metric value data supplied by a userspace program
 *
 * Returns message metric data on success, NULL otherwise
 */
static struct cerebrod_message_metric *
_get_userspace_metric_value(struct cerebrod_speaker_metric_info *metric_info)
{
  struct cerebrod_message_metric *mm = NULL;
  u_int32_t mtype, mlen;
  void *mvalue;

  assert(metric_info);

#if CEREBRO_DEBUG
  if (metric_info->next_call_time)
    CEREBROD_DBG(("Unexpected next_call_time"));
#endif /* CEREBRO_DEBUG */

  mtype = metric_info->metric_value_type;
  mlen = metric_info->metric_value_len;
  mvalue = metric_info->metric_value;
  if (check_data_type_len_value(mtype, mlen, mvalue) < 0)
    goto cleanup;

  mm = Malloc(sizeof(struct cerebrod_message_metric));
  memset(mm, '\0', sizeof(struct cerebrod_message_metric));

  /* need not overflow */
  strncpy(mm->metric_name, 
          metric_info->metric_name, 
          CEREBRO_MAX_METRIC_NAME_LEN);

  mm->metric_value_type = metric_info->metric_value_type;
  mm->metric_value_len = metric_info->metric_value_len;
  if (mm->metric_value_len)
    {
      mm->metric_value = Malloc(metric_info->metric_value_len);
      memcpy(mm->metric_value, 
             metric_info->metric_value, 
             metric_info->metric_value_len);
    }
  else
    mm->metric_value = NULL;

  return mm;

 cleanup:
  if (mm)
    {
      if (mm->metric_value)
        Free(mm->metric_value);
      Free(mm);
    }
  return NULL;
}
Exemple #3
0
int
cerebrod_reinit_socket(int old_fd,
                       int num,
                       Cerebrod_socket_setup socket_setup,
                       char *msg)
{
    int fd = old_fd;

    assert(socket_setup && msg);

    if (errno == EINVAL
            || errno == EBADF
            || errno == ENODEV
            || errno == ENETDOWN
            || errno == ENETUNREACH
            || old_fd < 0)
    {
        if (!(old_fd < 0))
            close(old_fd);       /* no-wrapper, make best effort */

        if ((fd = socket_setup(num)) < 0)
        {
            CEREBROD_DBG(("%s: error re-initializing socket", msg));

            /* Wait a bit, so we don't spin */
            sleep(CEREBROD_REINITIALIZE_TIME);
        }
        else
            CEREBROD_DBG(("success re-initializing socket"));
    }
    else if (errno == EINTR)
        CEREBROD_DBG(("%s: %s", msg, strerror(errno)));
    else
        CEREBROD_EXIT(("%s: %s", msg, strerror(errno)));

    return fd;
}
Exemple #4
0
/*
 * _event_server_request_check_version
 *
 * Check that the version is correct prior to unmarshalling
 *
 * Returns 0 if version is correct, -1 if not
 */
static int
_event_server_request_check_version(const char *buf,
                                    unsigned int buflen,
                                    int32_t *version)
{
  assert(buflen >= sizeof(int32_t) && version);

  if (!Unmarshall_int32(version, buf, buflen))
    {
      CEREBROD_DBG(("version could not be unmarshalled"));
      return -1;
    }

  if (*version != CEREBRO_EVENT_SERVER_PROTOCOL_VERSION)
    return -1;
  
  return 0;
}
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;
}
void *
cerebrod_listener(void *arg)
{
  char buf[CEREBRO_MAX_PACKET_LEN];

  _cerebrod_listener_initialize();

  for (;;)
    {
      struct cerebrod_message *msg;
      char nodename_buf[CEREBRO_MAX_NODENAME_LEN+1];
      char nodename_key[CEREBRO_MAX_NODENAME_LEN+1];
      struct timeval tv;
      int in_cluster_flag, i, count;
      fd_set readfds;
      int recv_len = 0;
      int maxfd = 0;

      FD_ZERO(&readfds);
      Pthread_mutex_lock(&listener_fds_lock);
      for (i = 0; i < conf.listen_message_config_len; i++)
        {
          if (listener_fds[i] > maxfd)
            maxfd = listener_fds[i];
          FD_SET(listener_fds[i], &readfds);
        }

      count = Select(maxfd + 1, &readfds, NULL, NULL, NULL);

      for (i = 0; i < conf.listen_message_config_len; i++)
        {
          if (FD_ISSET(listener_fds[i], &readfds))
            {
              if ((recv_len = recvfrom(listener_fds[i], 
                                       buf, 
                                       CEREBRO_MAX_PACKET_LEN, 
                                       0, 
                                       NULL, 
                                       NULL)) < 0)
                listener_fds[i] = cerebrod_reinit_socket(listener_fds[i], 
                                                         i,
                                                         _listener_setup_socket, 
                                                         "listener: recvfrom");
              break;
            }
        }
      Pthread_mutex_unlock(&listener_fds_lock);

      /* No packet read */
      if (recv_len <= 0)
	continue;

      if (recv_len >= CEREBRO_MAX_PACKET_LEN)
        {
	  CEREBROD_DBG(("received truncated packet"));
          continue;
        }

      if (_cerebrod_message_check_version(buf, recv_len) < 0)
        {
	  CEREBROD_DBG(("received invalid version packet"));
          continue;
        }

      if (!(msg = _cerebrod_message_unmarshall(buf, recv_len)))
        {
	  CEREBROD_DBG(("received unmarshallable packet"));
          continue;
        }

      _cerebrod_message_dump(msg, "Received Message");
      
      /* Guarantee ending '\0' character */
      memset(nodename_buf, '\0', CEREBRO_MAX_NODENAME_LEN+1);
      memcpy(nodename_buf, msg->nodename, CEREBRO_MAX_NODENAME_LEN);

      if (!strlen(nodename_buf))
        {
          CEREBROD_DBG(("received null nodename"));
          cerebrod_message_destroy(msg);
          continue;
        }

      if (found_clusterlist_module)
        {
          if ((in_cluster_flag = clusterlist_module_node_in_cluster(clusterlist_handle,
                                                                    nodename_buf)) < 0)
            CEREBROD_EXIT(("clusterlist_module_node_in_cluster: %s", nodename_buf));

          /* Second chance, is this data being forwarded from another host */
          if (!in_cluster_flag)
            {
              if (Hostlist_find(conf.forward_host_accept, nodename_buf) >= 0)
                in_cluster_flag++;
            }
        }
      else
        /* must assume it is in the cluster */
        /* Note, there is no need to handle 'forward_host_accept' under this case, 
         * since we don't know if it is in the cluster or not anyways.
         */
        in_cluster_flag = 1;
      
      if (!in_cluster_flag)
	{
	  CEREBROD_DBG(("received non-cluster packet: %s", nodename_buf));
          cerebrod_message_destroy(msg);
	  continue;
	}
      
      memset(nodename_key, '\0', CEREBRO_MAX_NODENAME_LEN+1);

      if (found_clusterlist_module)
        {
          if (clusterlist_module_get_nodename(clusterlist_handle,
                                              nodename_buf,
                                              nodename_key, 
                                              CEREBRO_MAX_NODENAME_LEN+1) < 0)
            {
              CEREBROD_DBG(("clusterlist_module_get_nodename: %s", nodename_buf));
              cerebrod_message_destroy(msg);
              continue;
            }
        }
      else
        memcpy(nodename_key, nodename_buf, CEREBRO_MAX_NODENAME_LEN+1);

      Gettimeofday(&tv, NULL);
      cerebrod_listener_data_update(nodename_key, msg, tv.tv_sec);

      /* Forward data as necessary.  Note, there is no need to
       * marshall data, it should already be marshalled when we
       * read it earlier.
       */
      for (i = 0; i < conf.forward_message_config_len; i++)
        {
          /* if the forward destination is local to the machine, don't forward */
          if (conf.forward_message_config[i].ip_is_local)
            continue;

          if (!forwarding_info[i].hosts
              || hostlist_find(forwarding_info[i].hosts, nodename_key) >= 0)
            {
              struct sockaddr *addr;
              struct sockaddr_in msgaddr;
              unsigned int addrlen;
              int rv;
              
              memset(&msgaddr, '\0', sizeof(struct sockaddr_in));
              msgaddr.sin_family = AF_INET;
              msgaddr.sin_port = htons(conf.forward_message_config[i].destination_port);
              memcpy(&msgaddr.sin_addr,
                     &conf.forward_message_config[i].ip_in_addr,
                     sizeof(struct in_addr));
              
              addr = (struct sockaddr *)&msgaddr;
              addrlen = sizeof(struct sockaddr_in);
              
              _cerebrod_message_dump(msg, "Forwarding Message");

              Pthread_mutex_lock(&forwarding_info[i].lock);
              
              if ((rv = sendto(forwarding_info[i].fd,
                               buf,
                               recv_len,
                               0,
                               addr,
                               addrlen)) != recv_len)
                {
                  if (rv < 0)
                    forwarding_info[i].fd = cerebrod_reinit_socket(forwarding_info[i].fd,
                                                                   i,
                                                                   _forwarding_setup_socket,
                                                                   "forwarding: sendto");
                  else
                    CEREBROD_ERR(("sendto: invalid bytes sent"));
                }
              
              Pthread_mutex_unlock(&forwarding_info[i].lock);
            }
        }

      cerebrod_message_destroy(msg);
    }

  return NULL;			/* NOT REACHED */
}
/*
 * _cerebrod_message_unmarshall
 *
 * unmarshall contents of a message packet buffer and
 * return in an allocated message
 *
 * Returns message data on success, NULL on error
 */
static struct cerebrod_message *
_cerebrod_message_unmarshall(const char *buf, unsigned int buflen)
{
  struct cerebrod_message *msg = NULL;
  struct cerebrod_message_metric *mm = NULL;
  unsigned int size;
  char *bufPtr;
  int i, n, bufPtrlen, c = 0;

  assert(buf);
  
  msg = Malloc(sizeof(struct cerebrod_message));

  memset(msg, '\0', sizeof(struct cerebrod_message));
  
  if (!(n = Unmarshall_int32(&(msg->version), buf + c, buflen - c)))
    goto cleanup;
  c += n;

  bufPtr = msg->nodename;
  bufPtrlen = sizeof(msg->nodename);
  if (!(n = Unmarshall_buffer(bufPtr, bufPtrlen, buf + c, buflen - c)))
    goto cleanup;
  c += n;
  
  if (!(n = Unmarshall_u_int32(&(msg->metrics_len), buf + c, buflen - c)))
    goto cleanup;
  c += n;

  /* If no metrics in this packet, just return with the header */
  if (!msg->metrics_len)
    {
      if (buflen != CEREBROD_MESSAGE_HEADER_LEN)
        {
          CEREBROD_DBG(("invalid packet length for no metrics"));
          goto cleanup;
        }
      msg->metrics = NULL;
      return msg;
    }
  
  size = sizeof(struct cerebrod_message_metric *)*(msg->metrics_len + 1);
  msg->metrics = Malloc(size);
  memset(msg->metrics, '\0', size);
      
  for (i = 0; i < msg->metrics_len; i++)
    {
      char *mname;
      int mnamelen;

      mm = Malloc(sizeof(struct cerebrod_message_metric));
      memset(mm, '\0', sizeof(struct cerebrod_message_metric));
      
      mname = mm->metric_name;
      mnamelen = sizeof(mm->metric_name);
      
      if (!(n = Unmarshall_buffer(mname, mnamelen, buf + c, buflen - c)))
        goto cleanup;
      c += n;
      
      if ((n = unmarshall_data_type_len(&(mm->metric_value_type),
                                        &(mm->metric_value_len),
                                        buf + c, 
                                        buflen - c,
                                        NULL)) < 0)
        goto cleanup;
      c += n;
      
      if (check_data_type_len(mm->metric_value_type, mm->metric_value_len) < 0)
        goto cleanup;

      mm->metric_value = NULL;
      if (mm->metric_value_len)
        {
          mm->metric_value = Malloc(mm->metric_value_len);
          if ((n = unmarshall_data_value(mm->metric_value_type, 
                                         mm->metric_value_len,
                                         mm->metric_value,
                                         mm->metric_value_len,
                                         buf + c,
                                         buflen - c,
                                         NULL)) < 0)
            goto cleanup;
          c += n;
        }

      msg->metrics[i] = mm;
    }
  mm = NULL;

  return msg;

 cleanup:
  if (mm)
    {
      if (mm->metric_value)
        Free(mm->metric_value);
      Free(mm);
    }

  if (msg)
    {
      if (msg->metrics)
        {
          i = 0;
          while (msg->metrics[i])
            {
              if (msg->metrics[i]->metric_value)
                Free(msg->metrics[i]->metric_value);
              Free(msg->metrics[i]);
              i++;
            }
          Free(msg->metrics);
        }
      Free(msg);
    }
  return NULL;
}
Exemple #9
0
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 */
}
Exemple #10
0
void *
cerebrod_event_server(void *arg)
{
  int server_fd;

  _event_server_initialize();

  if ((server_fd = _event_server_setup_socket(0)) < 0)
    CEREBROD_EXIT(("event server fd setup failed"));

  for (;;)
    {
      ListIterator eitr;
      struct cerebrod_event_connection_data *ecd;
      struct pollfd *pfds;
      int pfdslen = 0;
      int i;

      /* Note that the list_count won't grow larger after the first
       * mutex block, b/c the cerebrod_event_queue_monitor thread can
       * never add to the event_connections.  It can only shrink it.
       */
      Pthread_mutex_lock(&event_connections_lock);
      if (event_connections)
        pfdslen = List_count(event_connections);
      Pthread_mutex_unlock(&event_connections_lock);

      /* The + 1 is b/c of the server_fd. */
      pfdslen++;

      pfds = Malloc(sizeof(struct pollfd) * pfdslen);
      memset(pfds, '\0', sizeof(struct pollfd) * pfdslen);

      pfds[0].fd = server_fd;
      pfds[0].events = POLLIN;
      pfds[0].revents = 0;

      /* No 'event_connections' if there are no events */
      if (event_connections)
        {
          i = 1;
          Pthread_mutex_lock(&event_connections_lock);
          eitr = List_iterator_create(event_connections);
          while ((ecd = list_next(eitr)))
            {
              pfds[i].fd = ecd->fd;
              pfds[i].events = POLLIN;
              pfds[i].revents = 0;
              i++;
            }
          List_iterator_destroy(eitr);
          Pthread_mutex_unlock(&event_connections_lock);
        }
      
      Poll(pfds, pfdslen, -1);

      /* Deal with the server fd first */
      if (pfds[0].revents & POLLERR)
        CEREBROD_DBG(("server_fd POLLERR"));
      else if (pfds[0].revents & POLLIN)
        {
          unsigned int client_addr_len;
          int fd;
          struct sockaddr_in client_addr;

          client_addr_len = sizeof(struct sockaddr_in);
          if ((fd = accept(server_fd,
                           (struct sockaddr *)&client_addr,
                           &client_addr_len)) < 0)
            server_fd = cerebrod_reinit_socket(server_fd,
                                               0,
                                               _event_server_setup_socket,
                                               "event_server: accept");
          if (fd >= 0)
            _event_server_service_connection(fd);
        }

      /* Deal with the connecting fds */
      for (i = 1; i < pfdslen; i++)
        {
          if (pfds[i].revents & POLLERR)
            {
              CEREBROD_DBG(("fd = %d POLLERR", pfds[i].fd));
              Pthread_mutex_lock(&event_connections_lock);
              _delete_event_connection_fd(pfds[i].fd);
              Pthread_mutex_unlock(&event_connections_lock);
              continue;
            }

          if (pfds[i].revents & POLLIN)
            {
              char buf[CEREBRO_MAX_PACKET_LEN];
              int n;

              /* We should not expect any actual data.  If
               * we get some, just eat it and move on.
               *
               * The common situation is that the client
               * closes the connection.  So we need to delete
               * our fd.
               */

              n = fd_read_n(pfds[i].fd, 
                            buf,
                            CEREBRO_MAX_PACKET_LEN);
              if (n < 0)
                CEREBROD_DBG(("fd_read_n = %s", strerror(errno)));

              if (n <= 0)
                {
                  if (conf.debug && conf.event_server_debug)
                    {
                      Pthread_mutex_lock(&debug_output_mutex);
                      fprintf(stderr, "**************************************\n");
                      fprintf(stderr, "* Event Server Close Fd: %d\n", pfds[i].fd);
                      fprintf(stderr, "**************************************\n");
                      Pthread_mutex_unlock(&debug_output_mutex);
                    }
                  Pthread_mutex_lock(&event_connections_lock);
                  _delete_event_connection_fd(pfds[i].fd);
                  Pthread_mutex_unlock(&event_connections_lock);
                }
            }
        }
      
      Free(pfds);
    }

  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;
}
Exemple #12
0
/* 
 * _get_module_metric_value
 *
 * Get the metric value data from a module
 *
 * Returns message metric data on success, NULL otherwise
 */
static struct cerebrod_message_metric *
_get_module_metric_value(unsigned int index)
{
  struct cerebrod_message_metric *mm = NULL;
  char *metric_name;
  u_int32_t mtype, mlen;
  void *mvalue = NULL;

  assert(index < metric_handle_count);

  mm = Malloc(sizeof(struct cerebrod_message_metric));
  memset(mm, '\0', sizeof(struct cerebrod_message_metric));

  if (!(metric_name = metric_module_get_metric_name(metric_handle, index)))
    {
      CEREBROD_DBG(("metric_module_get_metric_name: %d", index));
      goto cleanup;
    }

  /* need not overflow */
  strncpy(mm->metric_name, metric_name, CEREBRO_MAX_METRIC_NAME_LEN);
  
  if (metric_module_get_metric_value(metric_handle,
                                     index,
                                     &mtype,
                                     &mlen,
                                     &mvalue) < 0)
    {
      CEREBROD_DBG(("metric_module_get_metric_value: %d", index));
      goto cleanup;
    }

  if (mtype == CEREBRO_DATA_VALUE_TYPE_STRING 
      && mlen > CEREBRO_MAX_DATA_STRING_LEN)
    {
      CEREBROD_DBG(("truncate metric string: %d", mlen));
      mlen = CEREBRO_MAX_DATA_STRING_LEN;
    }
 
  if (mtype == CEREBRO_DATA_VALUE_TYPE_STRING && !mlen)
    {
      CEREBROD_DBG(("adjusting metric type to none"));
      mtype = CEREBRO_DATA_VALUE_TYPE_NONE;
    }

  if (check_data_type_len_value(mtype, mlen, mvalue) < 0)
    goto cleanup;

  mm->metric_value_type = mtype;
  mm->metric_value_len = mlen;
  if (mm->metric_value_len)
    {
      mm->metric_value = Malloc(mm->metric_value_len);
      memcpy(mm->metric_value, mvalue, mm->metric_value_len);
    }
  else
    mm->metric_value = NULL;
  metric_module_destroy_metric_value(metric_handle, index, mvalue);
  
  return mm;

 cleanup:
  
  if (mvalue)
    metric_module_destroy_metric_value(metric_handle, index, mvalue);

  if (mm)
    {
      if (mm->metric_value)
        Free(mm->metric_value);
      Free(mm);
    }
 
  return NULL;
}
Exemple #13
0
/* 
 * _setup_metric_modules
 *
 * Setup metric modules. Under almost any circumstance, don't return a
 * -1 error, cerebro can go on without loading metric modules.
 *
 * Returns 1 if modules are loaded, 0 if not, -1 on error
 */
static int
_setup_metric_modules(void)
{
  int i;
#if CEREBRO_DEBUG
#if !WITH_CEREBROD_NO_THREADS
  int rv;
#endif /* !WITH_CEREBROD_NO_THREADS */
#endif /* CEREBRO_DEBUG */

  assert(metric_list);

#if CEREBRO_DEBUG
#if !WITH_CEREBROD_NO_THREADS
  /* Should be called with lock already set */
  rv = Pthread_mutex_trylock(&metric_list_lock);
  if (rv != EBUSY)
    CEREBROD_EXIT(("mutex not locked: rv=%d", rv));
#endif /* !WITH_CEREBROD_NO_THREADS */
#endif /* CEREBRO_DEBUG */

  if (!(metric_handle = metric_modules_load()))
    {
      CEREBROD_DBG(("metric_modules_load"));
      goto cleanup;
    }
  
  if ((metric_handle_count = metric_modules_count(metric_handle)) < 0)
    {
      CEREBROD_DBG(("metric_module_count failed"));
      goto cleanup;
    }
  
  if (!metric_handle_count)
    {
      if (conf.debug && conf.speak_debug)
        {
#if !WITH_CEREBROD_NO_THREADS
          Pthread_mutex_lock(&debug_output_mutex);
#endif /* !WITH_CEREBROD_NO_THREADS */
          fprintf(stderr, "**************************************\n");
          fprintf(stderr, "* No Metric Modules Found\n");
          fprintf(stderr, "**************************************\n");
#if !WITH_CEREBROD_NO_THREADS
          Pthread_mutex_unlock(&debug_output_mutex);
#endif /* !WITH_CEREBROD_NO_THREADS */
        }
      goto cleanup;
    }

  for (i = 0; i < metric_handle_count; i++)
    {
      struct cerebrod_speaker_metric_info *metric_info;
#if !WITH_CEREBROD_NO_THREADS
      Cerebro_metric_thread_pointer threadPtr;
#endif /* !WITH_CEREBROD_NO_THREADS */
      char *module_name, *metric_name;
      int metric_period;
      u_int32_t metric_flags;
      
      module_name = metric_module_name(metric_handle, i);

      if (conf.metric_module_exclude_len)
        {
          int found_exclude = 0;
          int j;

          for (j = 0; j < conf.metric_module_exclude_len; j++)
            {
              if (!strcasecmp(conf.metric_module_exclude[j], module_name))
                {
                  found_exclude++;
                  break;
                }
            }
          
          if (found_exclude)
            {
              if (conf.debug && conf.speak_debug)
                {
#if !WITH_CEREBROD_NO_THREADS
                  Pthread_mutex_lock(&debug_output_mutex);
#endif /* !WITH_CEREBROD_NO_THREADS */
                  fprintf(stderr, "**************************************\n");
                  fprintf(stderr, "* Skip Metric Module: %s\n", module_name);
                  fprintf(stderr, "**************************************\n");
#if !WITH_CEREBROD_NO_THREADS
                  Pthread_mutex_unlock(&debug_output_mutex);
#endif /* !WITH_CEREBROD_NO_THREADS */
                }
              CEREBROD_ERR(("Dropping metric module: %s", module_name));
              continue;
            }
        }
      
      if (conf.debug && conf.speak_debug)
        {
#if !WITH_CEREBROD_NO_THREADS
          Pthread_mutex_lock(&debug_output_mutex);
#endif /* !WITH_CEREBROD_NO_THREADS */
          fprintf(stderr, "**************************************\n");
          fprintf(stderr, "* Setup Metric Module: %s\n", module_name);
          fprintf(stderr, "**************************************\n");
#if !WITH_CEREBROD_NO_THREADS
          Pthread_mutex_unlock(&debug_output_mutex);
#endif /* !WITH_CEREBROD_NO_THREADS */
        }

      if (metric_module_setup(metric_handle, i) < 0)
        {
          CEREBROD_DBG(("metric_module_setup: %s", module_name));
          continue;
        }

      if (!(metric_name = metric_module_get_metric_name(metric_handle, i)))
        {
          CEREBROD_DBG(("metric_module_get_metric_name: %s", module_name));
          metric_module_cleanup(metric_handle, i);
          continue;
        }

      if (metric_module_get_metric_period(metric_handle, i, &metric_period) < 0)
        {
          CEREBROD_DBG(("metric_module_get_metric_period: %s", module_name));
          metric_module_cleanup(metric_handle, i);
          continue;
        }

      if (metric_module_get_metric_flags(metric_handle, i, &metric_flags) < 0)
        {
          CEREBROD_DBG(("metric_module_get_metric_flags: %s", module_name));
          metric_module_cleanup(metric_handle, i);
          continue;
        }

      if (metric_flags & CEREBRO_METRIC_MODULE_FLAGS_SEND_ON_PERIOD
          && metric_period <= 0)
        {
          CEREBROD_DBG(("metric module period invalid: %s", module_name));
          metric_module_cleanup(metric_handle, i);
          continue;
        }

      if (metric_module_send_message_function_pointer(metric_handle, i, &cerebrod_send_message) < 0)
        {
          CEREBROD_DBG(("metric_module_send_message_function_pointer: %s", module_name));
          metric_module_cleanup(metric_handle, i);
          continue;
        }
 
      metric_info = Malloc(sizeof(struct cerebrod_speaker_metric_info));
      /* No need to Strdup() the name in this case */
      metric_info->metric_name = metric_name;
      metric_info->metric_origin = CEREBROD_METRIC_SPEAKER_ORIGIN_MODULE;

      metric_info->metric_period = metric_period;
      metric_info->metric_flags = metric_flags;
      metric_info->index = i;

      /* 
       * If metric period is < 0, it presumably never will be sent
       * (metric is likely handled by a metric_thread), so set
       * next_call_time to UINT_MAX.
       *
       * If this is a metric that will be piggy-backed on heartbeats,
       * then initialize next_call_time to 0, so the data is sent on
       * the first heartbeat 
       *
       * If this is a metric that will not be piggy-backed on
       * heartbeats, set the next_call_time to UINT_MAX.  Let the
       * speaker logic decide when packets should be sent.
       */
      if (metric_info->metric_period < 0
          || metric_info->metric_flags & CEREBRO_METRIC_MODULE_FLAGS_SEND_ON_PERIOD)
        metric_info->next_call_time = UINT_MAX;
      else
        metric_info->next_call_time = 0;
      
      List_append(metric_list, metric_info);
      metric_list_size++;

#if !WITH_CEREBROD_NO_THREADS
      if ((threadPtr = metric_module_get_metric_thread(metric_handle, i)))
        {          
          pthread_t thread;
          pthread_attr_t attr;
          
          Pthread_attr_init(&attr);
          Pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
          Pthread_attr_setstacksize(&attr, CEREBROD_THREAD_STACKSIZE);
          Pthread_create(&thread, &attr, threadPtr, NULL);
          Pthread_attr_destroy(&attr);
        }
#endif /* !WITH_CEREBROD_NO_THREADS */
    }
  
  if (!metric_list_size)
    goto cleanup;

  cerebrod_speaker_data_metric_list_sort();
  return 1;

 cleanup:
  if (metric_handle)
    {
      /* unload will call module cleanup functions */
      metric_modules_unload(metric_handle);
      metric_handle = NULL;
      metric_handle_count = 0;
    }
  metric_list_size = 0;
  return 0;
}