summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2009-10-24 14:10:41 +0000
committerStef Walter <stef@memberwebs.com>2009-10-24 14:10:41 +0000
commit0af1b01b5ca61422c779b40a9c99cd0b29b40049 (patch)
tree26374207ac7df32b16332090328cd1a99ddeff4f
parent54c751ffc4f79dcd916b4dffe690f59615c7146d (diff)
Support for multiple local sockets (ie: INET + INET6)
* Allows us to make ipv6 queries.
-rw-r--r--common/compat.c12
-rw-r--r--common/compat.h4
-rw-r--r--common/snmp-engine.c109
-rw-r--r--common/snmp-engine.h2
-rw-r--r--daemon/rrdbotd.c24
-rw-r--r--tools/rrdbot-get.c23
6 files changed, 136 insertions, 38 deletions
diff --git a/common/compat.c b/common/compat.c
index eda00d0..1d94f1e 100644
--- a/common/compat.c
+++ b/common/compat.c
@@ -235,6 +235,18 @@ atexitv(voidfunc func, void* data)
#endif /* HAVE_ATEXITV */
+#ifndef HAVE_XREALLOC
+
+void*
+xrealloc(void *p, size_t size)
+{
+ register void* value = realloc(p, size);
+ if(value == NULL && size)
+ errx(1, "out of memory");
+ return value;
+}
+
+#endif /* HAVE_XREALLOC */
#ifndef HAVE_XCALLOC
diff --git a/common/compat.h b/common/compat.h
index 8eda20f..e19d1b1 100644
--- a/common/compat.h
+++ b/common/compat.h
@@ -73,6 +73,10 @@ int strtob(const char* str);
void atexitv(void (*func)(void*), void* data);
#endif
+#ifndef HAVE_XREALLOC
+void* xrealloc(void *p, size_t size);
+#endif
+
#ifndef HAVE_XCALLOC
void* xcalloc(size_t size);
#endif
diff --git a/common/snmp-engine.c b/common/snmp-engine.c
index 945418e..baf0f0d 100644
--- a/common/snmp-engine.c
+++ b/common/snmp-engine.c
@@ -378,14 +378,22 @@ struct request
struct snmp_pdu pdu;
};
+struct socket
+{
+ int fd; /* The SNMP socket we're communicating on */
+ struct sockaddr_storage addr; /* Local address of this socket */
+ socklen_t addr_len; /* Length of addr */
+ struct socket *next; /* Linked list of socket structures */
+};
+
/* The number of SNMP packet retries */
static int snmp_retries = 3;
/* The last request id */
static uint snmp_request_id = 1;
-/* The SNMP socket we're communicating on */
-static int snmp_socket = -1;
+/* The sockets we communicate on */
+static struct socket *snmp_sockets = NULL;
/* Since we only deal with one packet at a time, global buffer */
static unsigned char snmp_buffer[0x1000];
@@ -413,10 +421,11 @@ request_release (struct request *req)
static void
request_send (struct request* req, mstime when)
{
+ struct socket* sock;
struct asn_buf b;
ssize_t ret;
- ASSERT (snmp_socket != -1);
+ assert (snmp_sockets != NULL);
/* Update our bookkeeping */
req->num_sent++;
@@ -433,13 +442,25 @@ request_send (struct request* req, mstime when)
return;
}
+ /* Select a good socket to use, based on address family */
+ for (sock = snmp_sockets; sock; sock = sock->next) {
+ if (sock->addr.ss_family == req->host->address.ss_family)
+ break;
+ }
+
+ if (sock == NULL) {
+ log_warnx ("couldn't send snmp packet to: %s: %s",
+ req->host->hostname, "no local address of relevant protocol family");
+ return;
+ }
+
b.asn_ptr = snmp_buffer;
b.asn_len = sizeof (snmp_buffer);
if (snmp_pdu_encode (&req->pdu, &b)) {
log_error("couldn't encode snmp buffer");
} else {
- ret = sendto (snmp_socket, snmp_buffer, b.asn_ptr - snmp_buffer, 0,
+ ret = sendto (sock->fd, snmp_buffer, b.asn_ptr - snmp_buffer, 0,
(struct sockaddr*)&req->host->address, req->host->address_len);
if (ret == -1)
log_error ("couldn't send snmp packet to: %s", req->host->hostname);
@@ -605,11 +626,9 @@ request_response (int fd, int type, void* arg)
int len, ret;
int ip, id;
- ASSERT (snmp_socket == fd);
-
/* Read in the packet */
from_len = sizeof (from);
- len = recvfrom (snmp_socket, snmp_buffer, sizeof (snmp_buffer), 0,
+ len = recvfrom (fd, snmp_buffer, sizeof (snmp_buffer), 0,
(struct sockaddr*)&from, &from_len);
if(len < 0) {
if(errno != EAGAIN && errno != EWOULDBLOCK)
@@ -985,10 +1004,14 @@ snmp_engine_sync (const char* host, const char *port, const char* community,
*/
void
-snmp_engine_init (const char *bindaddr, int retries)
+snmp_engine_init (const char **bindaddrs, int retries)
{
struct addrinfo hints, *ai;
- int r;
+ struct socket *sock;
+ const char **p, *bindaddr;
+ int fd, r;
+
+ assert (bindaddrs);
snmp_retries = retries;
@@ -1000,29 +1023,44 @@ snmp_engine_init (const char *bindaddr, int retries)
if (!snmp_preparing)
err (1, "out of memory");
- if (!bindaddr)
- bindaddr = "0.0.0.0";
- memset (&hints, 0, sizeof (hints));
- hints.ai_flags = AI_PASSIVE;
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = AI_NUMERICSERV;
- r = getaddrinfo (bindaddr, "0", &hints, &ai);
- if (r != 0)
- errx (1, "couldn't resolve bind address: %s: %s", bindaddr, gai_strerror (r));
+ assert (snmp_sockets == NULL);
+
+ for (p = bindaddrs; p && *p; ++p) {
+ bindaddr = *p;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_NUMERICSERV;
+ r = getaddrinfo (bindaddr, "0", &hints, &ai);
+ if (r != 0)
+ errx (1, "couldn't resolve bind address: %s: %s", bindaddr, gai_strerror (r));
- ASSERT (snmp_socket == -1);
- snmp_socket = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (snmp_socket < 0)
- err (1, "couldn't open snmp socket");
+ fd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (fd < 0)
+ err (1, "couldn't open snmp socket");
- if (bind (snmp_socket, ai->ai_addr, ai->ai_addrlen) < 0)
- err (1, "couldn't listen on port");
+ if (bind (fd, ai->ai_addr, ai->ai_addrlen) < 0)
+ err (1, "couldn't listen on port");
- freeaddrinfo (ai);
+ if (server_watch (fd, SERVER_READ, request_response, NULL) == -1)
+ err (1, "couldn't listen on socket");
- if (server_watch (snmp_socket, SERVER_READ, request_response, NULL) == -1)
- err (1, "couldn't listen on socket");
+ /* Stash this socket info */
+ sock = xcalloc (sizeof (struct socket));
+ sock->fd = fd;
+
+ if (ai->ai_addrlen > sizeof (sock->addr))
+ errx (1, "resolve address is too big");
+ memcpy (&sock->addr, ai->ai_addr, ai->ai_addrlen);
+
+ /* Push onto the linked list */
+ sock->next = snmp_sockets;
+ snmp_sockets = sock;
+
+ freeaddrinfo (ai);
+ }
/* We fire off the resend timer every 1/5 second */
if (server_timer (200, request_resend_timer, NULL) == -1)
@@ -1034,10 +1072,17 @@ snmp_engine_init (const char *bindaddr, int retries)
void
snmp_engine_stop (void)
{
- if (snmp_socket != -1) {
- server_unwatch (snmp_socket);
- close (snmp_socket);
- snmp_socket = -1;
+ struct socket *sock;
+
+ while (snmp_sockets != NULL) {
+ /* Pop off the list */
+ sock = snmp_sockets;
+ snmp_sockets = sock->next;
+
+ /* And destroy */
+ server_unwatch (sock->fd);
+ close (sock->fd);
+ free (sock);
}
host_cleanup ();
diff --git a/common/snmp-engine.h b/common/snmp-engine.h
index 59c733d..d3d353c 100644
--- a/common/snmp-engine.h
+++ b/common/snmp-engine.h
@@ -6,7 +6,7 @@
typedef void (*snmp_response) (int request, int code, struct snmp_value *value, void *data);
-void snmp_engine_init (const char *bind_address, int retries);
+void snmp_engine_init (const char **bind_addresses, int retries);
int snmp_engine_request (const char* host, const char *port, const char* community,
int version, uint64_t interval, uint64_t timeout, int reqtype,
diff --git a/daemon/rrdbotd.c b/daemon/rrdbotd.c
index 573eb5f..f2ecd52 100644
--- a/daemon/rrdbotd.c
+++ b/daemon/rrdbotd.c
@@ -204,8 +204,9 @@ removepid(const char* pidfile)
int
main(int argc, char* argv[])
{
+ const char** local = NULL;
+ int n_local = 0;
const char* pidfile = NULL;
- const char *bind_address = NULL;
int daemonize = 1;
char ch;
char* t;
@@ -231,7 +232,9 @@ main(int argc, char* argv[])
/* Bind address */
case 'b':
- bind_address = optarg;
+ local = xrealloc (local, sizeof (char*) * (n_local + 2));
+ local[n_local] = optarg;
+ local[++n_local] = NULL;
break;
/* Config directory */
@@ -301,6 +304,17 @@ main(int argc, char* argv[])
if(argc != 0)
usage();
+ /* No bind addresses specified, use defaults... */
+ if (local == NULL) {
+ local = xrealloc (local, sizeof (char*) * 3);
+ local[0] = "0.0.0.0";
+ local[1] = NULL;
+#ifdef HAVE_INET6
+ local[1] = "::";
+ local[2] = NULL;
+#endif
+ }
+
/* The mainloop server */
server_init();
@@ -311,9 +325,13 @@ main(int argc, char* argv[])
mib_uninit();
/* Rev up the main engine */
- snmp_engine_init(bind_address, 3);
+ snmp_engine_init (local, 3);
rb_poll_engine_init();
+ free (local);
+ n_local = 0;
+ local = NULL;
+
if(daemonize)
{
/* Fork a daemon nicely */
diff --git a/tools/rrdbot-get.c b/tools/rrdbot-get.c
index 46219d9..27c8b75 100644
--- a/tools/rrdbot-get.c
+++ b/tools/rrdbot-get.c
@@ -426,6 +426,8 @@ int
main (int argc, char* argv[])
{
char *bind_address = NULL;
+ const char **local = NULL;
+ int n_local = 0;
char ch;
char* t;
@@ -460,7 +462,9 @@ main (int argc, char* argv[])
/* local source address */
case 's':
- bind_address = optarg;
+ local = xrealloc (local, sizeof (char*) * (n_local + 2));
+ local[n_local] = optarg;
+ local[++n_local] = NULL;
break;
/* The timeout */
@@ -495,8 +499,23 @@ main (int argc, char* argv[])
if(argc != 1)
usage ();
+ /* No bind addresses specified, use defaults... */
+ if (local == NULL) {
+ local = xrealloc (local, sizeof (char*) * 3);
+ local[0] = "0.0.0.0";
+ local[1] = NULL;
+#ifdef HAVE_INET6
+ local[1] = "::";
+ local[2] = NULL;
+#endif
+ }
+
server_init ();
- snmp_engine_init (bind_address, MAX_RETRIES);
+ snmp_engine_init (local, MAX_RETRIES);
+
+ free (local);
+ n_local = 0;
+ local = NULL;
parse_argument (argv[0]);