Commit b015e6b3 authored by Michael Graff's avatar Michael Graff
Browse files

make changes on HEAD, not on a branch.

parent 5a8bebe0
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: globals.h,v 1.69 2006/12/21 06:02:30 marka Exp $ */
/* $Id: globals.h,v 1.70 2006/12/22 03:07:57 explorer Exp $ */
#ifndef NAMED_GLOBALS_H
#define NAMED_GLOBALS_H 1
......@@ -25,7 +25,6 @@
#include <isc/rwlock.h>
#include <isc/log.h>
#include <isc/net.h>
#include <isc/mib.h>
#include <isccfg/cfg.h>
......@@ -49,7 +48,6 @@ EXTERN isc_taskmgr_t * ns_g_taskmgr INIT(NULL);
EXTERN dns_dispatchmgr_t * ns_g_dispatchmgr INIT(NULL);
EXTERN isc_entropy_t * ns_g_entropy INIT(NULL);
EXTERN isc_entropy_t * ns_g_fallbackentropy INIT(NULL);
EXTERN isc_mib_t * ns_g_mib INIT(NULL);
/*
* XXXRTH We're going to want multiple timer managers eventually. One
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.470 2006/12/21 06:02:29 marka Exp $ */
/* $Id: server.c,v 1.471 2006/12/22 03:07:57 explorer Exp $ */
/*! \file */
......@@ -236,9 +236,6 @@ render_xsl(const char *url, const char *querystring, void *args,
isc_buffer_t *b, isc_httpdfree_t **freecb,
void **freecb_args);
void
tree_walk(xmlTextWriterPtr writer, isc_mib_t *mib, isc_mibnode_t *node);
void
server_generatexml(ns_server_t *server, unsigned int *buflen, xmlChar **buf);
......@@ -5162,58 +5159,6 @@ ns_smf_add_message(isc_buffer_t *text) {
#define NODES 8
#define SPACES 3
void
tree_walk(xmlTextWriterPtr writer, isc_mib_t *mib, isc_mibnode_t *node)
{
char buf[128];
int xmlrc;
while (node != NULL) {
if (node->type == ISC_MIBNODETYPE_NODE)
if (!isc_mibnode_haschildren(node))
goto nextnode;
TRY0(xmlTextWriterStartElement(writer,
ISC_XMLCHAR node->name));
switch (node->type) {
case ISC_MIBNODETYPE_NODE:
tree_walk(writer, mib, isc_mib_firstnode(mib, node));
break;
case ISC_MIBNODETYPE_UINT32:
sprintf(buf, "%u", *(unsigned int *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_INT32:
sprintf(buf, "%d", *(int *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_UINT64:
sprintf(buf, "%qu",
*(unsigned long long *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_INT64:
sprintf(buf, "%qd", *(long long *)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
case ISC_MIBNODETYPE_STRING:
sprintf(buf, "%s", *(char **)(node->data));
TRY0(xmlTextWriterWriteString(writer,
ISC_XMLCHAR buf));
break;
}
TRY0(xmlTextWriterEndElement(writer));
nextnode:
node = isc_mib_nextnode(mib, node);
}
}
void
server_generatexml(ns_server_t *server, unsigned int *buflen, xmlChar **buf)
{
......
......@@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.88 2006/12/21 06:02:30 marka Exp $
# $Id: Makefile.in,v 1.89 2006/12/22 03:07:57 explorer Exp $
srcdir = @srcdir@
VPATH = @srcdir@
......@@ -56,7 +56,7 @@ OBJS = @ISC_EXTRA_OBJS@ \
hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
httpd.@O@ \
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md5.@O@ mem.@O@ mib.@O@ mutexblock.@O@ \
md5.@O@ mem.@O@ mutexblock.@O@ \
netaddr.@O@ netscope.@O@ ondestroy.@O@ \
parseint.@O@ quota.@O@ random.@O@ \
ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
......@@ -71,7 +71,7 @@ SRCS = @ISC_EXTRA_SRCS@ \
heap.c hex.c hmacmd5.c hmacsha.c \
httpd.c \
lex.c lfsr.c lib.c log.c \
md5.c mem.c mib.c mutexblock.c \
md5.c mem.c mutexblock.c \
netaddr.c netscope.c ondestroy.c \
parseint.c quota.c random.c \
ratelimiter.c refcount.c region.c result.c rwlock.c \
......
......@@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.59 2006/12/21 06:02:30 marka Exp $
# $Id: Makefile.in,v 1.60 2006/12/22 03:07:57 explorer Exp $
srcdir = @srcdir@
VPATH = @srcdir@
......@@ -33,7 +33,7 @@ HEADERS = app.h assertions.h base64.h bitstring.h boolean.h buffer.h \
httpd.h \
interfaceiter.h @ISC_IPV6_H@ lang.h lex.h \
lfsr.h lib.h list.h log.h \
magic.h md5.h mem.h mib.h msgcat.h msgs.h \
magic.h md5.h mem.h msgcat.h msgs.h \
mutexblock.h netaddr.h ondestroy.h os.h parseint.h \
print.h quota.h random.h ratelimiter.h \
refcount.h region.h resource.h \
......
/*
* Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: mib.h,v 1.4 2006/12/21 06:02:30 marka Exp $ */
#ifndef ISC_MIB_H
#define ISC_MIB_H
/*! \file mib.h
* \brief Statistics structures.
*
* \li MP:
* The statistics structures defined in this file handle all locking
* provided the API is used properly.
*
* This module defines a MIB database.
*
* Two entities are defined: providers and consumers. Providers will
* create and attach mib elements to the root or to other nodes, and update
* the MIB elements themselves. Consumers will read this data.
*
* Note that consumers cannot currently update the MIB, just read it. We
* may want to add this later.
*
* General assumptions about the use of the mib system, and design
* requirements:
*
* (1) Mib must be fast to update, with as little locking as feasable.
* On simple integers, this should require no locks if the system
* supports atomic increments and reads of integers.
*
* (2) Mib must be fast to read, also with as little locking as possible.
* The mib tree has a read/write lock to protect the structure of
* the entire mib tree.
*
* (3) The mib tree itself is expected to be updated infrequently, and
* so a simple read/write lock is used to protect the struture.
*
* (4) Sometimes complicated data will require special handling to protect
* during read or updates. When this is necessary, a pointer to a lock
* structure can be associated with each mib variable. This lock
* can be shared (for space savings).
*
* Constraints of use:
*
* (1) Each mib structure has an implied owner, which may be a module, an
* "object" like a zone, or other distinct object. It is required the
* owner of the mib node will be the one to create, modify the structure
* of, and delete it as needed.
*
* (2) The mib structure must be fully configured before inserting it into
* the tree. However, mib objects can be added and removed dynamically
* as required.
*
* (3) Mib have names. These names cannot contain periods, as this is
* used as the delimiter between names.
*
* (4) Walking a list of nodes must be done in the forward order only, never
* in the reverse direction. This is to avoid deadlocks, and to optimize
* locking. Locking will only be performed as needed while walking the
* mibnode list, and if the lock needed does not change it will not
* be unlocked until isc_mib_iterunlock() is called to explicitly
* unlock, or isc_mib_iterdestroy() is called to implicitly unlock it.
*
* (5) When walking the tree, or updating statistics, it is required that
* the mibnode locks be held for as little a time as possible. Any
* data should be copied quickly or the lock should be explicitly
* released.
*
* (6) When updating mib, the mibnode lock should be held as little as
* possible.
*
* (7) Even with locks there is no guarantee they will always be used, so
* users of this cannot assume reading two or more variables which
* share the same statistics lock will result in consistent data. For
* example, if there are three data items, "a", "b", and "total", where
* total = a + b, it is possible "a" will be updated using atomic
* operations, and then "total" will be incremented using the same
* operations. Atomic operations on integers will not always use the
* node's lock, so it is possible that total will not always be the sum
* of "a" and "b".
*
* (8) Consumers are read-only -- no modification is allowed. Search
* functions will return data that must not be modified. Removal of
* a node implies that the node's exact pointer is known. That is,
* no search is needed. Searching then removing a node is considered
* a misuse of this API.
*/
#include <isc/lang.h>
#include <isc/list.h>
#include <isc/mutex.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/types.h>
#define ISC_MIB_MAXNAME 12 /* max mib length */
#define ISC_MIB_NAMELEN 32 /* longest ASCII name length per node */
#define ISC_MIB_DEFSIZE 8 /* default object set size */
/*
* Node types.
*/
#define ISC_MIBNODETYPE_INVALID 0 /* Invalid node */
#define ISC_MIBNODETYPE_NODE 1 /* node is a node */
#define ISC_MIBNODETYPE_UINT32 2 /* node is an unsigned 32-bit integer */
#define ISC_MIBNODETYPE_INT32 3 /* node is an signed 32-bit integer */
#define ISC_MIBNODETYPE_UINT64 4 /* node is an unsigned 64-bit integer */
#define ISC_MIBNODETYPE_INT64 5 /* node is an signed 64-bit integer */
#define ISC_MIBNODETYPE_STRING 6 /* node is a string */
/*
* Node flags. These define flags used on isc_mibnode_t.
*/
#define ISC_MIBNODEFLAG_PERMANENT 0x00000001 /* cannot free */
typedef struct isc_mibnode isc_mibnode_t;
typedef struct isc_mib isc_mib_t;
/*
* This is a description of the data element we are tracking. We call this
* a "node."
*/
struct isc_mibnode {
isc_uint32_t type;
isc_uint32_t flags;
char *name;
isc_mibnode_t *parent;
isc_mutex_t *lock;
void *data; /* used if we are a data node */
ISC_LIST(isc_mibnode_t) nodes; /* used if we are a list node */
ISC_LINK(isc_mibnode_t) link;
};
/*
* Initialize a tree's root node.
*/
isc_result_t isc_mib_create(isc_mem_t *mem, isc_mib_t **rootp);
/*
* Destroy a MIB.
*/
void isc_mib_destroy(isc_mib_t **rootp);
/*
* FUNCTIONS BELOW THIS POINT SHOULD BE CALLED ONLY FROM PROVIDERS.
*/
/*
* Create and initialize a new node. This will allocate a node structure,
* and call isc_mibnode_init() to initialize it.
*
* This function allocates memory, so a corresponding call to
* isc_mibnode_destroy() must be made to free the memory allocated by
* this function and by isc_mibnode_init().
*/
isc_result_t isc_mibnode_create(isc_mib_t *mib, isc_uint32_t type,
const char *name,
isc_uint32_t flags, isc_mutex_t *lock,
void *item, unsigned int itemlen,
isc_mibnode_t **nodep);
/*
* Initialize a static or pre-allocated node.
* This will set it up but NOT link it into the tree.
*
* This function allocates memory from the mib's memory context, so a
* call to isc_mibnode_invalidate() must be called to destroy it.
*/
isc_result_t isc_mibnode_init(isc_mib_t *mib, isc_mibnode_t *node,
isc_uint32_t type, const char *name,
isc_mutex_t *lock, isc_uint32_t flags,
void *item, unsigned int itemlen);
void isc_mibnode_invalidate(isc_mib_t *mib, isc_mibnode_t *node);
void isc_mib_add(isc_mib_t *root, isc_mibnode_t *parent, isc_mibnode_t *node);
void isc_mib_remove(isc_mib_t *root, isc_mibnode_t *node);
void isc_mibnode_destroy(isc_mib_t *mib, isc_mibnode_t **nodep);
isc_boolean_t isc_mibnode_haschildren(isc_mibnode_t *node);
/*
* Walk a mib. This performs a depth-first traversal of the mib tree.
* Locking is automatic. After walking is completed, isc_mib_release()
* must be called.
*
* Also, have a way to find a node's parent.
*/
isc_mibnode_t *isc_mib_firstnode(isc_mib_t *mib, isc_mibnode_t *parent);
isc_mibnode_t *isc_mib_nextnode(isc_mib_t *mib, isc_mibnode_t *previous);
isc_mibnode_t *isc_mib_parent(isc_mib_t *mib, isc_mibnode_t *node);
/*
* Release any locks held on the mib and node.
* This is the last step in searching and tree-walking.
*
* If 'node' is NULL, only the tree is unlocked.
*/
void isc_mib_unlock(isc_mib_t *mib, isc_mibnode_t *node);
void isc_mib_lock(isc_mib_t *mib, isc_mibnode_t *node);
void
isc_mibnode_getdata(isc_mibnode_t *node,
isc_mibnode_t *previous,
isc_boolean_t lock,
void *item, unsigned int itemlen);
#endif /* ISC_MIB_H */
/*
* Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: mib.c,v 1.4 2006/12/21 06:02:30 marka Exp $ */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <isc/atomic.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/mib.h>
#include <isc/util.h>
#include <isc/list.h>
/*
* The root of a statistics tree.
*
* We use a isc_refcount_t for reference counting, which is a self-locked
* type. It is very efficient and may use atomic operations rather than
* locks.
*/
struct isc_mib {
isc_mem_t *mem;
isc_rwlock_t rwlock;
ISC_LIST(isc_mibnode_t) nodes;
isc_refcount_t refs;
};
isc_result_t
isc_mib_create(isc_mem_t *mem, isc_mib_t **rootp)
{
isc_result_t result;
isc_mib_t *root;
REQUIRE(rootp != NULL && *rootp == NULL);
root = isc_mem_get(mem, sizeof *root);
if (root == NULL)
return (ISC_R_NOMEMORY);
result = isc_rwlock_init(&root->rwlock, 0, 0);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mem, root, sizeof *root);
return (result);
}
ISC_LIST_INIT(root->nodes);
root->mem = NULL;
isc_mem_attach(mem, &root->mem);
isc_refcount_init(&root->refs, 1);
*rootp = root;
return (ISC_R_SUCCESS);
}
isc_result_t
isc_mibnode_create(isc_mib_t *mib, isc_uint32_t type,
const char *name, isc_uint32_t flags,
isc_mutex_t *lock, void *item, unsigned int itemlen,
isc_mibnode_t **nodep)
{
isc_result_t result;
isc_mibnode_t *node;
REQUIRE(nodep != NULL && *nodep == NULL);
REQUIRE((flags & ISC_MIBNODEFLAG_PERMANENT) == 0);
node = isc_mem_get(mib->mem, sizeof *node);
if (node == NULL)
return (ISC_R_NOMEMORY);
*nodep = node;
result = isc_mibnode_init(mib, node, type, name, lock, flags,
item, itemlen);
return (result);
}
void
isc_mibnode_destroy(isc_mib_t *mib, isc_mibnode_t **nodep)
{
isc_mibnode_t *node;
REQUIRE(nodep != NULL && *nodep != NULL);
node = *nodep;
REQUIRE((node->flags & ISC_MIBNODEFLAG_PERMANENT) == 0);
isc_mibnode_invalidate(mib, node);
*nodep = NULL;
isc_mem_put(mib->mem, node, sizeof *node);
}
/*
* XXXMLG Should break this out into two functions, one which is used
* internally for most of the setting, and another which simply makes
* certain that the ISC_MIBNODEFLAG_PERMANENT is set when the client calls
* _init() and _invalidate() directly.
*/
void
isc_mibnode_invalidate(isc_mib_t *mib, isc_mibnode_t *node)
{
REQUIRE(node != NULL);
REQUIRE(!ISC_LINK_LINKED(node, link));
switch (node->type) {
case ISC_MIBNODETYPE_NODE:
REQUIRE(ISC_LIST_EMPTY(node->nodes));
break;
}
isc_mem_free(mib->mem, node->name);
node = ISC_MIBNODETYPE_INVALID;
}
/*
* Initialize a statically allocated mibnode. The caller will need to call
* isc_mibnode_invalidate() after it is no longer in use.
*/
isc_result_t
isc_mibnode_init(isc_mib_t *mib, isc_mibnode_t *node, isc_uint32_t type,
const char *name, isc_mutex_t *lock, isc_uint32_t flags,
void *item, unsigned int itemlen)
{
REQUIRE(mib != NULL);
REQUIRE(node != NULL);
REQUIRE(name != NULL);
ISC_LINK_INIT(node, link);
node->type = type;
node->name = isc_mem_strdup(mib->mem, name);
if (node->name == NULL)
return (ISC_R_NOMEMORY);
node->parent = NULL;
node->lock = NULL;
node->flags = flags;
node->lock = lock;
ISC_LIST_INIT(node->nodes);
switch (type) {
case ISC_MIBNODETYPE_NODE:
break;
case ISC_MIBNODETYPE_STRING:
REQUIRE(itemlen >= sizeof(char *));
node->data = item;
break;
case ISC_MIBNODETYPE_UINT32:
case ISC_MIBNODETYPE_INT32:
REQUIRE(itemlen >= sizeof(isc_uint32_t));
node->data = item;
break;
case ISC_MIBNODETYPE_UINT64:
case ISC_MIBNODETYPE_INT64:
REQUIRE(itemlen >= sizeof(isc_uint64_t));
node->data = item;
break;
default:
isc_error_runtimecheck(__FILE__, __LINE__,
"Invalid type");
}
return (ISC_R_SUCCESS);
}
void
isc_mib_destroy(isc_mib_t **rootp)
{
isc_mib_t *root;
isc_mem_t *mem;
unsigned int refs;
REQUIRE(rootp != NULL && *rootp != NULL);
root = *rootp;
rootp = NULL;
isc_refcount_decrement(&root->refs, &refs);
INSIST(refs == 0);
isc_refcount_destroy(&root->refs);
REQUIRE(ISC_LIST_EMPTY(root->nodes));
/* record and then forget the root's memory context */
mem = root->mem;
root->mem = NULL;
isc_rwlock_destroy(&root->rwlock);
isc_mem_putanddetach(&mem, root, sizeof *root);
}
void
isc_mib_add(isc_mib_t *root, isc_mibnode_t *parent, isc_mibnode_t *node)
{
REQUIRE(root != NULL);
REQUIRE(node != NULL);
RWLOCK(&root->rwlock, isc_rwlocktype_write);
isc_refcount_increment(&root->refs, NULL);
if (parent == NULL) {
ISC_LIST_APPEND(root->nodes, node, link);
node->parent = NULL;
} else {
REQUIRE(parent->type == ISC_MIBNODETYPE_NODE);
ISC_LIST_APPEND(parent->nodes, node, link);
node->parent = parent;
}
RWUNLOCK(&root->rwlock, isc_rwlocktype_write);
}
void
isc_mib_remove(isc_mib_t *root, isc_mibnode_t *node)
{
REQUIRE(root != NULL);
REQUIRE(node != NULL);
RWLOCK(&root->rwlock, isc_rwlocktype_write);
isc_refcount_decrement(&root->refs, NULL);
if (node->parent == NULL)
ISC_LIST_UNLINK(root->nodes, node, link);
else
ISC_LIST_UNLINK(node->parent->nodes, node, link);
node->parent = NULL;
RWUNLOCK(&root->rwlock, isc_rwlocktype_write);
}
isc_boolean_t
isc_mibnode_haschildren(isc_mibnode_t *node)
{
REQUIRE(node != NULL);
REQUIRE(node->type == ISC_MIBNODETYPE_NODE);
if (ISC_LIST_HEAD(node->nodes) == NULL)
return (ISC_FALSE);
return (ISC_TRUE);
}
isc_mibnode_t *
isc_mib_firstnode(isc_mib_t *mib, isc_mibnode_t *parent)
{