From 1319ebdf37fc25db48cd520c1a43f0a783686850 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 16 Aug 2008 15:14:20 +0200 Subject: [PATCH] Something new to show cluster statistics in XML --- Makefile | 2 + ModuleClusterStats.py | 38 ++++ handler_clusterstats.c | 458 +++++++++++++++++++++++++++++++++++++++++++++++++ handler_clusterstats.h | 89 ++++++++++ 4 files changed, 587 insertions(+) create mode 100644 ModuleClusterStats.py create mode 100644 handler_clusterstats.c create mode 100644 handler_clusterstats.h diff --git a/Makefile b/Makefile index a614147..5194e44 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,11 @@ all: handler_example.c + gcc -g -o create create.c gcc -g -Wall -lrrd -lavahi-client -o rrdsaver rrdsaver.c gcc -g -lavahi-client -lvirt -o domumdns domumdns.c gcc -g -fPIC -shared -I/opt/cherokee/include -o libplugin_example.so handler_example.c gcc -g -fPIC -shared -I/opt/cherokee/include -lavahi-client -o libplugin_avahi.so handler_avahi.c gcc -DTRACE_ENABLED -D_GNU_SOURCE -I/usr/include/libxml2 -g -fPIC -shared -I/opt/cherokee/include -lrrd -lavahi-client -lvirt -o libplugin_virt.so handler_avahi.c handler_virt.c experiment5.c + gcc -g -fPIC -shared -I/opt/cherokee/include -lavahi-client -o libplugin_clusterstats.so handler_clusterstats.c install: cp *.so /opt/cherokee/lib/cherokee/. diff --git a/ModuleClusterStats.py b/ModuleClusterStats.py new file mode 100644 index 0000000..e2f81e2 --- /dev/null +++ b/ModuleClusterStats.py @@ -0,0 +1,38 @@ +from Form import * +from Table import * +from Module import * +from validations import * + +NOTE_SERVICE_TYPE = 'What service type should we browse on the network for.' + +class ModuleAvahiBase (Module, FormHelper): + PROPERTIES = [ + 'service_type' + ] + + def __init__ (self, cfg, prefix, name, submit_url): + FormHelper.__init__ (self, name, cfg) + Module.__init__ (self, name, cfg, prefix, submit_url) + + def _op_render (self): + txt = "

Avahi options

