Intermediate update... consider this version completely broken
[handlervirt.git] / handler_clusterstats.c
blob351a281a052b70e5b17da9aeabbad5dd05daf952
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);
70 return cherokee_module_props_free_base (MODULE_PROPS(props));
74 ret_t
75 cherokee_handler_clusterstats_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
77 cherokee_list_t *i;
78 cherokee_handler_clusterstats_props_t *props;
79 int error;
81 if (*_props == NULL) {
82 CHEROKEE_NEW_STRUCT (n, handler_clusterstats_props);
84 cherokee_module_props_init_base (MODULE_PROPS(n),
85 MODULE_PROPS_FREE(props_free));
87 /* Look at handler_clusterstats.h
88 * This is an avahi of configuration.
90 cherokee_buffer_init (&n->service_type);
92 cherokee_avl_init(&n->entries);
94 n->client = NULL;
95 n->sb = NULL;
96 n->threaded_poll = NULL;
98 *_props = MODULE_PROPS(n);
101 props = PROP_CLUSTERSTATS(*_props);
103 cherokee_config_node_foreach (i, conf) {
104 cherokee_config_node_t *subconf = CONFIG_NODE(i);
106 if (equal_buf_str (&subconf->key, "service_type")) {
107 cherokee_buffer_add_buffer (&props->service_type, &subconf->val);
111 /* If the configuration for avahi was not set, we should not continue */
112 if (props->service_type.len == 0) {
113 return ret_error;
116 if (!(props->threaded_poll = avahi_threaded_poll_new())) {
117 return ret_error;
120 if (!(props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), 0, client_callback, props, &error))) {
121 return ret_error;
124 /* create some browsers on the client object here, if you wish */
125 if (!(props->sb = avahi_service_browser_new(props->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, props->service_type.buf, NULL, 0, browse_callback, props))) {
126 TRACE ("avahi", "Failed to create service browser: %s (%s)\n", avahi_strerror(avahi_client_errno(props->client)), props->service_type.buf);
127 return ret_error;
130 /* Finally, start the event loop thread */
131 if (avahi_threaded_poll_start(props->threaded_poll) < 0) {
132 return ret_error;
136 return ret_ok;
139 ret_t
140 cherokee_handler_clusterstats_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
142 ret_t ret;
144 CHEROKEE_NEW_STRUCT (n, handler_clusterstats);
146 /* Init the base class object
148 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(clusterstats));
150 MODULE(n)->init = (handler_func_init_t) cherokee_handler_clusterstats_init;
151 MODULE(n)->free = (module_func_free_t) cherokee_handler_clusterstats_free;
152 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_clusterstats_step;
153 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_clusterstats_add_headers;
155 HANDLER(n)->support = hsupport_length | hsupport_range;
157 /* Init
159 ret = cherokee_buffer_init (&n->buffer);
160 if (unlikely(ret != ret_ok))
161 return ret;
163 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
164 if (unlikely(ret != ret_ok))
165 return ret;
167 *hdl = HANDLER(n);
169 return ret_ok;
173 ret_t
174 cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t *hdl)
176 cherokee_buffer_mrproper (&hdl->buffer);
178 return ret_ok;
181 static ret_t
182 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
183 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
184 AvahiStringList *list = (AvahiStringList *)value;
185 char *avahi_key, *avahi_value;
186 unsigned int len;
188 cherokee_buffer_add_str (buf, " <domain>\n");
189 cherokee_buffer_add_va (buf, " <name>%s</name>\n", key->buf);
191 if ((len = avahi_string_list_length (list)) > 0) {
192 unsigned int i;
193 cherokee_buffer_add_str (buf, " <properties>\n");
195 for (i = 0; i < len; i++) {
196 avahi_string_list_get_pair (list, &avahi_key, &avahi_value, NULL);
197 cherokee_buffer_add_va (buf, " <property name=\"%s\">%s</property>\n", avahi_key, avahi_value);
198 avahi_free(avahi_key);
199 avahi_free(avahi_value);
200 list = avahi_string_list_get_next(list);
203 cherokee_buffer_add_str (buf, " </properties>\n");
204 } else {
205 cherokee_buffer_add_str (buf, " <properties/>\n");
208 cherokee_buffer_add_str (buf, " </domain>\n");
210 return ret_ok;
213 static void
214 clusterstats_build_page (cherokee_handler_clusterstats_t *hdl)
216 cherokee_buffer_t *buf;
217 size_t len;
219 /* Init
221 buf = &hdl->buffer;
223 /* Useful output
226 /* First, block the event loop */
227 avahi_threaded_poll_lock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
229 /* Than, do your stuff */
230 if (cherokee_avl_len(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &len) == ret_ok && len > 0) {
231 cherokee_buffer_add_str (buf, "<domains>\n");
232 cherokee_avl_while (&HDL_CLUSTERSTATS_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL);
233 cherokee_buffer_add_str (buf, "</domains>");
234 } else {
235 cherokee_buffer_add_str (buf, "<domains/>");
238 /* Finally, unblock the event loop */
239 avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
242 ret_t
243 cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t *hdl)
245 cint_t web_interface = 1;
247 /* Build the page
249 if (web_interface) {
250 clusterstats_build_page (hdl);
253 hdl->action = send_page;
255 return ret_ok;
259 ret_t
260 cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
262 cuint_t tosend;
264 if (cherokee_buffer_is_empty (&hdl->buffer))
265 return ret_eof;
267 tosend = (hdl->buffer.len > 1024 ? 1024 : hdl->buffer.len);
269 cherokee_buffer_add (buffer, hdl->buffer.buf, tosend);
270 cherokee_buffer_move_to_begin (&hdl->buffer, tosend);
272 if (cherokee_buffer_is_empty (&hdl->buffer))
273 return ret_eof_have_data;
275 return ret_ok;
279 ret_t
280 cherokee_handler_clusterstats_add_headers (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
282 if (hdl->buffer.len == 0) {
283 cherokee_connection_t *conn = HANDLER_CONN(hdl);
284 conn->error_code = http_not_found;
287 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
289 switch (hdl->action) {
290 case send_page:
291 default:
292 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
293 break;
296 return ret_ok;
300 /* Avahi example stuff */
302 static void resolve_callback(
303 AvahiServiceResolver *r,
304 AVAHI_GCC_UNUSED AvahiIfIndex interface,
305 AVAHI_GCC_UNUSED AvahiProtocol protocol,
306 AvahiResolverEvent event,
307 const char *name,
308 const char *type,
309 const char *domain,
310 const char *host_name,
311 const AvahiAddress *address,
312 uint16_t port,
313 AvahiStringList *txt,
314 AvahiLookupResultFlags flags,
315 void* userdata) {
316 assert(r);
318 /* Called whenever a service has been resolved successfully or timed out */
320 switch (event) {
321 case AVAHI_RESOLVER_FAILURE:
322 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))));
323 avahi_service_resolver_free(r);
324 break;
326 case AVAHI_RESOLVER_FOUND: {
327 char a[AVAHI_ADDRESS_STR_MAX], *t;
328 AvahiStringList *val;
329 AvahiStringList *nonvol = avahi_string_list_copy(txt);
331 avahi_address_snprint(a, sizeof(a), address);
334 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
335 cherokee_buffer_add(&buf, name, strlen(name));
337 if (cherokee_avl_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, (void *) &val) == ret_ok) {
338 avahi_string_list_free(val);
341 nonvol = avahi_string_list_add_pair(nonvol, "dom0", host_name);
343 cherokee_avl_add(&PROP_CLUSTERSTATS(userdata)->entries, &buf, (void* ) nonvol);
344 cherokee_buffer_mrproper(&buf);
346 // cherokee_avl_add_ptr (&PROP_CLUSTERSTATS(userdata)->entries, name, (void *) host_name);
348 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
350 t = avahi_string_list_to_string(txt);
352 TRACE("avahi",
353 "\t%s:%u (%s)\n"
354 "\tTXT=%s\n"
355 "\tcookie is %u\n"
356 "\tis_local: %i\n"
357 "\tour_own: %i\n"
358 "\twide_area: %i\n"
359 "\tmulticast: %i\n"
360 "\tcached: %i\n",
361 host_name, port, a,
363 avahi_string_list_get_service_cookie(txt),
364 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
365 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
366 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
367 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
368 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
370 avahi_free(t);
375 static void browse_callback(
376 AvahiServiceBrowser *b,
377 AvahiIfIndex interface,
378 AvahiProtocol protocol,
379 AvahiBrowserEvent event,
380 const char *name,
381 const char *type,
382 const char *domain,
383 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
384 void* userdata) {
386 AvahiClient *c = PROP_CLUSTERSTATS(userdata)->client;
387 assert(b);
389 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
391 switch (event) {
392 case AVAHI_BROWSER_FAILURE:
393 TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
394 avahi_threaded_poll_stop(PROP_CLUSTERSTATS(userdata)->threaded_poll);
395 return;
397 case AVAHI_BROWSER_NEW:
398 TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
400 /* We ignore the returned resolver object. In the callback
401 function we free it. If the server is terminated before
402 the callback function is called the server will free
403 the resolver for us. */
405 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
406 TRACE("avahi", "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
408 break;
410 case AVAHI_BROWSER_REMOVE: {
411 void **val;
412 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
413 cherokee_buffer_add(&buf, name, strlen(name));
414 if (cherokee_avl_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, val) == ret_ok) {
415 avahi_string_list_free((AvahiStringList*) *val);
417 cherokee_buffer_mrproper(&buf);
419 // cherokee_avl_del_ptr(&PROP_CLUSTERSTATS(userdata)->entries, name, val);
421 TRACE("avahi", "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
422 break;
425 case AVAHI_BROWSER_ALL_FOR_NOW:
426 case AVAHI_BROWSER_CACHE_EXHAUSTED:
427 TRACE("avahi", "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
428 break;
432 static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
433 assert(c);
435 /* Called whenever the client or server state changes */
437 if (state == AVAHI_CLIENT_FAILURE) {
438 TRACE("avahi", "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
439 avahi_threaded_poll_stop(PROP_CLUSTERSTATS(userdata)->threaded_poll);
443 ret_t
444 cherokee_handler_clusterstats_props_init_base (cherokee_handler_clusterstats_props_t *props, module_func_props_free_t free_func)
446 cherokee_buffer_init (&props->service_type);
448 return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func);