diff options
| author | Stef Walter <stef@memberwebs.com> | 2009-10-24 14:10:41 +0000 | 
|---|---|---|
| committer | Stef Walter <stef@memberwebs.com> | 2009-10-24 14:10:41 +0000 | 
| commit | 0af1b01b5ca61422c779b40a9c99cd0b29b40049 (patch) | |
| tree | 26374207ac7df32b16332090328cd1a99ddeff4f /common | |
| parent | 54c751ffc4f79dcd916b4dffe690f59615c7146d (diff) | |
Support for multiple local sockets (ie: INET + INET6)
 * Allows us to make ipv6 queries.
Diffstat (limited to 'common')
| -rw-r--r-- | common/compat.c | 12 | ||||
| -rw-r--r-- | common/compat.h | 4 | ||||
| -rw-r--r-- | common/snmp-engine.c | 109 | ||||
| -rw-r--r-- | common/snmp-engine.h | 2 | 
4 files changed, 94 insertions, 33 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, | 
