2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 10:10:06 +00:00

[master] add JSON statistics channel

3524.	[func]		Added an alternate statistics channel in JSON format,
			when the server is built with the json-c library:
			http://[address]:[port]/json.  [RT #32630]
This commit is contained in:
Evan Hunt 2013-03-13 14:24:50 -07:00
parent 8a64253066
commit feb067b25a
18 changed files with 1432 additions and 23 deletions

View File

@ -1,3 +1,7 @@
3524. [func] Added an alternate statistics channel in JSON format,
when the server is built with the json-c library:
http://[address]:[port]/json. [RT #32630]
3523. [contrib] Ported filesystem and ldap DLZ drivers to
dynamically-loadable modules, and added the
"wildcard" module based on a contribution from

6
README
View File

@ -230,6 +230,12 @@ Building
a nonstandard prefix, you can tell configure where to
look for it using "--with-openssl=/prefix".
To support the HTTP statistics channel, the server must
be linked with at least one of the following: libxml2
(http://xmlsoft.org) or json-c (https://github.com/json-c).
If these are installed at a nonstandard prefix, use
"--with-libxml2=/prefix" or "--with-libjson=/prefix".
On some platforms it is necessary to explictly request large
file support to handle files bigger than 2GB. This can be
done by "--enable-largefile" on the configure command line.

View File

@ -43,6 +43,10 @@
#include <named/server.h>
#include <named/statschannel.h>
#ifdef HAVE_JSON_H
#include <json/json.h>
#endif
#include "bind9.xsl.h"
struct ns_statschannel {
@ -538,8 +542,11 @@ dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
xmlTextWriterPtr writer;
int xmlrc;
#endif
#ifdef HAVE_JSON
json_object *job, *cat, *counter;
#endif
#ifndef HAVE_LIBXML2
#if !defined(HAVE_LIBXML2) && !defined(HAVE_JSON)
UNUSED(category);
#endif
@ -551,6 +558,18 @@ dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
memset(values, 0, sizeof(values[0]) * ncounters);
isc_stats_dump(stats, generalstat_dump, &dumparg, options);
#ifdef HAVE_JSON
cat = job = (json_object *) arg;
if (ncounters > 0 && type == isc_statsformat_json) {
if (category != NULL) {
cat = json_object_new_object();
if (cat == NULL)
return (ISC_R_NOMEMORY);
json_object_object_add(job, category, cat);
}
}
#endif
for (i = 0; i < ncounters; i++) {
index = indices[i];
value = values[index];
@ -566,7 +585,7 @@ dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
break;
case isc_statsformat_xml:
#ifdef HAVE_LIBXML2
writer = arg;
writer = (xmlTextWriterPtr) arg;
if (category != NULL) {
/* <NameOfCategory> */
@ -613,6 +632,14 @@ dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
#endif
break;
case isc_statsformat_json:
#ifdef HAVE_JSON
counter = json_object_new_int64(value);
if (counter == NULL)
return (ISC_R_NOMEMORY);
json_object_object_add(cat, desc[index], counter);
break;
#endif
}
}
return (ISC_R_SUCCESS);
@ -634,6 +661,9 @@ rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
xmlTextWriterPtr writer;
int xmlrc;
#endif
#ifdef HAVE_JSON
json_object *zoneobj, *obj;
#endif
if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE)
== 0) {
@ -662,6 +692,15 @@ rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
val));
TRY0(xmlTextWriterEndElement(writer)); /* type */
#endif
break;
case isc_statsformat_json:
#ifdef HAVE_JSON
zoneobj = (json_object *) dumparg->arg;
obj = json_object_new_int64(val);
if (obj == NULL)
return;
json_object_object_add(zoneobj, typestr, obj);
#endif
break;
}
@ -687,6 +726,10 @@ rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
xmlTextWriterPtr writer;
int xmlrc;
#endif
#ifdef HAVE_JSON
json_object *zoneobj, *obj;
char buf[1024];
#endif
if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN)
!= 0) {
@ -732,6 +775,17 @@ rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
TRY0(xmlTextWriterEndElement(writer)); /* counter */
TRY0(xmlTextWriterEndElement(writer)); /* rrset */
#endif
break;
case isc_statsformat_json:
#ifdef HAVE_JSON
zoneobj = (json_object *) dumparg->arg;
sprintf(buf, "%s%s%s", stale ? "#" : "",
nxrrset ? "!" : "", typestr);
obj = json_object_new_int64(val);
if (obj == NULL)
return;
json_object_object_add(zoneobj, buf, obj);
#endif
break;
}
@ -755,6 +809,9 @@ opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
xmlTextWriterPtr writer;
int xmlrc;
#endif
#ifdef HAVE_JSON
json_object *zoneobj, *obj;
#endif
isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1);
dns_opcode_totext(code, &b);
@ -775,6 +832,15 @@ opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
"%" ISC_PRINT_QUADFORMAT "u",
val));
TRY0(xmlTextWriterEndElement(writer)); /* counter */
#endif
break;
case isc_statsformat_json:
#ifdef HAVE_JSON
zoneobj = (json_object *) dumparg->arg;
obj = json_object_new_int64(val);
if (obj == NULL)
return;
json_object_object_add(zoneobj, codebuf, obj);
#endif
break;
}
@ -793,7 +859,6 @@ opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
/* XXXMLG below here sucks. (not so much) */
static isc_result_t
zone_xmlrender(dns_zone_t *zone, void *arg) {
isc_result_t result;
@ -1174,6 +1239,609 @@ render_index(const char *url, const char *querystring, void *arg,
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_JSON
/*
* Which statistics to include when rendering to JSON
*/
#define STATS_JSON_SERVER 0x01
#define STATS_JSON_ZONES 0x02
#define STATS_JSON_TASKS 0x04
#define STATS_JSON_NET 0x08
#define STATS_JSON_MEM 0x10
#define STATS_JSON_ALL 0xff
#define CHECKMEM(m) do { \
if (m == NULL) { \
result = ISC_R_NOMEMORY;\
goto error;\
} \
} while(0)
static void
wrap_jsonfree(isc_buffer_t *buffer, void *arg) {
json_object_put(isc_buffer_base(buffer));
if (arg != NULL)
json_object_put((json_object *) arg);
}
static json_object *
addzone(char *name, char *class, isc_uint32_t serial) {
json_object *node = json_object_new_object();
if (node == NULL)
return (NULL);
json_object_object_add(node, "name", json_object_new_string(name));
json_object_object_add(node, "class", json_object_new_string(class));
json_object_object_add(node, "serial", json_object_new_int64(serial));
return (node);
}
static isc_result_t
zone_jsonrender(dns_zone_t *zone, void *arg) {
isc_result_t result = ISC_R_SUCCESS;
char buf[1024 + 32]; /* sufficiently large for zone name and class */
char class[1024 + 32]; /* sufficiently large for zone name and class */
char *zone_name_only = NULL;
char *class_only = NULL;
dns_rdataclass_t rdclass;
isc_uint32_t serial;
isc_uint64_t nsstat_values[dns_nsstatscounter_max];
isc_stats_t *zonestats;
dns_stats_t *rcvquerystats;
json_object *zonearray = (json_object *) arg;
json_object *zoneobj = NULL;
dns_zonestat_level_t statlevel;
statlevel = dns_zone_getstatlevel(zone);
if (statlevel == dns_zonestat_none)
return (ISC_R_SUCCESS);
dns_zone_name(zone, buf, sizeof(buf));
zone_name_only = strtok(buf, "/");
if(zone_name_only == NULL)
zone_name_only = buf;
rdclass = dns_zone_getclass(zone);
dns_rdataclass_format(rdclass, class, sizeof(class));
class_only = class;
if (dns_zone_getserial2(zone, &serial) != ISC_R_SUCCESS)
serial = -1;
zoneobj = addzone(zone_name_only, class_only, serial);
if (zoneobj == NULL)
return (ISC_R_NOMEMORY);
zonestats = dns_zone_getrequeststats(zone);
rcvquerystats = dns_zone_getrcvquerystats(zone);
if (statlevel == dns_zonestat_full && zonestats != NULL) {
json_object *counters = json_object_new_object();
if (counters == NULL) {
result = ISC_R_NOMEMORY;
goto error;
}
result = dump_counters(zonestats, isc_statsformat_json,
counters, NULL, nsstats_xmldesc,
dns_nsstatscounter_max, nsstats_index,
nsstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(zoneobj, "rcodes", counters);
else
json_object_put(counters);
}
if (statlevel == dns_zonestat_full && rcvquerystats != NULL) {
stats_dumparg_t dumparg;
json_object *counters = json_object_new_object();
CHECKMEM(counters);
dumparg.type = isc_statsformat_json;
dumparg.arg = counters;
dumparg.result = ISC_R_SUCCESS;
dns_rdatatypestats_dump(rcvquerystats, rdtypestat_dump,
&dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(zoneobj, "qtypes", counters);
else
json_object_put(counters);
}
json_object_array_add(zonearray, zoneobj);
zoneobj = NULL;
result = ISC_R_SUCCESS;
error:
if (zoneobj != NULL)
json_object_put(zoneobj);
return (result);
}
static isc_result_t
generatejson(ns_server_t *server, size_t *msglen,
const char **msg, json_object **rootp, isc_uint8_t flags)
{
dns_view_t *view;
isc_result_t result = ISC_R_SUCCESS;
json_object *bindstats, *viewlist, *counters, *obj;
isc_uint64_t nsstat_values[dns_nsstatscounter_max];
isc_uint64_t resstat_values[dns_resstatscounter_max];
isc_uint64_t adbstat_values[dns_adbstats_max];
isc_uint64_t zonestat_values[dns_zonestatscounter_max];
isc_uint64_t sockstat_values[isc_sockstatscounter_max];
stats_dumparg_t dumparg;
char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
isc_time_t now;
REQUIRE(msglen != NULL);
REQUIRE(msg != NULL && *msg == NULL);
REQUIRE(rootp == NULL || *rootp == NULL);
bindstats = json_object_new_object();
if (bindstats == NULL)
return (ISC_R_NOMEMORY);
/*
* These statistics are included no matter which URL we use.
*/
obj = json_object_new_string("1.0");
CHECKMEM(obj);
json_object_object_add(bindstats, "json-stats-version", obj);
isc_time_now(&now);
isc_time_formatISO8601(&ns_g_boottime,
boottime, sizeof(boottime));
isc_time_formatISO8601(&ns_g_configtime,
configtime, sizeof configtime);
isc_time_formatISO8601(&now, nowstr, sizeof(nowstr));
obj = json_object_new_string(boottime);
CHECKMEM(obj);
json_object_object_add(bindstats, "boot-time", obj);
obj = json_object_new_string(configtime);
CHECKMEM(obj);
json_object_object_add(bindstats, "config-time", obj);
obj = json_object_new_string(nowstr);
CHECKMEM(obj);
json_object_object_add(bindstats, "current-time", obj);
if ((flags & STATS_JSON_SERVER) != 0) {
/* OPCODE counters */
counters = json_object_new_object();
dumparg.result = ISC_R_SUCCESS;
dumparg.type = isc_statsformat_json;
dumparg.arg = counters;
dns_opcodestats_dump(server->opcodestats,
opcodestat_dump, &dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(bindstats, "opcodes", counters);
else
json_object_put(counters);
/* QTYPE counters */
counters = json_object_new_object();
dumparg.result = ISC_R_SUCCESS;
dumparg.arg = counters;
dns_rdatatypestats_dump(server->rcvquerystats,
rdtypestat_dump, &dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(bindstats, "qtypes", counters);
else
json_object_put(counters);
/* server stat counters */
counters = json_object_new_object();
dumparg.result = ISC_R_SUCCESS;
dumparg.arg = counters;
result = dump_counters(server->nsstats, isc_statsformat_json,
counters, NULL, nsstats_xmldesc,
dns_nsstatscounter_max,
nsstats_index, nsstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(bindstats, "nsstats", counters);
else
json_object_put(counters);
/* zone stat counters */
counters = json_object_new_object();
dumparg.result = ISC_R_SUCCESS;
dumparg.arg = counters;
result = dump_counters(server->zonestats, isc_statsformat_json,
counters, NULL, zonestats_xmldesc,
dns_zonestatscounter_max,
zonestats_index, zonestat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(bindstats, "zonestats",
counters);
else
json_object_put(counters);
/* resolver stat counters */
counters = json_object_new_object();
dumparg.result = ISC_R_SUCCESS;
dumparg.arg = counters;
result = dump_counters(server->resolverstats,
isc_statsformat_json, counters, NULL,
resstats_xmldesc,
dns_resstatscounter_max,
resstats_index, resstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(bindstats, "resstats", counters);
else
json_object_put(counters);
}
if ((flags & (STATS_JSON_ZONES | STATS_JSON_SERVER)) != 0) {
viewlist = json_object_new_object();
CHECKMEM(viewlist);
json_object_object_add(bindstats, "views", viewlist);
view = ISC_LIST_HEAD(server->viewlist);
while (view != NULL) {
json_object *za, *v = json_object_new_object();
CHECKMEM(v);
json_object_object_add(viewlist, view->name, v);
za = json_object_new_array();
CHECKMEM(za);
if ((flags & STATS_JSON_ZONES) != 0) {
result = dns_zt_apply(view->zonetable, ISC_TRUE,
zone_jsonrender, za);
if (result != ISC_R_SUCCESS) {
goto error;
}
}
if (json_object_array_length(za) != 0)
json_object_object_add(v, "zones", za);
else
json_object_put(za);
if ((flags & STATS_JSON_SERVER) != 0) {
json_object *res;
dns_stats_t *dstats;
isc_stats_t *istats;
res = json_object_new_object();
CHECKMEM(res);
json_object_object_add(v, "resolver", res);
istats = view->resstats;
if (istats != NULL) {
counters = json_object_new_object();
CHECKMEM(counters);
result = dump_counters(istats,
isc_statsformat_json,
counters, NULL,
resstats_xmldesc,
dns_resstatscounter_max,
resstats_index,
resstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
result = dumparg.result;
goto error;
}
json_object_object_add(res, "stats",
counters);
}
dstats = view->resquerystats;
if (dstats != NULL) {
counters = json_object_new_object();
CHECKMEM(counters);
dumparg.arg = counters;
dumparg.result = ISC_R_SUCCESS;
dns_rdatatypestats_dump(dstats,
rdtypestat_dump,
&dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
result = dumparg.result;
goto error;
}
json_object_object_add(res, "qtypes",
counters);
}
dstats = dns_db_getrrsetstats(view->cachedb);
if (dstats != NULL) {
counters = json_object_new_object();
CHECKMEM(counters);
dumparg.arg = counters;
dumparg.result = ISC_R_SUCCESS;
dns_rdatasetstats_dump(dstats,
rdatasetstats_dump,
&dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
result = dumparg.result;
goto error;
}
json_object_object_add(res,
"cache",
counters);
}
counters = json_object_new_object();
CHECKMEM(counters);
result = dns_cache_renderjson(view->cache,
counters);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
json_object_object_add(res, "cachestats",
counters);
istats = view->adbstats;
if (istats != NULL) {
counters = json_object_new_object();
CHECKMEM(counters);
result = dump_counters(istats,
isc_statsformat_json,
counters, NULL,
adbstats_xmldesc,
dns_adbstats_max,
adbstats_index,
adbstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
result = dumparg.result;
goto error;
}
json_object_object_add(res, "adb",
counters);
}
}
view = ISC_LIST_NEXT(view, link);
}
}
if ((flags & STATS_JSON_NET) != 0) {
/* socket stat counters */
json_object *sockets;
counters = json_object_new_object();
dumparg.result = ISC_R_SUCCESS;
dumparg.arg = counters;
result = dump_counters(server->sockstats,
isc_statsformat_json, counters,
NULL, sockstats_xmldesc,
isc_sockstatscounter_max,
sockstats_index, sockstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto error;
}
if (json_object_get_object(counters)->count != 0)
json_object_object_add(bindstats, "sockstats",
counters);
else
json_object_put(counters);
sockets = json_object_new_object();
CHECKMEM(sockets);
result = isc_socketmgr_renderjson(ns_g_socketmgr, sockets);
if (result != ISC_R_SUCCESS) {
json_object_put(sockets);
goto error;
}
json_object_object_add(bindstats, "socketmgr", sockets);
}
if ((flags & STATS_JSON_TASKS) != 0) {
json_object *tasks = json_object_new_object();
CHECKMEM(tasks);
result = isc_taskmgr_renderjson(ns_g_taskmgr, tasks);
if (result != ISC_R_SUCCESS) {
json_object_put(tasks);
goto error;
}
json_object_object_add(bindstats, "taskmgr", tasks);
}
if ((flags & STATS_JSON_MEM) != 0) {
json_object *memory = json_object_new_object();
CHECKMEM(memory);
result = isc_mem_renderjson(memory);
if (result != ISC_R_SUCCESS) {
json_object_put(memory);
goto error;
}
json_object_object_add(bindstats, "memory", memory);
}
*msg = json_object_to_json_string_ext(bindstats,
JSON_C_TO_STRING_PRETTY);
*msglen = strlen(*msg);
if (rootp != NULL) {
*rootp = bindstats;
bindstats = NULL;
}
result = ISC_R_SUCCESS;
error:
if (bindstats != NULL)
json_object_put(bindstats);
return (result);
}
static isc_result_t
render_json(isc_uint8_t flags, const char *url, const char *querystring,
void *arg, unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args)
{
isc_result_t result;
json_object *bindstats = NULL;
ns_server_t *server = arg;
const char *msg = NULL;
size_t msglen;
char *p;
UNUSED(url);
UNUSED(querystring);
result = generatejson(server, &msglen, &msg, &bindstats, flags);
if (result == ISC_R_SUCCESS) {
*retcode = 200;
*retmsg = "OK";
*mimetype = "application/json";
DE_CONST(msg, p);
isc_buffer_reinit(b, p, msglen);
isc_buffer_add(b, msglen);
*freecb = wrap_jsonfree;
*freecb_args = bindstats;
} else
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
"failed at rendering JSON()");
return (result);
}
static isc_result_t
render_json_all(const char *url, const char *querystring, void *arg,
unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args)
{
return (render_json(STATS_JSON_ALL, url, querystring, arg,
retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_server(const char *url, const char *querystring, void *arg,
unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args)
{
return (render_json(STATS_JSON_SERVER, url, querystring, arg,
retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_zones(const char *url, const char *querystring, void *arg,
unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args)
{
return (render_json(STATS_JSON_ZONES, url, querystring, arg,
retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_mem(const char *url, const char *querystring, void *arg,
unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args)
{
return (render_json(STATS_JSON_MEM, url, querystring, arg,
retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_tasks(const char *url, const char *querystring, void *arg,
unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args)
{
return (render_json(STATS_JSON_TASKS, url, querystring, arg,
retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
static isc_result_t
render_json_net(const char *url, const char *querystring, void *arg,
unsigned int *retcode, const char **retmsg,
const char **mimetype, isc_buffer_t *b,
isc_httpdfree_t **freecb, void **freecb_args)
{
return (render_json(STATS_JSON_NET, url, querystring, arg,
retcode, retmsg, mimetype, b,
freecb, freecb_args));
}
#endif /* HAVE_JSON */
static isc_result_t
render_xsl(const char *url, const char *querystring, void *args,
unsigned int *retcode, const char **retmsg, const char **mimetype,
@ -1316,7 +1984,22 @@ add_listener(ns_server_t *server, ns_statschannel_t **listenerp,
goto cleanup;
#ifdef HAVE_LIBXML2
isc_httpdmgr_addurl(listener->httpdmgr, "/xml", render_index, server);
isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server);
#endif
#ifdef HAVE_JSON
isc_httpdmgr_addurl(listener->httpdmgr, "/json",
render_json_all, server);
isc_httpdmgr_addurl(listener->httpdmgr, "/json/server",
render_json_server, server);
isc_httpdmgr_addurl(listener->httpdmgr, "/json/zones",
render_json_zones, server);
isc_httpdmgr_addurl(listener->httpdmgr, "/json/tasks",
render_json_tasks, server);
isc_httpdmgr_addurl(listener->httpdmgr, "/json/net",
render_json_net, server);
isc_httpdmgr_addurl(listener->httpdmgr, "/json/mem",
render_json_mem, server);
#endif
isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", render_xsl,
server);

View File

@ -239,6 +239,9 @@ int sigwait(const unsigned int *set, int *sig);
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define if libjson was found */
#undef HAVE_JSON
/* Define to 1 if you have the <kerberosv5/krb5.h> header file. */
#undef HAVE_KERBEROSV5_KRB5_H

55
configure vendored
View File

@ -1467,6 +1467,7 @@ with_gssapi
with_randomdev
enable_threads
with_libxml2
with_libjson
enable_largefile
with_purify
with_libtool
@ -2177,6 +2178,7 @@ Optional Packages:
--with-gssapi=PATH Specify path for system-supplied GSSAPI [default=yes]
--with-randomdev=PATH Specify path for random device
--with-libxml2=PATH Build with libxml2 library yes|no|path
--with-libjson=PATH Build with libjson0 library yes|no|path
--with-purify=PATH use Rational purify
--with-libtool use GNU libtool
--with-export-libdir=PATH
@ -16011,6 +16013,59 @@ else
$as_echo "no" >&6; }
fi
#
# was --with-libjson specified?
#
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for json library" >&5
$as_echo_n "checking for json library... " >&6; }
# Check whether --with-libjson was given.
if test "${with_libjson+set}" = set; then :
withval=$with_libjson; use_libjson="$withval"
else
use_libjson="auto"
fi
case "$use_libjson" in
no)
libjson_libs=""
;;
auto|yes)
if test -f "/usr/include/json/json.h"
then
libjson_libs="-ljson"
libjson_cflags="-I /usr/include/json"
else
libjson_libs=""
fi
;;
*)
if test -f "${use_libjson}/include/json/json.h"
then
libjson_libs="-L${use_libjson}/lib -ljson"
libjson_cflags="-I${use_libjson}/include/json"
else
as_fn_error $? "$use_libjson/include/json.h not found." "$LINENO" 5
fi
;;
esac
HERE
if test "X${libjson_libs}" != "X"
then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
CFLAGS="$CFLAGS $libjson_cflags"
LIBS="$LIBS $libjson_libs"
$as_echo "#define HAVE_JSON 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
#
# In solaris 10, SMF can manage named service
#

View File

@ -1483,6 +1483,49 @@ else
AC_MSG_RESULT(no)
fi
#
# was --with-libjson specified?
#
AC_MSG_CHECKING(for json library)
AC_ARG_WITH(libjson,
[ --with-libjson[=PATH] Build with libjson0 library [yes|no|path]],
use_libjson="$withval", use_libjson="auto")
case "$use_libjson" in
no)
libjson_libs=""
;;
auto|yes)
if test -f "/usr/include/json/json.h"
then
libjson_libs="-ljson"
libjson_cflags="-I /usr/include/json"
else
libjson_libs=""
fi
;;
*)
if test -f "${use_libjson}/include/json/json.h"
then
libjson_libs="-L${use_libjson}/lib -ljson"
libjson_cflags="-I${use_libjson}/include/json"
else
AC_MSG_ERROR([$use_libjson/include/json.h not found.])
fi
;;
esac
HERE
if test "X${libjson_libs}" != "X"
then
AC_MSG_RESULT(yes)
CFLAGS="$CFLAGS $libjson_cflags"
LIBS="$LIBS $libjson_libs"
AC_DEFINE(HAVE_JSON, 1, [Define if libjson was found])
else
AC_MSG_RESULT(no)
fi
#
# In solaris 10, SMF can manage named service
#

View File

@ -10504,8 +10504,9 @@ ns.domain.com.rpz-nsdname CNAME .
This statement intends to be flexible to support multiple
communication protocols in the future, but currently only
HTTP access is supported.
It requires that BIND 9 be compiled with libxml2;
the <command>statistics-channels</command> statement is
It requires that BIND 9 be compiled with libxml2 and/or
json-c (also known as libjson0); the
<command>statistics-channels</command> statement is
still accepted even if it is built without the library,
but any HTTP access will fail with an error.
</para>
@ -10514,7 +10515,8 @@ ns.domain.com.rpz-nsdname CNAME .
An <command>inet</command> control channel is a TCP socket
listening at the specified <command>ip_port</command> on the
specified <command>ip_addr</command>, which can be an IPv4 or IPv6
address. An <command>ip_addr</command> of <literal>*</literal> (asterisk) is
address. An <command>ip_addr</command> of <literal>*</literal>
(asterisk) is
interpreted as the IPv4 wildcard address; connections will be
accepted on any of the system's IPv4 addresses.
To listen on the IPv6 wildcard address,
@ -10545,6 +10547,41 @@ ns.domain.com.rpz-nsdname CNAME .
<command>named</command> will not open any communication channels.
</para>
<para>
The statistics are available in various formats and views
depending on the URI used to access them. For example, if
the statistics channel is configured to listen on 127.0.0.1
port 8888, then the statistics are accessible in XML format at
<ulink url="http://127.0.0.1:8888/"
>http://127.0.0.1:8888/</ulink> or
<ulink url="http://127.0.0.1:8888/xml"
>http://127.0.0.1:8888/xml</ulink>. A CSS file is
included which can format the XML statistics into tables
when viewed with a stylesheet-capable browser, and into
charts and graphs when using a javascript-capable browser.
</para>
<para>
The full set of statistics can also be read in JSON format at
<ulink url="http://127.0.0.1:8888/json"
>http://127.0.0.1:8888/json</ulink>.
Broken-out subsets of the statistics can be viewed at
<ulink url="http://127.0.0.1:8888/json/server"
>http://127.0.0.1:8888/json/server</ulink>
(server and resolver statistics),
<ulink url="http://127.0.0.1:8888/json/zones"
>http://127.0.0.1:8888/json/zones</ulink>
(zone statistics),
<ulink url="http://127.0.0.1:8888/json/net"
>http://127.0.0.1:8888/json/net</ulink>
(network status and socket statistics),
<ulink url="http://127.0.0.1:8888/json/mem"
>http://127.0.0.1:8888/json/mem</ulink>
(memory manager statistics),
<ulink url="http://127.0.0.1:8888/json/tasks"
>http://127.0.0.1:8888/json/tasks</ulink>
(task manager statistics).
</para>
</sect2>
<sect2 id="trusted-keys">

View File

@ -21,6 +21,7 @@
#include <config.h>
#include <isc/json.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/string.h>
@ -29,6 +30,7 @@
#include <isc/time.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <isc/xml.h>
#include <dns/cache.h>
#include <dns/db.h>
@ -1448,3 +1450,85 @@ error:
return (xmlrc);
}
#endif
#ifdef HAVE_JSON
#define CHECKMEM(m) do { \
if (m == NULL) { \
result = ISC_R_NOMEMORY;\
goto error;\
} \
} while(0)
isc_result_t
dns_cache_renderjson(dns_cache_t *cache, json_object *cstats) {
isc_result_t result = ISC_R_SUCCESS;
int indices[dns_cachestatscounter_max];
isc_uint64_t values[dns_cachestatscounter_max];
json_object *obj;
REQUIRE(VALID_CACHE(cache));
getcounters(cache->stats, isc_statsformat_file,
dns_cachestatscounter_max, indices, values);
obj = json_object_new_int64(values[dns_cachestatscounter_hits]);
CHECKMEM(obj);
json_object_object_add(cstats, "CacheHits", obj);
obj = json_object_new_int64(values[dns_cachestatscounter_misses]);
CHECKMEM(obj);
json_object_object_add(cstats, "CacheMisses", obj);
obj = json_object_new_int64(values[dns_cachestatscounter_queryhits]);
CHECKMEM(obj);
json_object_object_add(cstats, "QueryHits", obj);
obj = json_object_new_int64(values[dns_cachestatscounter_querymisses]);
CHECKMEM(obj);
json_object_object_add(cstats, "QueryMisses", obj);
obj = json_object_new_int64(values[dns_cachestatscounter_deletelru]);
CHECKMEM(obj);
json_object_object_add(cstats, "DeleteLRU", obj);
obj = json_object_new_int64(values[dns_cachestatscounter_deletettl]);
CHECKMEM(obj);
json_object_object_add(cstats, "DeleteTTL", obj);
obj = json_object_new_int64(dns_db_nodecount(cache->db));
CHECKMEM(obj);
json_object_object_add(cstats, "CacheNodes", obj);
obj = json_object_new_int64(dns_db_hashsize(cache->db));
CHECKMEM(obj);
json_object_object_add(cstats, "CacheBuckets", obj);
obj = json_object_new_int64(isc_mem_total(cache->mctx));
CHECKMEM(obj);
json_object_object_add(cstats, "TreeMemTotal", obj);
obj = json_object_new_int64(isc_mem_inuse(cache->mctx));
CHECKMEM(obj);
json_object_object_add(cstats, "TreeMemInUse", obj);
obj = json_object_new_int64(isc_mem_maxinuse(cache->mctx));
CHECKMEM(obj);
json_object_object_add(cstats, "HeapMemMax", obj);
obj = json_object_new_int64(isc_mem_total(cache->hmctx));
CHECKMEM(obj);
json_object_object_add(cstats, "HeapMemTotal", obj);
obj = json_object_new_int64(isc_mem_inuse(cache->hmctx));
CHECKMEM(obj);
json_object_object_add(cstats, "HeapMemInUse", obj);
obj = json_object_new_int64(isc_mem_maxinuse(cache->hmctx));
CHECKMEM(obj);
json_object_object_add(cstats, "HeapMemMax", obj);
result = ISC_R_SUCCESS;
error:
return (result);
}
#endif

View File

@ -49,6 +49,7 @@
*** Imports
***/
#include <isc/json.h>
#include <isc/lang.h>
#include <isc/stats.h>
#include <isc/stdtime.h>
@ -327,6 +328,14 @@ dns_cache_renderxml(dns_cache_t *cache, xmlTextWriterPtr writer);
*/
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_JSON
isc_result_t
dns_cache_renderjson(dns_cache_t *cache, json_object *cstats);
/*
* Render cache statistics and status in JSON
*/
#endif /* HAVE_JSON */
ISC_LANG_ENDDECLS
#endif /* DNS_CACHE_H */

View File

@ -938,9 +938,10 @@ isc_httpd_senddone(isc_task_t *task, isc_event_t *ev)
*/
if (httpd->freecb != NULL) {
isc_buffer_t *b = NULL;
if (isc_buffer_length(&httpd->bodybuffer) > 0)
if (isc_buffer_length(&httpd->bodybuffer) > 0) {
b = &httpd->bodybuffer;
httpd->freecb(b, httpd->freecb_arg);
httpd->freecb(b, httpd->freecb_arg);
}
NOTICE("senddone free callback performed");
}
if (ISC_LINK_LINKED(&httpd->bodybuffer, link)) {

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or 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.
*/
#ifndef ISC_JSON_H
#define ISC_JSON_H 1
/*
* This file is here mostly to make it easy to add additional libjson header
* files as needed across all the users of this file. Rather than place
* these libjson includes in each file, one include makes it easy to handle
* the ifdef as well as adding the ability to add additional functions
* which may be useful.
*/
#ifdef HAVE_JSON
#include <json/json.h>
#endif
#define ISC_JSON_RENDERCONFIG 0x00000001 /* render config data */
#define ISC_JSON_RENDERSTATS 0x00000002 /* render stats */
#define ISC_JSON_RENDERALL 0x000000ff /* render everything */
#endif /* ISC_JSON_H */

View File

@ -24,6 +24,7 @@
#include <stdio.h>
#include <isc/json.h>
#include <isc/lang.h>
#include <isc/mutex.h>
#include <isc/platform.h>
@ -554,6 +555,15 @@ isc_mem_renderxml(xmlTextWriterPtr writer);
*/
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_JSON
isc_result_t
isc_mem_renderjson(json_object *memobj);
/*%<
* Render all contexts' statistics and status in JSON.
*/
#endif /* HAVE_JSON */
/*
* Memory pools
*/

View File

@ -57,13 +57,14 @@
*** Imports
***/
#include <isc/lang.h>
#include <isc/types.h>
#include <isc/event.h>
#include <isc/eventclass.h>
#include <isc/time.h>
#include <isc/lang.h>
#include <isc/json.h>
#include <isc/region.h>
#include <isc/sockaddr.h>
#include <isc/time.h>
#include <isc/types.h>
#include <isc/xml.h>
ISC_LANG_BEGINDECLS
@ -1143,15 +1144,21 @@ isc__socketmgr_maxudp(isc_socketmgr_t *mgr, int maxudp);
*/
#ifdef HAVE_LIBXML2
int
isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer);
/*%<
* Render internal statistics and other state into the XML document.
*/
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_JSON
isc_result_t
isc_socketmgr_renderjson(isc_socketmgr_t *mgr, json_object *stats);
/*%<
* Render internal statistics and other state into JSON format.
*/
#endif /* HAVE_JSON */
#ifdef USE_SOCKETIMPREGISTER
/*%<
* See isc_socketmgr_create() above.

View File

@ -81,6 +81,7 @@
***/
#include <isc/eventclass.h>
#include <isc/json.h>
#include <isc/lang.h>
#include <isc/stdtime.h>
#include <isc/types.h>
@ -787,10 +788,13 @@ isc_taskmgr_excltask(isc_taskmgr_t *mgr, isc_task_t **taskp);
#ifdef HAVE_LIBXML2
int
isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer);
#endif
#ifdef HAVE_JSON
isc_result_t
isc_taskmgr_renderjson(isc_taskmgr_t *mgr, json_object *tasksobj);
#endif
/*%<

View File

@ -129,7 +129,8 @@ typedef enum {
/*% Statistics formats (text file or XML) */
typedef enum {
isc_statsformat_file,
isc_statsformat_xml
isc_statsformat_xml,
isc_statsformat_json
} isc_statsformat_t;
#endif /* ISC_TYPES_H */

View File

@ -27,6 +27,7 @@
#include <limits.h>
#include <isc/json.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/msgs.h>
@ -2379,18 +2380,21 @@ isc_mem_references(isc_mem_t *ctx0) {
return (references);
}
#ifdef HAVE_LIBXML2
#if defined(HAVE_LIBXML2) || defined(HAVE_JSON)
typedef struct summarystat {
isc_uint64_t total;
isc_uint64_t inuse;
isc_uint64_t blocksize;
isc_uint64_t contextsize;
} summarystat_t;
#endif
#ifdef HAVE_LIBXML2
#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
static int
renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) {
xml_renderctx(isc__mem_t *ctx, summarystat_t *summary,
xmlTextWriterPtr writer)
{
int xmlrc;
REQUIRE(VALID_CONTEXT(ctx));
@ -2501,7 +2505,7 @@ isc_mem_renderxml(xmlTextWriterPtr writer) {
for (ctx = ISC_LIST_HEAD(contexts);
ctx != NULL;
ctx = ISC_LIST_NEXT(ctx, link)) {
xmlrc = renderctx(ctx, &summary, writer);
xmlrc = xml_renderctx(ctx, &summary, writer);
if (xmlrc < 0) {
UNLOCK(&lock);
goto error;
@ -2549,4 +2553,160 @@ isc_mem_renderxml(xmlTextWriterPtr writer) {
}
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_JSON
#define CHECKMEM(m) do { \
if (m == NULL) { \
result = ISC_R_NOMEMORY;\
goto error;\
} \
} while(0)
static isc_result_t
json_renderctx(isc__mem_t *ctx, summarystat_t *summary, json_object *array) {
isc_result_t result = ISC_R_FAILURE;
json_object *ctxobj, *obj;
char buf[1024];
REQUIRE(VALID_CONTEXT(ctx));
REQUIRE(summary != NULL);
REQUIRE(array != NULL);
MCTXLOCK(ctx, &ctx->lock);
summary->contextsize += sizeof(*ctx) +
(ctx->max_size + 1) * sizeof(struct stats) +
ctx->max_size * sizeof(element *) +
ctx->basic_table_count * sizeof(char *);
summary->total += ctx->total;
summary->inuse += ctx->inuse;
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0)
summary->blocksize += ctx->basic_table_count *
NUM_BASIC_BLOCKS * ctx->mem_target;
#if ISC_MEM_TRACKLINES
if (ctx->debuglist != NULL) {
summary->contextsize +=
(ctx->max_size + 1) * sizeof(debuglist_t) +
ctx->debuglistcnt * sizeof(debuglink_t);
}
#endif
ctxobj = json_object_new_object();
CHECKMEM(ctxobj);
sprintf(buf, "%p", ctx);
obj = json_object_new_string(buf);
CHECKMEM(obj);
json_object_object_add(ctxobj, "id", obj);
if (ctx->name[0] != 0) {
obj = json_object_new_string(ctx->name);
CHECKMEM(obj);
json_object_object_add(ctxobj, "name", obj);
}
obj = json_object_new_int64(ctx->references);
CHECKMEM(obj);
json_object_object_add(ctxobj, "references", obj);
obj = json_object_new_int64(ctx->total);
CHECKMEM(obj);
json_object_object_add(ctxobj, "total", obj);
obj = json_object_new_int64(ctx->inuse);
CHECKMEM(obj);
json_object_object_add(ctxobj, "inuse", obj);
obj = json_object_new_int64(ctx->maxinuse);
CHECKMEM(obj);
json_object_object_add(ctxobj, "maxinuse", obj);
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
isc_uint64_t blocksize;
blocksize = ctx->basic_table_count * NUM_BASIC_BLOCKS *
ctx->mem_target;
obj = json_object_new_int64(blocksize);
CHECKMEM(obj);
json_object_object_add(ctxobj, "blocksize", obj);
}
obj = json_object_new_int64(ctx->poolcnt);
CHECKMEM(obj);
json_object_object_add(ctxobj, "pools", obj);
obj = json_object_new_int64(ctx->hi_water);
CHECKMEM(obj);
json_object_object_add(ctxobj, "hiwater", obj);
obj = json_object_new_int64(ctx->lo_water);
CHECKMEM(obj);
json_object_object_add(ctxobj, "lowater", obj);
MCTXUNLOCK(ctx, &ctx->lock);
json_object_array_add(array, ctxobj);
return (ISC_R_SUCCESS);
error:
MCTXUNLOCK(ctx, &ctx->lock);
if (ctxobj != NULL)
json_object_put(ctxobj);
return (result);
}
isc_result_t
isc_mem_renderjson(json_object *memobj) {
isc_result_t result = ISC_R_SUCCESS;
isc__mem_t *ctx;
summarystat_t summary;
isc_uint64_t lost;
json_object *ctxarray, *obj;
memset(&summary, 0, sizeof(summary));
RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
ctxarray = json_object_new_array();
CHECKMEM(ctxarray);
LOCK(&lock);
lost = totallost;
for (ctx = ISC_LIST_HEAD(contexts);
ctx != NULL;
ctx = ISC_LIST_NEXT(ctx, link)) {
result = json_renderctx(ctx, &summary, ctxarray);
if (result != ISC_R_SUCCESS) {
UNLOCK(&lock);
goto error;
}
}
UNLOCK(&lock);
obj = json_object_new_int64(summary.total);
CHECKMEM(obj);
json_object_object_add(memobj, "TotalUse", obj);
obj = json_object_new_int64(summary.inuse);
CHECKMEM(obj);
json_object_object_add(memobj, "InUse", obj);
obj = json_object_new_int64(summary.blocksize);
CHECKMEM(obj);
json_object_object_add(memobj, "BlockSize", obj);
obj = json_object_new_int64(summary.contextsize);
CHECKMEM(obj);
json_object_object_add(memobj, "ContextSize", obj);
obj = json_object_new_int64(lost);
CHECKMEM(obj);
json_object_object_add(memobj, "Lost", obj);
json_object_object_add(memobj, "contexts", ctxarray);
return (ISC_R_SUCCESS);
error:
if (ctxarray != NULL)
json_object_put(ctxarray);
return (result);
}
#endif /* HAVE_JSON */
#endif /* BIND9 */

View File

@ -30,6 +30,7 @@
#include <isc/condition.h>
#include <isc/event.h>
#include <isc/json.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/msgs.h>
@ -1780,7 +1781,8 @@ isc_task_exiting(isc_task_t *t) {
}
#if defined(HAVE_LIBXML2) && defined(BIND9)
#ifdef BIND9
#ifdef HAVE_LIBXML2
#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
int
isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) {
@ -1881,4 +1883,117 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) {
return (xmlrc);
}
#endif /* HAVE_LIBXML2 && BIND9 */
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_JSON
#define CHECKMEM(m) do { \
if (m == NULL) { \
result = ISC_R_NOMEMORY;\
goto error;\
} \
} while(0)
isc_result_t
isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, json_object *tasks) {
isc_result_t result = ISC_R_SUCCESS;
isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0;
isc__task_t *task = NULL;
json_object *obj = NULL, *array = NULL, *taskobj = NULL;
LOCK(&mgr->lock);
/*
* Write out the thread-model, and some details about each depending
* on which type is enabled.
*/
#ifdef ISC_PLATFORM_USETHREADS
obj = json_object_new_string("threaded");
CHECKMEM(obj);
json_object_object_add(tasks, "thread-model", obj);
obj = json_object_new_int(mgr->workers);
CHECKMEM(obj);
json_object_object_add(tasks, "worker-threads", obj);
#else /* ISC_PLATFORM_USETHREADS */
obj = json_object_new_string("non-threaded");
CHECKMEM(obj);
json_object_object_add(tasks, "thread-model", obj);
obj = json_object_new_int(mgr->refs);
CHECKMEM(obj);
json_object_object_add(tasks, "references", obj);
#endif /* ISC_PLATFORM_USETHREADS */
obj = json_object_new_int(mgr->default_quantum);
CHECKMEM(obj);
json_object_object_add(tasks, "default-quantum", obj);
obj = json_object_new_int(mgr->tasks_running);
CHECKMEM(obj);
json_object_object_add(tasks, "tasks-running", obj);
obj = json_object_new_int(mgr->tasks_ready);
CHECKMEM(obj);
json_object_object_add(tasks, "tasks-ready", obj);
array = json_object_new_array();
CHECKMEM(array);
for (task = ISC_LIST_HEAD(mgr->tasks);
task != NULL;
task = ISC_LIST_NEXT(task, link))
{
char buf[255];
LOCK(&task->lock);
taskobj = json_object_new_object();
CHECKMEM(taskobj);
json_object_array_add(array, taskobj);
sprintf(buf, "%p", task);
obj = json_object_new_string(buf);
CHECKMEM(obj);
json_object_object_add(taskobj, "id", obj);
if (task->name[0] != 0) {
obj = json_object_new_string(task->name);
CHECKMEM(obj);
json_object_object_add(taskobj, "name", obj);
}
obj = json_object_new_int(task->references);
CHECKMEM(obj);
json_object_object_add(taskobj, "references", obj);
obj = json_object_new_string(statenames[task->state]);
CHECKMEM(obj);
json_object_object_add(taskobj, "state", obj);
obj = json_object_new_int(task->quantum);
CHECKMEM(obj);
json_object_object_add(taskobj, "quantum", obj);
obj = json_object_new_int(task->nevents);
CHECKMEM(obj);
json_object_object_add(taskobj, "events", obj);
UNLOCK(&task->lock);
}
json_object_object_add(tasks, "tasks", array);
array = NULL;
result = ISC_R_SUCCESS;
error:
if (array != NULL)
json_object_put(array);
if (task != NULL)
UNLOCK(&task->lock);
UNLOCK(&mgr->lock);
return (result);
}
#endif
#endif /* BIND9 */

View File

@ -39,6 +39,7 @@
#include <isc/bufferlist.h>
#include <isc/condition.h>
#include <isc/formatcheck.h>
#include <isc/json.h>
#include <isc/list.h>
#include <isc/log.h>
#include <isc/mem.h>
@ -541,10 +542,16 @@ ISC_SOCKETFUNC_SCOPE isc_boolean_t
isc__socket_isbound(isc_socket_t *sock);
ISC_SOCKETFUNC_SCOPE void
isc__socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes);
#if defined(HAVE_LIBXML2) && defined(BIND9)
#ifdef BIND9
#ifdef HAVE_LIBXML2
ISC_SOCKETFUNC_SCOPE void
isc__socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer);
#endif
#ifdef HAVE_JSON
ISC_SOCKETFUNC_SCOPE isc_result_t
isc__socketmgr_renderjson(isc_socketmgr_t *mgr0, json_object *stats);
#endif
#endif /* BIND9 */
ISC_SOCKETFUNC_SCOPE isc_result_t
isc__socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags,
@ -5956,8 +5963,9 @@ isc__socket_getfd(isc_socket_t *socket0) {
return ((short) socket->fd);
}
#if defined(HAVE_LIBXML2) && defined(BIND9)
#ifdef BIND9
#if defined(HAVE_LIBXML2) && defined(HAVE_JSON)
static const char *
_socktype(isc_sockettype_t type)
{
@ -5972,7 +5980,9 @@ _socktype(isc_sockettype_t type)
else
return ("not-initialized");
}
#endif
#ifdef HAVE_LIBXML2
#define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
ISC_SOCKETFUNC_SCOPE int
isc_socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer) {
@ -6082,3 +6092,144 @@ isc_socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer) {
return (xmlrc);
}
#endif /* HAVE_LIBXML2 */
#ifdef HAVE_JSON
#define CHECKMEM(m) do { \
if (m == NULL) { \
result = ISC_R_NOMEMORY;\
goto error;\
} \
} while(0)
ISC_SOCKETFUNC_SCOPE isc_result_t
isc_socketmgr_renderjson(isc_socketmgr_t *mgr0, json_object *stats) {
isc_result_t result = ISC_R_SUCCESS;
isc__socketmgr_t *mgr = (isc__socketmgr_t *)mgr0;
isc__socket_t *sock = NULL;
char peerbuf[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_t addr;
ISC_SOCKADDR_LEN_T len;
json_object *obj, *array = json_object_new_array();
CHECKMEM(array);
LOCK(&mgr->lock);
#ifdef USE_SHARED_MANAGER
obj = json_object_new_int(mgr->refs);
CHECKMEM(obj);
json_object_object_add(stats, "references", obj);
#endif /* USE_SHARED_MANAGER */
sock = ISC_LIST_HEAD(mgr->socklist);
while (sock != NULL) {
json_object *states, *entry = json_object_new_object();
char buf[255];
CHECKMEM(entry);
json_object_array_add(array, entry);
LOCK(&sock->lock);
sprintf(buf, "%p", sock);
obj = json_object_new_string(buf);
CHECKMEM(obj);
json_object_object_add(entry, "id", obj);
if (sock->name[0] != 0) {
obj = json_object_new_string(sock->name);
CHECKMEM(obj);
json_object_object_add(entry, "name", obj);
}
obj = json_object_new_int(sock->references);
CHECKMEM(obj);
json_object_object_add(entry, "references", obj);
obj = json_object_new_string(_socktype(sock->type));
CHECKMEM(obj);
json_object_object_add(entry, "type", obj);
if (sock->connected) {
isc_sockaddr_format(&sock->peer_address, peerbuf,
sizeof(peerbuf));
obj = json_object_new_string(peerbuf);
CHECKMEM(obj);
json_object_object_add(entry, "peer-address", obj);
}
len = sizeof(addr);
if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
obj = json_object_new_string(peerbuf);
CHECKMEM(obj);
json_object_object_add(entry, "local-address", obj);
}
states = json_object_new_array();
CHECKMEM(states);
json_object_object_add(entry, "states", states);
if (sock->pending_recv) {
obj = json_object_new_string("pending-receive");
CHECKMEM(obj);
json_object_array_add(states, obj);
}
if (sock->pending_send) {
obj = json_object_new_string("pending-send");
CHECKMEM(obj);
json_object_array_add(states, obj);
}
if (sock->pending_accept) {
obj = json_object_new_string("pending-accept");
CHECKMEM(obj);
json_object_array_add(states, obj);
}
if (sock->listener) {
obj = json_object_new_string("listener");
CHECKMEM(obj);
json_object_array_add(states, obj);
}
if (sock->connected) {
obj = json_object_new_string("connected");
CHECKMEM(obj);
json_object_array_add(states, obj);
}
if (sock->connecting) {
obj = json_object_new_string("connecting");
CHECKMEM(obj);
json_object_array_add(states, obj);
}
if (sock->bound) {
obj = json_object_new_string("bound");
CHECKMEM(obj);
json_object_array_add(states, obj);
}
UNLOCK(&sock->lock);
sock = ISC_LIST_NEXT(sock, link);
}
json_object_object_add(stats, "sockets", array);
array = NULL;
result = ISC_R_SUCCESS;
error:
if (array != NULL)
json_object_put(array);
if (sock != NULL)
UNLOCK(&sock->lock);
UNLOCK(&mgr->lock);
return (result);
}
#endif /* HAVE_JSON */
#endif /* BIND9 */