+ if (shutdown == 1) {
+ // Since the thread is blocking, calling pthread_join
+ // doesn't actually succeed in stopping it. It will stick around
+ // until a message is received on the socket (at which
+ // it will realize that "sysevent_socket_thread_loop" is 0 and will
+ // break out of the read loop and be allowed to die). This is
+ // fine when the process isn't supposed to be exiting, but in
+ // the case of a process shutdown, we don't want to have an
+ // idle thread hanging around. Calling pthread_cancel here in
+ // the case of a shutdown is just assures that the thread is
+ // gone and that the process has been fully terminated.
+
+ DEBUG("sysevent plugin: Canceling socket thread for process shutdown");
+
+ status = pthread_cancel(sysevent_socket_thread_id);
+
+ if (status != 0 && status != ESRCH) {
+ ERROR("sysevent plugin: Unable to cancel socket thread: %d (%s)", status,
+ STRERRNO);
+ status = -1;
+ } else
+ status = 0;
+ } else {
+ status = pthread_join(sysevent_socket_thread_id, /* return = */ NULL);
+ if (status != 0 && status != ESRCH) {
+ ERROR("sysevent plugin: Stopping socket thread failed.");
+ status = -1;
+ } else
+ status = 0;
+ }
+
+ pthread_mutex_lock(&sysevent_thread_lock);
+ memset(&sysevent_socket_thread_id, 0, sizeof(sysevent_socket_thread_id));
+ sysevent_socket_thread_error = 0;
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ DEBUG("sysevent plugin: Finished requesting stop of socket thread");
+
+ return status;
+} /* }}} int stop_socket_thread */
+
+static int stop_dequeue_thread() /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (sysevent_dequeue_thread_loop == 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+ return -1;
+ }
+
+ sysevent_dequeue_thread_loop = 0;
+ pthread_cond_broadcast(&sysevent_cond);
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ // Since the thread is blocking, calling pthread_join
+ // doesn't actually succeed in stopping it. It will stick around
+ // until a message is received on the socket (at which
+ // it will realize that "sysevent_dequeue_thread_loop" is 0 and will
+ // break out of the read loop and be allowed to die). Since this
+ // function is called when the processing is exiting, we don't want to
+ // have an idle thread hanging around. Calling pthread_cancel here
+ // just assures that the thread is gone and that the process has been
+ // fully terminated.
+
+ DEBUG("sysevent plugin: Canceling dequeue thread for process shutdown");
+
+ int status = pthread_cancel(sysevent_dequeue_thread_id);
+
+ if (status != 0 && status != ESRCH) {
+ ERROR("sysevent plugin: Unable to cancel dequeue thread: %d (%s)", status,
+ STRERRNO);
+ status = -1;
+ } else
+ status = 0;
+
+ pthread_mutex_lock(&sysevent_thread_lock);
+ memset(&sysevent_dequeue_thread_id, 0, sizeof(sysevent_dequeue_thread_id));
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ DEBUG("sysevent plugin: Finished requesting stop of dequeue thread");
+
+ return status;
+} /* }}} int stop_dequeue_thread */
+
+static int stop_threads() /* {{{ */
+{
+ int status = stop_socket_thread(1);
+ int status2 = stop_dequeue_thread();
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int stop_threads */
+
+static int sysevent_init(void) /* {{{ */
+{
+ ring.head = 0;
+ ring.tail = 0;
+ ring.maxLen = buffer_length;
+ ring.buffer = (char **)calloc(buffer_length, sizeof(char *));
+
+ if (ring.buffer == NULL) {
+ ERROR("sysevent plugin: sysevent_init ring buffer calloc failed");
+ return -1;
+ }
+
+ for (int i = 0; i < buffer_length; i++) {
+ ring.buffer[i] = calloc(1, listen_buffer_size);
+
+ if (ring.buffer[i] == NULL) {
+ ERROR("sysevent plugin: sysevent_init ring buffer entry calloc failed");
+ return -1;
+ }
+ }
+
+ ring.timestamp = (cdtime_t *)calloc(buffer_length, sizeof(cdtime_t));
+
+ if (ring.timestamp == NULL) {
+ ERROR("sysevent plugin: sysevent_init ring buffer timestamp calloc failed");
+ return -1;
+ }
+
+ if (sock == -1) {
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_protocol = 0,
+ .ai_flags = AI_PASSIVE | AI_ADDRCONFIG,
+ };
+ struct addrinfo *res = 0;
+
+ int err = getaddrinfo(listen_ip, listen_port, &hints, &res);
+
+ if (err != 0) {
+ ERROR("sysevent plugin: failed to resolve local socket address (err=%d)",
+ err);
+ freeaddrinfo(res);
+ return -1;
+ }
+
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (sock == -1) {
+ ERROR("sysevent plugin: failed to open socket: %s", STRERRNO);
+ freeaddrinfo(res);
+ return -1;
+ }
+
+ if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
+ ERROR("sysevent plugin: failed to bind socket: %s", STRERRNO);
+ freeaddrinfo(res);
+ sock = -1;
+ return -1;
+ }
+
+ freeaddrinfo(res);
+ }
+
+ DEBUG("sysevent plugin: socket created and bound");
+
+ return start_threads();
+} /* }}} int sysevent_init */
+
+static int sysevent_config_add_listen(const oconfig_item_t *ci) /* {{{ */
+{
+ if (ci->values_num != 2 || ci->values[0].type != OCONFIG_TYPE_STRING ||
+ ci->values[1].type != OCONFIG_TYPE_STRING) {
+ ERROR("sysevent plugin: The `%s' config option needs "
+ "two string arguments (ip and port).",
+ ci->key);
+ return -1;
+ }
+
+ listen_ip = strdup(ci->values[0].value.string);
+ listen_port = strdup(ci->values[1].value.string);
+
+ return 0;
+}
+
+static int sysevent_config_add_buffer_size(const oconfig_item_t *ci) /* {{{ */
+{
+ int tmp = 0;
+
+ if (cf_util_get_int(ci, &tmp) != 0)
+ return -1;
+ else if ((tmp >= 1024) && (tmp <= 65535))
+ listen_buffer_size = tmp;
+ else {
+ WARNING(
+ "sysevent plugin: The `BufferSize' must be between 1024 and 65535.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sysevent_config_add_buffer_length(const oconfig_item_t *ci) /* {{{ */
+{
+ int tmp = 0;
+
+ if (cf_util_get_int(ci, &tmp) != 0)
+ return -1;
+ else if ((tmp >= 3) && (tmp <= 4096))
+ buffer_length = tmp;
+ else {
+ WARNING("sysevent plugin: The `Bufferlength' must be between 3 and 4096.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sysevent_config_add_regex_filter(const oconfig_item_t *ci) /* {{{ */
+{
+ if (ci->values_num != 1 || ci->values[0].type != OCONFIG_TYPE_STRING) {
+ ERROR("sysevent plugin: The `%s' config option needs "
+ "one string argument, a regular expression.",
+ ci->key);
+ return -1;
+ }
+
+#if HAVE_REGEX_H
+ if (ignorelist == NULL)
+ ignorelist = ignorelist_create(/* invert = */ 1);
+
+ int status = ignorelist_add(ignorelist, ci->values[0].value.string);
+
+ if (status != 0) {
+ ERROR("sysevent plugin: invalid regular expression: %s",
+ ci->values[0].value.string);
+ return 1;
+ }
+
+ monitor_all_messages = 0;
+#else
+ WARNING("sysevent plugin: The plugin has been compiled without support "
+ "for the \"RegexFilter\" option.");
+#endif
+
+ return 0;
+}
+
+static int sysevent_config(oconfig_item_t *ci) /* {{{ */
+{
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp("Listen", child->key) == 0)
+ sysevent_config_add_listen(child);
+ else if (strcasecmp("BufferSize", child->key) == 0)
+ sysevent_config_add_buffer_size(child);
+ else if (strcasecmp("BufferLength", child->key) == 0)
+ sysevent_config_add_buffer_length(child);
+ else if (strcasecmp("RegexFilter", child->key) == 0)
+ sysevent_config_add_regex_filter(child);
+ else {
+ WARNING("sysevent plugin: Option `%s' is not allowed here.", child->key);
+ }
+ }
+
+ return 0;
+} /* }}} int sysevent_config */
+
+static int sysevent_read(void) /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (sysevent_socket_thread_error != 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ ERROR("sysevent plugin: The sysevent socket thread had a problem (%d). "
+ "Restarting it.",
+ sysevent_socket_thread_error);
+
+ stop_threads();
+
+ start_threads();
+
+ return -1;
+ } /* if (sysevent_socket_thread_error != 0) */
+
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ return 0;
+} /* }}} int sysevent_read */
+
+static int sysevent_shutdown(void) /* {{{ */
+{