" + + table = TableProps() + self.AddPropEntry (table, "mDNS Service Type", "%s!service_type" % (self._prefix), NOTE_SERVICE_TYPE) + txt += self.Indent(table) + + return txt + + def _op_apply_changes (self, uri, post): + self.ApplyChangesPrefix (self._prefix, [], post) + + +class ModuleAvahi (ModuleAvahiBase): + def __init__ (self, cfg, prefix, submit_url): + ModuleAvahiBase.__init__ (self, cfg, prefix, 'avahi', submit_url) + + def _op_render (self): + return ModuleAvahiBase._op_render (self) + + def _op_apply_changes (self, uri, post): + return ModuleAvahiBase._op_apply_changes (self, uri, post) diff --git a/handler_clusterstats.c b/handler_clusterstats.c new file mode 100644 index 0000000..86ab2b3 --- /dev/null +++ b/handler_clusterstats.c @@ -0,0 +1,458 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Cherokee + * + * Authors: + * Alvaro Lopez Ortega + * Stefan de Konink + * + * Copyright (C) 2001-2008 Alvaro Lopez Ortega + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "handler_clusterstats.h" +#include + +#include +#include + +#include +#include + +/* Plug-in initialization + * + * In this function you can use any of these: + * http_delete | http_get | http_post | http_put + * + * For a full list: cherokee_http_method_t + * + * It is what your handler to be implements. + * + */ +PLUGIN_INFO_HANDLER_EASIEST_INIT (clusterstats, http_get); + + +/* Methods implementation + */ + +static ret_t +props_free (cherokee_handler_clusterstats_props_t *props) +{ + if (props->threaded_poll) + avahi_threaded_poll_stop(props->threaded_poll); + + if (props->sb) + avahi_service_browser_free(props->sb); + + if (props->client) + avahi_client_free(props->client); + + if (props->threaded_poll) + avahi_threaded_poll_free(props->threaded_poll); + + cherokee_buffer_mrproper(&props->service_type); + + cherokee_avl_mrproper (&props->entries, (cherokee_func_free_t) cherokee_buffer_mrproper); +// cherokee_avl_mrproper (&props->entries, NULL); + + return cherokee_module_props_free_base (MODULE_PROPS(props)); +} + + +ret_t +cherokee_handler_clusterstats_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props) +{ + cherokee_list_t *i; + cherokee_handler_clusterstats_props_t *props; + int error; + + if (*_props == NULL) { + CHEROKEE_NEW_STRUCT (n, handler_clusterstats_props); + + cherokee_module_props_init_base (MODULE_PROPS(n), + MODULE_PROPS_FREE(props_free)); + + /* Look at handler_clusterstats.h + * This is an avahi of configuration. + */ + cherokee_buffer_init (&n->service_type); + + *_props = MODULE_PROPS(n); + } + + props = PROP_CLUSTERSTATS(*_props); + + cherokee_config_node_foreach (i, conf) { + cherokee_config_node_t *subconf = CONFIG_NODE(i); + + if (equal_buf_str (&subconf->key, "service_type")) { + cherokee_buffer_add_buffer (&props->service_type, &subconf->val); + } +/* else { + PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", subconf->key.buf); + return ret_error; + }*/ + } + + /* If the configuration for avahi was not set, we should not continue */ + if (props->service_type.len == 0) { + return ret_error; + } + + props->client = NULL; + props->sb = NULL; + props->threaded_poll = NULL; + + cherokee_avl_init(&props->entries); + + if (!(props->threaded_poll = avahi_threaded_poll_new())) { + return ret_error; + } + + if (!(props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), 0, client_callback, props, &error))) { + return ret_error; + } + + /* create some browsers on the client object here, if you wish */ + if (!(props->sb = avahi_service_browser_new(props->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, props->service_type.buf, NULL, 0, browse_callback, props))) { + TRACE ("avahi", "Failed to create service browser: %s (%s)\n", avahi_strerror(avahi_client_errno(props->client)), props->service_type.buf); + return ret_error; + } + + /* Finally, start the event loop thread */ + if (avahi_threaded_poll_start(props->threaded_poll) < 0) { + return ret_error; + } + + + return ret_ok; +} + +ret_t +cherokee_handler_clusterstats_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props) +{ + ret_t ret; + + CHEROKEE_NEW_STRUCT (n, handler_clusterstats); + + /* Init the base class object + */ + cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(clusterstats)); + + MODULE(n)->init = (handler_func_init_t) cherokee_handler_clusterstats_init; + MODULE(n)->free = (module_func_free_t) cherokee_handler_clusterstats_free; + HANDLER(n)->step = (handler_func_step_t) cherokee_handler_clusterstats_step; + HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_clusterstats_add_headers; + + HANDLER(n)->support = hsupport_length | hsupport_range; + + /* Init + */ + ret = cherokee_buffer_init (&n->buffer); + if (unlikely(ret != ret_ok)) + return ret; + + ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024); + if (unlikely(ret != ret_ok)) + return ret; + + *hdl = HANDLER(n); + + return ret_ok; +} + + +ret_t +cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t *hdl) +{ + cherokee_buffer_mrproper (&hdl->buffer); + + return ret_ok; +} + +static ret_t +while_func_entries (cherokee_buffer_t *key, void *value, void *param) { + cherokee_buffer_t *buf = (cherokee_buffer_t *)param; + AvahiStringList *list = (AvahiStringList *)value; + char *avahi_key, *avahi_value; + unsigned int len; + + cherokee_buffer_add_str (buf, " \n"); + cherokee_buffer_add_va (buf, " %s\n", key->buf); + + if ((len = avahi_string_list_length (list)) > 0) { + unsigned int i; + cherokee_buffer_add_str (buf, " \n"); + + do { + avahi_string_list_get_pair (list, &avahi_key, &avahi_value, NULL); + cherokee_buffer_add_va (buf, " %s\n", avahi_key, avahi_value); + avahi_free(avahi_key); + avahi_free(avahi_value); + list = avahi_string_list_get_next(list); + } while (avahi_string_list_get_next(list) != NULL); + + cherokee_buffer_add_str (buf, " \n"); + } else { + cherokee_buffer_add_str (buf, " \n"); + } + + cherokee_buffer_add_str (buf, " \n"); + + return ret_ok; +} + +static void +clusterstats_build_page (cherokee_handler_clusterstats_t *hdl) +{ + ret_t ret; + cherokee_buffer_t *buf; + size_t len; + + /* Init + */ + buf = &hdl->buffer; + + /* Useful output + */ + + /* First, block the event loop */ + avahi_threaded_poll_lock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll); + + /* Than, do your stuff */ + if (cherokee_avl_len(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &len) == ret_ok && len > 0) { + cherokee_buffer_add_str (buf, "\n"); + cherokee_avl_while (&HDL_CLUSTERSTATS_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL); + cherokee_buffer_add_str (buf, ""); + } else { + cherokee_buffer_add_str (buf, ""); + } + + /* Finally, unblock the event loop */ + avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll); +} + +ret_t +cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t *hdl) +{ + ret_t ret; + void *param; + cint_t web_interface = 1; + + /* Build the page + */ + if (web_interface) { + clusterstats_build_page (hdl); + } + + hdl->action = send_page; + + return ret_ok; +} + + +ret_t +cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer) +{ + if (cherokee_buffer_is_empty (&hdl->buffer)) + return ret_eof; + + cherokee_buffer_add (buffer, hdl->buffer.buf, 1024); + cherokee_buffer_move_to_begin (&hdl->buffer, 1024); + + if (cherokee_buffer_is_empty (&hdl->buffer)) + return ret_eof_have_data; + + return ret_ok; + +// cherokee_buffer_add_buffer (buffer, &hdl->buffer); +// return ret_eof_have_data; +} + + +ret_t +cherokee_handler_clusterstats_add_headers (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer) +{ + if (hdl->buffer.len == 0) { + cherokee_connection_t *conn = HANDLER_CONN(hdl); + conn->error_code = http_not_found; + } + + cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len); + + switch (hdl->action) { + case send_page: + default: + cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF); + break; + } + + return ret_ok; +} + + +/* Avahi example stuff */ + +static void resolve_callback( + AvahiServiceResolver *r, + AVAHI_GCC_UNUSED AvahiIfIndex interface, + AVAHI_GCC_UNUSED AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void* userdata) { + assert(r); + + /* Called whenever a service has been resolved successfully or timed out */ + + switch (event) { + case AVAHI_RESOLVER_FAILURE: + TRACE("avahi", "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r)))); + avahi_service_resolver_free(r); + break; + + case AVAHI_RESOLVER_FOUND: { + char a[AVAHI_ADDRESS_STR_MAX], *t; + void **val; + AvahiStringList *nonvol = avahi_string_list_copy(txt); + + avahi_address_snprint(a, sizeof(a), address); + + + cherokee_buffer_t buf; + cherokee_buffer_init(&buf); + cherokee_buffer_add(&buf, name, strlen(name)); + + if (cherokee_avl_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, val) == ret_ok) { + avahi_string_list_free((AvahiStringList*) *val); + } + + nonvol = avahi_string_list_add_pair(nonvol, "dom0", host_name); + + cherokee_avl_add(&PROP_CLUSTERSTATS(userdata)->entries, &buf, (void* ) nonvol); + cherokee_buffer_mrproper(&buf); + +// cherokee_avl_add_ptr (&PROP_CLUSTERSTATS(userdata)->entries, name, (void *) host_name); + + TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain); + + t = avahi_string_list_to_string(txt); + + TRACE("avahi", + "\t%s:%u (%s)\n" + "\tTXT=%s\n" + "\tcookie is %u\n" + "\tis_local: %i\n" + "\tour_own: %i\n" + "\twide_area: %i\n" + "\tmulticast: %i\n" + "\tcached: %i\n", + host_name, port, a, + t, + avahi_string_list_get_service_cookie(txt), + !!(flags & AVAHI_LOOKUP_RESULT_LOCAL), + !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN), + !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA), + !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST), + !!(flags & AVAHI_LOOKUP_RESULT_CACHED)); + + avahi_free(t); + } + } +} + +static void browse_callback( + AvahiServiceBrowser *b, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, + void* userdata) { + + AvahiClient *c = PROP_CLUSTERSTATS(userdata)->client; + assert(b); + + /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ + + switch (event) { + case AVAHI_BROWSER_FAILURE: + TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); + avahi_threaded_poll_stop(PROP_CLUSTERSTATS(userdata)->threaded_poll); + return; + + case AVAHI_BROWSER_NEW: + TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + + /* We ignore the returned resolver object. In the callback + function we free it. If the server is terminated before + the callback function is called the server will free + the resolver for us. */ + + if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata))) + TRACE("avahi", "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); + + break; + + case AVAHI_BROWSER_REMOVE: { + void **val; + cherokee_buffer_t buf; + cherokee_buffer_init(&buf); + cherokee_buffer_add(&buf, name, strlen(name)); + if (cherokee_avl_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, val) == ret_ok) { + avahi_string_list_free((AvahiStringList*) *val); + } + cherokee_buffer_mrproper(&buf); + +// cherokee_avl_del_ptr(&PROP_CLUSTERSTATS(userdata)->entries, name, val); + + TRACE("avahi", "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + break; + } + + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + TRACE("avahi", "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); + break; + } +} + +static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) { + assert(c); + + /* Called whenever the client or server state changes */ + + if (state == AVAHI_CLIENT_FAILURE) { + TRACE("avahi", "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c))); + avahi_threaded_poll_stop(PROP_CLUSTERSTATS(userdata)->threaded_poll); + } +} + +ret_t +cherokee_handler_clusterstats_props_init_base (cherokee_handler_clusterstats_props_t *props, module_func_props_free_t free_func) +{ + cherokee_buffer_init (&props->service_type); + + return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func); +} diff --git a/handler_clusterstats.h b/handler_clusterstats.h new file mode 100644 index 0000000..0dd4beb --- /dev/null +++ b/handler_clusterstats.h @@ -0,0 +1,89 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Cherokee + * + * Authors: + * Alvaro Lopez Ortega + * Stefan de Konink + * + * Copyright (C) 2001-2008 Alvaro Lopez Ortega + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef CHEROKEE_HANDLER_CLUSTERSTATS_H +#define CHEROKEE_HANDLER_CLUSTERSTATS_H + +#include + +#include +#include + +#include +#include +#include +#include + +/* Data types + */ +typedef struct { + cherokee_module_props_t base; + + /* A table to store all our output */ + cherokee_avl_t entries; + + AvahiClient *client; + AvahiServiceBrowser *sb; + AvahiThreadedPoll *threaded_poll; + + /* Configuration parameters */ + cherokee_buffer_t service_type; +} cherokee_handler_clusterstats_props_t; + +typedef struct { + /* Shared structures */ + cherokee_handler_t handler; + + /* A buffer is your output 'to be' */ + cherokee_buffer_t buffer; + + enum { + send_page, + send_yourmother /* not advised but possible */ + } action; /* this could implement a state machine */ +} cherokee_handler_clusterstats_t; + +#define HDL_CLUSTERSTATS(x) ((cherokee_handler_clusterstats_t *)(x)) +#define PROP_CLUSTERSTATS(x) ((cherokee_handler_clusterstats_props_t *)(x)) +#define HDL_CLUSTERSTATS_PROPS(x) (PROP_CLUSTERSTATS(MODULE(x)->props)) + + +/* Library init function + */ +void PLUGIN_INIT_NAME(avahi) (cherokee_plugin_loader_t *loader); +ret_t cherokee_handler_clusterstats_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props); + +/* virtual methods implementation + */ +ret_t cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t *hdl); +ret_t cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t *hdl); +ret_t cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer); +ret_t cherokee_handler_clusterstats_add_headers (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer); + +static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata); +static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata); +static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata); + +#endif /* CHEROKEE_HANDLER_CLUSTERSTATS_H */ -- 2.11.4.GIT