#define MAX_CONNS 5
#define MAX_CONNS_LIMIT 16384
+#define log_err(...) syslog (LOG_ERR, MODULE_NAME": "__VA_ARGS__)
+#define log_warn(...) syslog (LOG_WARNING, MODULE_NAME": "__VA_ARGS__)
+
/*
* Private data structures
*/
/* Read a single character from the socket. If an error occurs or end-of-file
* is reached return '\0'. */
-char read_char (conn_t *src)
+static char read_char (conn_t *src)
{
char ret = '\0';
FD_SET (src->socket, &fdset);
if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
- syslog (LOG_ERR, "select() failed: %s", strerror (errno));
+ log_err ("select() failed: %s", strerror (errno));
return '\0';
}
errno = 0;
if (0 > (len = read (src->socket, (void *)&ret, 1))) {
if (EINTR != errno) {
- syslog (LOG_ERR, "read() failed: %s", strerror (errno));
+ log_err ("read() failed: %s", strerror (errno));
return '\0';
}
}
return '\0';
} while (EINTR == errno);
return ret;
-} /* char read_char (conn_t *) */
+} /* static char read_char (conn_t *) */
/* Read a single line (terminated by '\n') from the the socket.
*
* characters of the input stream, the line will will be ignored! By
* definition we should not get any longer input lines, thus this is
* acceptable in this case ;-) */
-char *read_line (conn_t *src)
+static char *read_line (conn_t *src)
{
int i = 0;
FD_SET (src->socket, &fdset);
if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
- syslog (LOG_ERR, "select() failed: %s", strerror (errno));
+ log_err ("select() failed: %s", strerror (errno));
return NULL;
}
(void *)(src->buffer + src->idx),
BUFSIZE - src->idx))) {
if (EINTR != errno) {
- syslog (LOG_ERR, "read() failed: %s", strerror (errno));
+ log_err ("read() failed: %s", strerror (errno));
return NULL;
}
}
src->length = i;
return src->buffer;
-} /* char *read_line (conn_t *) */
+} /* static char *read_line (conn_t *) */
static void *collect (void *arg)
{
errno = 0;
if (-1 == fcntl (connection->socket, F_GETFL, &flags)) {
- syslog (LOG_ERR, "fcntl() failed: %s", strerror (errno));
+ log_err ("fcntl() failed: %s", strerror (errno));
loop = 0;
}
errno = 0;
if (-1 == fcntl (connection->socket, F_SETFL, flags | O_NONBLOCK)) {
- syslog (LOG_ERR, "fcntl() failed: %s", strerror (errno));
+ log_err ("fcntl() failed: %s", strerror (errno));
loop = 0;
}
}
}
if (':' != line[1]) {
- syslog (LOG_ERR, "email: syntax error in line '%s'", line);
+ log_err ("syntax error in line '%s'", line);
continue;
}
int bytes = 0;
if (NULL == tmp) {
- syslog (LOG_ERR, "email: syntax error in line '%s'", line);
+ log_err ("syntax error in line '%s'", line);
continue;
}
} while (NULL != (type = strtok_r (NULL, ",", &ptr)));
}
else {
- syslog (LOG_ERR, "email: unknown type '%c'", line[0]);
+ log_err ("unknown type '%c'", line[0]);
}
} /* while (loop) */
free (buffer);
pthread_exit ((void *)0);
-} /* void *collect (void *) */
+} /* static void *collect (void *) */
static void *open_connection (void *arg)
{
errno = 0;
if (-1 == (connector_socket = socket (PF_UNIX, SOCK_STREAM, 0))) {
disabled = 1;
- syslog (LOG_ERR, "socket() failed: %s", strerror (errno));
+ log_err ("socket() failed: %s", strerror (errno));
pthread_exit ((void *)1);
}
offsetof (struct sockaddr_un, sun_path)
+ strlen(addr.sun_path))) {
disabled = 1;
- syslog (LOG_ERR, "bind() failed: %s", strerror (errno));
+ log_err ("bind() failed: %s", strerror (errno));
pthread_exit ((void *)1);
}
errno = 0;
if (-1 == listen (connector_socket, 5)) {
disabled = 1;
- syslog (LOG_ERR, "listen() failed: %s", strerror (errno));
+ log_err ("listen() failed: %s", strerror (errno));
pthread_exit ((void *)1);
}
if (NULL != (grp = getgrnam (sock_group))) {
errno = 0;
if (0 != chown (SOCK_PATH, (uid_t)-1, grp->gr_gid)) {
- syslog (LOG_WARNING, "chown() failed: %s", strerror (errno));
+ log_warn ("chown() failed: %s", strerror (errno));
}
}
else {
- syslog (LOG_WARNING, "getgrnam() failed: %s", strerror (errno));
+ log_warn ("getgrnam() failed: %s", strerror (errno));
}
}
else {
- syslog (LOG_WARNING, "not running as root");
+ log_warn ("not running as root");
}
errno = 0;
if (0 != chmod (SOCK_PATH, sock_perms)) {
- syslog (LOG_WARNING, "chmod() failed: %s", strerror (errno));
+ log_warn ("chmod() failed: %s", strerror (errno));
}
{ /* initialize collector threads */
if (0 != (err = pthread_create (&collectors[i]->thread, &ptattr,
collect, collectors[i]))) {
- syslog (LOG_ERR, "pthread_create() failed: %s",
- strerror (err));
+ log_err ("pthread_create() failed: %s", strerror (err));
}
}
if (-1 == (remote = accept (connector_socket, NULL, NULL))) {
if (EINTR != errno) {
disabled = 1;
- syslog (LOG_ERR, "accept() failed: %s", strerror (errno));
+ log_err ("accept() failed: %s", strerror (errno));
pthread_exit ((void *)1);
}
}
pthread_cond_signal (&conn_available);
}
pthread_exit ((void *)0);
-} /* void *open_connection (void *) */
+} /* static void *open_connection (void *) */
#endif /* EMAIL_HAVE_READ */
static void email_init (void)
if (0 != (err = pthread_create (&connector, NULL,
open_connection, NULL))) {
disabled = 1;
- syslog (LOG_ERR, "pthread_create() failed: %s", strerror (err));
+ log_err ("pthread_create() failed: %s", strerror (err));
return;
}
#endif /* EMAIL_HAVE_READ */
if (disabled)
return;
- close (connector_socket);
pthread_kill (connector, SIGTERM);
+ close (connector_socket);
/* don't allow any more connections to be processed */
pthread_mutex_lock (&conns_mutex);
for (i = 0; i < max_conns; ++i) {
- close (collectors[i]->socket);
pthread_kill (collectors[i]->thread, SIGTERM);
+ close (collectors[i]->socket);
}
pthread_mutex_unlock (&conns_mutex);
char buf[BUFSIZE] = "";
int len = 0;
- if (0 == value)
- return;
-
len = snprintf (buf, BUFSIZE, "%u:%i", (unsigned int)curtime, value);
if ((len < 0) || (len >= BUFSIZE))
return;
char buf[BUFSIZE] = "";
int len = 0;
- if (0.0 == value)
- return;
-
len = snprintf (buf, BUFSIZE, "%u:%.2f", (unsigned int)curtime, value);
if ((len < 0) || (len >= BUFSIZE))
return;
plugin_submit ("email_spam_score", NULL, buf);
return;
+} /* static void score_submit (double) */
+
+/* Copy list l1 to list l2. l2 may partly exist already, but it is assumed
+ * that neither the order nor the name of any element of either list is
+ * changed and no elements are deleted. The values of l1 are reset to zero
+ * after they have been copied to l2. */
+static void copy_type_list (type_list_t *l1, type_list_t *l2)
+{
+ type_t *ptr1;
+ type_t *ptr2;
+
+ type_t *last = NULL;
+
+ for (ptr1 = l1->head, ptr2 = l2->head; NULL != ptr1;
+ ptr1 = ptr1->next, last = ptr2, ptr2 = ptr2->next) {
+ if (NULL == ptr2) {
+ ptr2 = (type_t *)smalloc (sizeof (type_t));
+ ptr2->name = NULL;
+ ptr2->next = NULL;
+
+ if (NULL == last) {
+ l2->head = ptr2;
+ }
+ else {
+ last->next = ptr2;
+ }
+
+ l2->tail = ptr2;
+ }
+
+ if (NULL == ptr2->name) {
+ ptr2->name = sstrdup (ptr1->name);
+ }
+
+ ptr2->value = ptr1->value;
+ ptr1->value = 0;
+ }
+ return;
}
static void email_read (void)
{
type_t *ptr;
+ double sc;
+
+ static type_list_t *cnt;
+ static type_list_t *sz;
+ static type_list_t *chk;
+
if (disabled)
return;
- pthread_mutex_lock (&count_mutex);
+ if (NULL == cnt) {
+ cnt = (type_list_t *)smalloc (sizeof (type_list_t));
+ cnt->head = NULL;
+ }
- for (ptr = count.head; NULL != ptr; ptr = ptr->next) {
- type_submit ("email_count", ptr->name, ptr->value);
- ptr->value = 0;
+ if (NULL == sz) {
+ sz = (type_list_t *)smalloc (sizeof (type_list_t));
+ sz->head = NULL;
+ }
+
+ if (NULL == chk) {
+ chk = (type_list_t *)smalloc (sizeof (type_list_t));
+ chk->head = NULL;
}
+ /* email count */
+ pthread_mutex_lock (&count_mutex);
+
+ copy_type_list (&count, cnt);
+
pthread_mutex_unlock (&count_mutex);
+ for (ptr = cnt->head; NULL != ptr; ptr = ptr->next) {
+ type_submit ("email_count", ptr->name, ptr->value);
+ }
+
+ /* email size */
pthread_mutex_lock (&size_mutex);
- for (ptr = size.head; NULL != ptr; ptr = ptr->next) {
- type_submit ("email_size", ptr->name, ptr->value);
- ptr->value = 0;
- }
+ copy_type_list (&size, sz);
pthread_mutex_unlock (&size_mutex);
+ for (ptr = sz->head; NULL != ptr; ptr = ptr->next) {
+ type_submit ("email_size", ptr->name, ptr->value);
+ }
+
+ /* spam score */
pthread_mutex_lock (&score_mutex);
- score_submit (score);
+ sc = score;
score = 0.0;
score_count = 0;
pthread_mutex_unlock (&score_mutex);
+ score_submit (sc);
+
+ /* spam checks */
pthread_mutex_lock (&check_mutex);
- for (ptr = check.head; NULL != ptr; ptr = ptr->next) {
- type_submit ("email_spam_check", ptr->name, ptr->value);
- ptr->value = 0;
- }
+ copy_type_list (&check, chk);
pthread_mutex_unlock (&check_mutex);
+
+ for (ptr = chk->head; NULL != ptr; ptr = ptr->next) {
+ type_submit ("email_spam_check", ptr->name, ptr->value);
+ }
return;
} /* static void read (void) */
#else /* if !EMAIL_HAVE_READ */