update
[handlervirt.git] / handler_clusterstats.c
blobb49638fc0e86d861d020b2d4f9923d6b99da02bc
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Cherokee
5 * Authors:
6 * Alvaro Lopez Ortega <alvaro@alobbs.com>
7 * Stefan de Konink <stefan@konink.de>
9 * Copyright (C) 2001-2008 Alvaro Lopez Ortega
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
26 #include "handler_clusterstats.h"
27 #include <cherokee/cherokee.h>
29 #include <avahi-client/client.h>
30 #include <avahi-client/lookup.h>
32 #include <avahi-common/malloc.h>
33 #include <avahi-common/error.h>
35 /* Plug-in initialization
37 * In this function you can use any of these:
38 * http_delete | http_get | http_post | http_put
40 * For a full list: cherokee_http_method_t
42 * It is what your handler to be implements.
45 PLUGIN_INFO_HANDLER_EASIEST_INIT (clusterstats, http_get);
48 /* Methods implementation
51 static ret_t
52 props_free (cherokee_handler_clusterstats_props_t *props)
54 if (props->threaded_poll)
55 avahi_threaded_poll_stop(props->threaded_poll);
57 if (props->sb)
58 avahi_service_browser_free(props->sb);
60 if (props->client)
61 avahi_client_free(props->client);
63 if (props->threaded_poll)
64 avahi_threaded_poll_free(props->threaded_poll);
66 cherokee_buffer_mrproper(&props->service_type);
68 cherokee_avl_mrproper (&props->entries, (cherokee_func_free_t) cherokee_buffer_mrproper);
69 // cherokee_avl_mrproper (&props->entries, NULL);
71 return cherokee_module_props_free_base (MODULE_PROPS(props));
75 ret_t
76 cherokee_handler_clusterstats_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
78 cherokee_list_t *i;
79 cherokee_handler_clusterstats_props_t *props;
80 int error;
82 if (*_props == NULL) {
83 CHEROKEE_NEW_STRUCT (n, handler_clusterstats_props);
85 cherokee_module_props_init_base (MODULE_PROPS(n),
86 MODULE_PROPS_FREE(props_free));
88 /* Look at handler_clusterstats.h
89 * This is an avahi of configuration.
91 cherokee_buffer_init (&n->service_type);
93 *_props = MODULE_PROPS(n);
96 props = PROP_CLUSTERSTATS(*_props);
98 cherokee_config_node_foreach (i, conf) {
99 cherokee_config_node_t *subconf = CONFIG_NODE(i);
101 if (equal_buf_str (&subconf->key, "service_type")) {
102 cherokee_buffer_add_buffer (&props->service_type, &subconf->val);
104 /* else {
105 PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", subconf->key.buf);
106 return ret_error;
110 /* If the configuration for avahi was not set, we should not continue */
111 if (props->service_type.len == 0) {
112 return ret_error;
115 props->client = NULL;
116 props->sb = NULL;
117 props->threaded_poll = NULL;
119 cherokee_avl_init(&props->entries);
121 if (!(props->threaded_poll = avahi_threaded_poll_new())) {
122 return ret_error;
125 if (!(props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), 0, client_callback, props, &error))) {
126 return ret_error;
129 /* create some browsers on the client object here, if you wish */
130 if (!(props->sb = avahi_service_browser_new(props->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, props->service_type.buf, NULL, 0, browse_callback, props))) {
131 TRACE ("avahi", "Failed to create service browser: %s (%s)\n", avahi_strerror(avahi_client_errno(props->client)), props->service_type.buf);
132 return ret_error;
135 /* Finally, start the event loop thread */
136 if (avahi_threaded_poll_start(props->threaded_poll) < 0) {
137 return ret_error;
141 return ret_ok;
144 ret_t
145 cherokee_handler_clusterstats_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
147 ret_t ret;
149 CHEROKEE_NEW_STRUCT (n, handler_clusterstats);
151 /* Init the base class object
153 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(clusterstats));
155 MODULE(n)->init = (handler_func_init_t) cherokee_handler_clusterstats_init;
156 MODULE(n)->free = (module_func_free_t) cherokee_handler_clusterstats_free;
157 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_clusterstats_step;
158 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_clusterstats_add_headers;
160 HANDLER(n)->support = hsupport_length | hsupport_range;
162 /* Init
164 ret = cherokee_buffer_init (&n->buffer);
165 if (unlikely(ret != ret_ok))
166 return ret;
168 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
169 if (unlikely(ret != ret_ok))
170 return ret;
172 *hdl = HANDLER(n);
174 return ret_ok;
178 ret_t
179 cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t *hdl)
181 cherokee_buffer_mrproper (&hdl->buffer);
183 return ret_ok;
186 static ret_t
187 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
188 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
189 AvahiStringList *list = (AvahiStringList *)value;
190 char *avahi_key, *avahi_value;
191 unsigned int len;
193 cherokee_buffer_add_str (buf, " <domain>\n");
194 cherokee_buffer_add_va (buf, " <name>%s</name>\n", key->buf);
196 if ((len = avahi_string_list_length (list)) > 0) {
197 unsigned int i;
198 cherokee_buffer_add_str (buf, " <properties>\n");
200 for (i = 0; i < len; i++) {
201 avahi_string_list_get_pair (list, &avahi_key, &avahi_value, NULL);
202 cherokee_buffer_add_va (buf, " <property name=\"%s\">%s</property>\n", avahi_key, avahi_value);
203 avahi_free(avahi_key);
204 avahi_free(avahi_value);
205 list = avahi_string_list_get_next(list);
208 cherokee_buffer_add_str (buf, " </properties>\n");
209 } else {
210 cherokee_buffer_add_str (buf, " <properties/>\n");
213 cherokee_buffer_add_str (buf, " </domain>\n");
215 return ret_ok;
218 static void
219 clusterstats_build_page (cherokee_handler_clusterstats_t *hdl)
221 ret_t ret;
222 cherokee_buffer_t *buf;
223 size_t len;
225 /* Init
227 buf = &hdl->buffer;
229 /* Useful output
232 /* First, block the event loop */
233 avahi_threaded_poll_lock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
235 /* Than, do your stuff */
236 if (cherokee_avl_len(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &len) == ret_ok && len > 0) {
237 cherokee_buffer_add_str (buf, "<domains>\n");
238 cherokee_avl_while (&HDL_CLUSTERSTATS_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL);
239 cherokee_buffer_add_str (buf, "</domains>");
240 } else {
241 cherokee_buffer_add_str (buf, "<domains/>");
244 /* Finally, unblock the event loop */
245 avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
248 ret_t
249 cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t *hdl)
251 ret_t ret;
252 void *param;
253 cint_t web_interface = 1;
255 /* Build the page
257 if (web_interface) {
258 clusterstats_build_page (hdl);
261 hdl->action = send_page;
263 return ret_ok;
267 ret_t
268 cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
270 if (cherokee_buffer_is_empty (&hdl->buffer))
271 return ret_eof;
273 cherokee_buffer_add (buffer, hdl->buffer.buf, 1024);
274 cherokee_buffer_move_to_begin (&hdl->buffer, 1024);
276 if (cherokee_buffer_is_empty (&hdl->buffer))
277 return ret_eof_have_data;
279 return ret_ok;
281 // cherokee_buffer_add_buffer (buffer, &hdl->buffer);
282 // return ret_eof_have_data;
286 ret_t
287 cherokee_handler_clusterstats_add_headers (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
289 if (hdl->buffer.len == 0) {
290 cherokee_connection_t *conn = HANDLER_CONN(hdl);
291 conn->error_code = http_not_found;
294 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
296 switch (hdl->action) {
297 case send_page:
298 default:
299 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
300 break;
303 return ret_ok;
307 /* Avahi example stuff */
309 static void resolve_callback(
310 AvahiServiceResolver *r,
311 AVAHI_GCC_UNUSED AvahiIfIndex interface,
312 AVAHI_GCC_UNUSED AvahiProtocol protocol,
313 AvahiResolverEvent event,
314 const char *name,
315 const char *type,
316 const char *domain,
317 const char *host_name,
318 const AvahiAddress *address,
319 uint16_t port,
320 AvahiStringList *txt,
321 AvahiLookupResultFlags flags,
322 void* userdata) {
323 assert(r);
325 /* Called whenever a service has been resolved successfully or timed out */
327 switch (event) {
328 case AVAHI_RESOLVER_FAILURE:
329 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))));
330 avahi_service_resolver_free(r);
331 break;
333 case AVAHI_RESOLVER_FOUND: {
334 char a[AVAHI_ADDRESS_STR_MAX], *t;
335 void **val;
336 AvahiStringList *nonvol = avahi_string_list_copy(txt);
338 avahi_address_snprint(a, sizeof(a), address);
341 cherokee_buffer_t buf;
342 cherokee_buffer_init(&buf);
343 cherokee_buffer_add(&buf, name, strlen(name));
345 if (cherokee_avl_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, val) == ret_ok) {
346 avahi_string_list_free((AvahiStringList*) *val);
349 nonvol = avahi_string_list_add_pair(nonvol, "dom0", host_name);
351 cherokee_avl_add(&PROP_CLUSTERSTATS(userdata)->entries, &buf, (void* ) nonvol);
352 cherokee_buffer_mrproper(&buf);
354 // cherokee_avl_add_ptr (&PROP_CLUSTERSTATS(userdata)->entries, name, (void *) host_name);
356 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
358 t = avahi_string_list_to_string(txt);
360 TRACE("avahi",
361 "\t%s:%u (%s)\n"
362 "\tTXT=%s\n"
363 "\tcookie is %u\n"
364 "\tis_local: %i\n"
365 "\tour_own: %i\n"
366 "\twide_area: %i\n"
367 "\tmulticast: %i\n"
368 "\tcached: %i\n",
369 host_name, port, a,
371 avahi_string_list_get_service_cookie(txt),
372 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
373 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
374 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
375 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
376 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
378 avahi_free(t);
383 static void browse_callback(
384 AvahiServiceBrowser *b,
385 AvahiIfIndex interface,
386 AvahiProtocol protocol,
387 AvahiBrowserEvent event,
388 const char *name,
389 const char *type,
390 const char *domain,
391 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
392 void* userdata) {
394 AvahiClient *c = PROP_CLUSTERSTATS(userdata)->client;
395 assert(b);
397 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
399 switch (event) {
400 case AVAHI_BROWSER_FAILURE:
401 TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
402 avahi_threaded_poll_stop(PROP_CLUSTERSTATS(userdata)->threaded_poll);
403 return;
405 case AVAHI_BROWSER_NEW:
406 TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
408 /* We ignore the returned resolver object. In the callback
409 function we free it. If the server is terminated before
410 the callback function is called the server will free
411 the resolver for us. */
413 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
414 TRACE("avahi", "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
416 break;
418 case AVAHI_BROWSER_REMOVE: {
419 void **val;
420 cherokee_buffer_t buf;
421 cherokee_buffer_init(&buf);
422 cherokee_buffer_add(&buf, name, strlen(name));
423 if (cherokee_avl_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, val) == ret_ok) {
424 avahi_string_list_free((AvahiStringList*) *val);
426 cherokee_buffer_mrproper(&buf);
428 // cherokee_avl_del_ptr(&PROP_CLUSTERSTATS(userdata)->entries, name, val);
430 TRACE("avahi", "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
431 break;
434 case AVAHI_BROWSER_ALL_FOR_NOW:
435 case AVAHI_BROWSER_CACHE_EXHAUSTED:
436 TRACE("avahi", "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
437 break;
441 static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
442 assert(c);
444 /* Called whenever the client or server state changes */
446 if (state == AVAHI_CLIENT_FAILURE) {
447 TRACE("avahi", "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
448 avahi_threaded_poll_stop(PROP_CLUSTERSTATS(userdata)->threaded_poll);
452 ret_t
453 cherokee_handler_clusterstats_props_init_base (cherokee_handler_clusterstats_props_t *props, module_func_props_free_t free_func)
455 cherokee_buffer_init (&props->service_type);
457 return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func);