summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2006-03-29 04:01:41 +0000
committerStef Walter <stef@memberwebs.com>2006-03-29 04:01:41 +0000
commitfd9f86dd89a675a3e8a3255acf3e8349b166aff7 (patch)
treeca81c4c8c75027dec78c2b2fb361988817341f76
parentb2b5114fa36aeafcf9f177393d02ee6f9b63bbc4 (diff)
Added socket support to bsnmp-regex.
-rw-r--r--Makefile.am2
-rw-r--r--configure.in6
-rw-r--r--module/bsnmp-regex.c243
-rw-r--r--module/regex-tree.def2
-rw-r--r--tools/Makefile.am6
-rw-r--r--tools/sockin.c211
6 files changed, 404 insertions, 66 deletions
diff --git a/Makefile.am b/Makefile.am
index 9bb1356..f18715b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
# EXTRA_DIST = BUGS
-SUBDIRS = module
+SUBDIRS = module tools
diff --git a/configure.in b/configure.in
index 4f0935b..1bb5a78 100644
--- a/configure.in
+++ b/configure.in
@@ -24,10 +24,6 @@ if test "$enable_debug" = "yes"; then
echo "enabling debug compile mode"
fi
-# Some checks for libraries
-AC_CHECK_LIB(bsnmp, snmp_close, ,
- [echo "Couldn't find the bsnmp library"; exit 1])
-
# Checks for header files.
AC_HEADER_STDC
@@ -52,5 +48,5 @@ AC_FUNC_MALLOC
AC_FUNC_MEMCMP
dnl TODO AC_CHECK_FUNCS([atexit inet_ntoa inet_pton memset strerror strspn strtol])
-AC_CONFIG_FILES([Makefile module/Makefile])
+AC_CONFIG_FILES([Makefile module/Makefile tools/Makefile])
AC_OUTPUT
diff --git a/module/bsnmp-regex.c b/module/bsnmp-regex.c
index 98a94a9..4a75a7c 100644
--- a/module/bsnmp-regex.c
+++ b/module/bsnmp-regex.c
@@ -1,10 +1,49 @@
+/*
+ * Copyright (c) 2006, Nate Nielsen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Nate Nielsen <nielsen@memberwebs.com>
+ */
#include "usuals.h"
+#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
+#include <sys/un.h>
#include <syslog.h>
#include <unistd.h>
#include <stdarg.h>
@@ -23,7 +62,7 @@
#include "regex_oid.h"
#define DEFAULT_CONFIG CONF_PREFIX "/rrdbot"
-#define DEFAULT_FIFO "/var/run/snmp-regex.fifo"
+#define DEFAULT_SOCKET "/var/run/snmp-regex.sock"
/* our module handle */
static struct lmodule *module;
@@ -62,23 +101,32 @@ struct data_entry {
TAILQ_HEAD(data_entry_list, data_entry);
-/* list of peers */
+/* list of regexes */
static struct data_entry_list entries = TAILQ_HEAD_INITIALIZER(entries);
static uint32_t entry_count = 0;
-
/* configuration */
static u_char *regex_config = NULL;
static char *config_memory = NULL;
-/* The FIFO log */
-static u_char *regex_fifo = NULL;
-static int fifo_fd = -1;
-static void *fifo_sel = NULL;
+/* The socket to read from */
+static u_char *regex_sock = NULL;
+static int sock_fd = -1;
+static void *sock_sel = NULL;
-/* Buffer for parsing logs */
#define LINE_LENGTH 1024
-static char line_buffer[LINE_LENGTH];
+
+struct connection {
+ int fd;
+ void *sel;
+ char line_buffer[LINE_LENGTH];
+ TAILQ_ENTRY(connection) link;
+};
+
+TAILQ_HEAD(connection_list, connection);
+
+/* List of connections */
+static struct connection_list connections = TAILQ_HEAD_INITIALIZER(connections);
/* -----------------------------------------------------------------------------
* HELPERS
@@ -377,42 +425,55 @@ process_log (char *line, int len)
}
/* -----------------------------------------------------------------------------
- * LOG READING
+ * SOCKET HANDLING
*/
static void
-close_fifo ()
+close_connection (struct connection *conn)
{
- if (fifo_sel) {
- fd_deselect (fifo_sel);
- fifo_sel = NULL;
- }
+ if (conn->sel)
+ fd_deselect (conn->sel);
+ conn->sel = NULL;
- if (fifo_fd != -1) {
- close (fifo_fd);
- fifo_fd = -1;
- }
+ if (conn->fd >= 0)
+ close (conn->fd);
+ conn->fd = -1;
- memset (line_buffer, 0, sizeof (line_buffer));
+ free (conn);
+ TAILQ_REMOVE (&connections, conn, link);
}
static void
-receive_log (int fd, void *data)
+io_data (int fd, void *user_data)
{
+ struct connection *conn = (struct connection*)user_data;
+ char *line_buffer;
char *t;
int len;
int r, l;
- ASSERT (fd == fifo_fd);
+ fprintf(stderr, "io data\n");
+
+ ASSERT (fd == conn->fd);
+ line_buffer = conn->line_buffer;
len = strlen (line_buffer);
ASSERT (len < LINE_LENGTH);
+fprintf (stderr, "going to read: ");
do {
r = read (fd, line_buffer + len, (LINE_LENGTH - 1) - len);
+fprintf (stderr, "done: %d\n", r);
+ /* An error, close */
if (r < 0 && errno != EAGAIN) {
- emsg ("couldn't read from fifo: %s: %s", regex_fifo, strerror (errno));
+ emsg ("couldn't read from socket: %s: %s", regex_sock, strerror (errno));
+ close_connection (conn);
+ return;
+
+ /* Connection is finished, close */
+ } else if (r == 0) {
+ close_connection (conn);
return;
/* Got data, null terminate */
@@ -449,47 +510,114 @@ receive_log (int fd, void *data)
} while (r > 0);
}
+static void
+io_accept (int fd, void *unused)
+{
+ struct connection *conn;
+ int nfd;
+
+fprintf(stderr, "accepting sock\n");
+
+ nfd = accept (fd, NULL, NULL);
+ if (nfd < 0) {
+ if (errno != EAGAIN || errno != EINTR)
+ emsg ("couldn't accept socket connection: %s: %s", regex_sock, strerror (errno));
+ return;
+ }
+
+ fcntl (nfd, F_SETFL, O_NONBLOCK | fcntl(nfd, F_GETFL, 0));
+
+ conn = calloc (1, sizeof (*conn));
+ if (!conn) {
+ emsg ("out of memory");
+ close (nfd);
+ return;
+ }
+
+ conn->fd = nfd;
+ TAILQ_INSERT_HEAD (&connections, conn, link);
+
+ conn->sel = fd_select (nfd, io_data, conn, module);
+ if (!conn->sel) {
+ emsg ("couldn't list on socket connection: %s: %s", regex_sock, strerror (errno));
+ close_connection (conn);
+ }
+}
+
+static void
+close_sock ()
+{
+ struct connection *conn;
+
+ if (sock_sel)
+ fd_deselect (sock_sel);
+ sock_sel = NULL;
+
+ if (sock_fd != -1)
+ close (sock_fd);
+ sock_fd = -1;
+
+ while ((conn = TAILQ_FIRST(&connections)) != NULL)
+ close_connection (conn);
+}
+
static int
-open_fifo ()
+open_sock ()
{
struct stat sb;
+ struct sockaddr_un addr;
+ int len;
- close_fifo ();
+ close_sock ();
- ASSERT (regex_fifo && regex_fifo[0]);
+ ASSERT (regex_sock && regex_sock[0]);
- if (stat (regex_fifo, &sb) == 0) {
- /* Complain if it's not a FIFO */
- if (!S_ISFIFO (sb.st_mode)) {
- emsg ("file or directory already exists: %s", regex_fifo);
+ if (stat (regex_sock, &sb) == 0) {
+ /* Complain if it's not a sock */
+ if (!S_ISSOCK (sb.st_mode)) {
+ emsg ("file or directory already exists: %s", regex_sock);
return -1;
}
- } else if (errno == ENOENT) {
- /* Try and create it */
- if (mkfifo (regex_fifo, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
- emsg ("couldn't create fifo: %s: %s", regex_fifo, strerror (errno));
- return -1;
- }
+ /* If it's a socket delete */
+ unlink (regex_sock);
+
+ } else if (errno != ENOENT) {
+ emsg ("couldn't access file: %s: %s", regex_sock, strerror (errno));
+ return -1;
+ }
- } else {
- emsg ("couldn't access fifo: %s: %s", regex_fifo, strerror (errno));
+ /* Create socket and ... */
+ sock_fd = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock_fd < 0) {
+ emsg ("couldn't create socket: %s", strerror (errno));
return -1;
}
- fifo_fd = open (regex_fifo, O_RDONLY | O_NONBLOCK);
- if (fifo_fd < 0) {
- emsg ("couldn't open fifo: %s: %s", regex_fifo, strerror (errno));
+ memset (&addr, 0, sizeof (addr));
+ addr.sun_family = AF_UNIX;
+ strlcpy (addr.sun_path, regex_sock, sizeof (addr.sun_path));
+ len = sizeof(addr) - (sizeof(addr.sun_path) - strlen (addr.sun_path));
+
+ /* ... bind and ... */
+ if (bind (sock_fd, (struct sockaddr*)&addr, len) != 0) {
+ emsg ("couldn't bind to socket: %s: %s", regex_sock, strerror (errno));
return -1;
}
- fifo_sel = fd_select (fifo_fd, receive_log, NULL, module);
- if (!fifo_sel) {
- emsg ("couldn't listen on fifo: %s: %s", regex_fifo, strerror (errno));
+ /* ... listen to it ... */
+ if (listen (sock_fd, 5) < 0) {
+ emsg ("couldn't listen on socket: %s: %s", regex_sock, strerror (errno));
+ return -1;
+ }
+
+ /* ... watch for new connections ... */
+ sock_sel = fd_select (sock_fd, io_accept, NULL, module);
+ if (!sock_sel) {
+ emsg ("couldn't listen on socket: %s: %s", regex_sock, strerror (errno));
return -1;
}
- memset (line_buffer, 0, sizeof (line_buffer));
return 0;
}
@@ -816,10 +944,10 @@ op_regexconfig (struct snmp_context *ctx, struct snmp_value *value,
return r;
- case LEAF_regexFifo:
+ case LEAF_regexSocket:
if (op == SNMP_OP_GET)
- return string_get (value, regex_fifo, -1);
+ return string_get (value, regex_sock, -1);
/* Remainder only at initialization */
if (community != COMM_INITIALIZE)
@@ -827,10 +955,10 @@ op_regexconfig (struct snmp_context *ctx, struct snmp_value *value,
switch (op) {
case SNMP_OP_SET:
- if ((r = string_save (value, ctx, -1, &regex_fifo)) == SNMP_ERR_NOERROR) {
- if (!regex_fifo[0])
+ if ((r = string_save (value, ctx, -1, &regex_sock)) == SNMP_ERR_NOERROR) {
+ if (!regex_sock[0])
r = SNMP_ERR_WRONG_VALUE;
- else if (open_fifo () < 0)
+ else if (open_sock () < 0)
r = SNMP_ERR_GENERR;
}
if (r != SNMP_ERR_NOERROR)
@@ -840,7 +968,7 @@ op_regexconfig (struct snmp_context *ctx, struct snmp_value *value,
string_commit (ctx);
break;
case SNMP_OP_ROLLBACK:
- string_rollback (ctx, &regex_fifo);
+ string_rollback (ctx, &regex_sock);
break;
default:
ASSERT(0);
@@ -975,8 +1103,8 @@ module_init (struct lmodule *mod, int argc, char *argv[])
if (!regex_config)
return ENOMEM;
- regex_fifo = strdup (DEFAULT_FIFO);
- if (!regex_fifo) {
+ regex_sock = strdup (DEFAULT_SOCKET);
+ if (!regex_sock) {
free (regex_config);
return ENOMEM;
}
@@ -989,9 +1117,6 @@ static void
module_start (void)
{
reg_index = or_register (&oid_regex, "The MIB for regex data.", module);
-
- /* Initial reads */
- receive_log (fifo_fd, NULL);
}
/* Called, when the module is to be unloaded after it was successfully loaded */
@@ -1004,10 +1129,10 @@ module_fini (void)
ASSERT (regex_config);
free (regex_config);
- ASSERT (regex_fifo);
- free (regex_fifo);
+ ASSERT (regex_sock);
+ free (regex_sock);
- close_fifo ();
+ close_sock ();
config_free_all ();
return 0;
diff --git a/module/regex-tree.def b/module/regex-tree.def
index aaab8bb..366dc0e 100644
--- a/module/regex-tree.def
+++ b/module/regex-tree.def
@@ -6,7 +6,7 @@
(203 regexData
# Valid only during configuration
(0 regexConfig OCTETSTRING op_regexconfig GET SET)
- (1 regexFifo OCTETSTRING op_regexconfig GET SET)
+ (1 regexSocket OCTETSTRING op_regexconfig GET SET)
(10 regexCount INTEGER op_regex GET)
(11 regexEntry : INTEGER op_regexentry
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..c7cd5a4
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,6 @@
+
+bin_PROGRAMS = sockin
+
+sockin_SOURCES = sockin.c
+sockin_CFLAGS = -I${top_srcdir}/common/ -I${top_srcdir}
+sockin_LDFLAGS =
diff --git a/tools/sockin.c b/tools/sockin.c
new file mode 100644
index 0000000..946b5d3
--- /dev/null
+++ b/tools/sockin.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2006, Nate Nielsen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Nate Nielsen <nielsen@memberwebs.com>
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+
+static void
+usage ()
+{
+ fprintf (stderr, "usage: sockin [-t timeout] socket\n");
+ fprintf (stderr, " sockin [-t timeout] [-d] socket command arg ...\n");
+ exit (2);
+}
+
+static int
+write_all (int fd, void *buf, size_t len)
+{
+ int r;
+ while (len > 0) {
+ r = write(fd, buf, len);
+ if(r >= 0) {
+ buf += r;
+ len -= r;
+ continue;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+connect_sock (const char *path, int timeout)
+{
+ struct sockaddr_un addr;
+ int len, sock;
+
+ /* Connect to the socket */
+ sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ err (1, "couldn't create socket");
+
+ /* Try to connect once a second for timeout seconds */
+ for(;;) {
+ addr.sun_family = AF_UNIX;
+ strlcpy (addr.sun_path, path, sizeof (addr.sun_path));
+ len = sizeof(addr) - (sizeof(addr.sun_path) - strlen (addr.sun_path));\
+
+ if (connect (sock, (struct sockaddr*)&addr, len) < 0) {
+ if (errno == EAGAIN || errno == EINTR) {
+ continue;
+ } else if (timeout--) {
+ sleep (1);
+ continue;
+ } else {
+ err (1, "couldn't connect to socket: %s", path);
+ }
+ }
+
+ break;
+ }
+
+ return sock;
+}
+
+int
+main (int argc, char* argv[])
+{
+ int timeout = 0;
+ int daemonize = 0;
+ int sock, i, r, l;
+ char buf[128];
+ const char *path;
+ char **args;
+ char *t2;
+ char ch;
+
+ /* Parse the arguments nicely */
+ while ((ch = getopt (argc, argv, "t:d")) != -1) {
+ switch(ch) {
+
+ /* Config directory */
+ case 'd':
+ daemonize = 1;
+ break;
+
+ /* Only print commands */
+ case 't':
+ timeout = strtol (optarg, &t2, 10);
+ if (timeout < 0 || *t2)
+ err (2, "invalid timeout: %s", optarg);
+ break;
+
+ /* Usage information */
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage ();
+
+ /* The socket path */
+ path = argv[0];
+ sock = connect_sock (path, timeout);
+
+ argc--;
+ argv++;
+
+ /* Command mode */
+ if (argc) {
+
+ /* Allocate a new command line (no chance to free) */
+ args = (char**)calloc (argc, sizeof (char*));
+ if (!args)
+ err (1, "out of memory");
+ for (i = 0; i < argc; i++)
+ args[i] = argv[i];
+
+ if (daemonize) {
+ if (daemon (1, 0) < 0)
+ err (1, "couldn't daemonize process");
+ }
+
+ /* And duplicate our socket onto stdout */
+ dup2 (1, sock);
+
+ execvp (args[0], args);
+ err (1, "couldn't execute program: %s", args[0]);
+
+ /* Pipe mode */
+ } else {
+
+ /* Handle some signals */
+ signal (SIGPIPE, SIG_IGN);
+
+ for (;;) {
+ l = read (0, buf, sizeof (buf));
+
+ if (l < 0)
+ err (1, "couldn't read data");
+ else if(l == 0)
+ break;
+
+ for (;;) {
+ r = write_all (sock, buf, l);
+
+ if (r < 0) {
+ if (errno != EPIPE)
+ err (1, "couldn't write data to socket: %s", argv[0]);
+
+ /* Try to reconnect when a broken pipe */
+ close (sock);
+ sock = connect_sock (path, timeout);
+ continue;
+ }
+
+ break;
+ }
+ }
+ }
+
+ close (sock);
+ return 0;
+}