#include <named/server.h>
#include <named/statschannel.h>
+#ifdef HAVE_JSON_H
+#include <json/json.h>
+#endif
+
#include "bind9.xsl.h"
struct ns_statschannel {
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
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];
break;
case isc_statsformat_xml:
#ifdef HAVE_LIBXML2
- writer = arg;
+ writer = (xmlTextWriterPtr) arg;
if (category != NULL) {
/* <NameOfCategory> */
#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);
xmlTextWriterPtr writer;
int xmlrc;
#endif
+#ifdef HAVE_JSON
+ json_object *zoneobj, *obj;
+#endif
if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE)
== 0) {
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;
}
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) {
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;
}
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);
"%" 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;
}
/* XXXMLG below here sucks. (not so much) */
-
static isc_result_t
zone_xmlrender(dns_zone_t *zone, void *arg) {
isc_result_t result;
#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,
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);
#include <limits.h>
+#include <isc/json.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/msgs.h>
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));
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;
}
#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 */