Avahi robustness updates
[handlervirt.git] / handler_clusterstats.c
blob6c727a9f3c7b5b65154381d90f8e64ac4280b8ee
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_r_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;
80 if (*_props == NULL) {
81 CHEROKEE_NEW_STRUCT (n, handler_clusterstats_props);
83 cherokee_module_props_init_base (MODULE_PROPS(n),
84 MODULE_PROPS_FREE(props_free));
86 /* Look at handler_clusterstats.h
87 * This is an avahi of configuration.
89 cherokee_buffer_init (&n->service_type);
91 cherokee_avl_r_init(&n->entries);
93 n->client = NULL;
94 n->sb = NULL;
95 n->threaded_poll = NULL;
97 *_props = MODULE_PROPS(n);
100 props = PROP_CLUSTERSTATS(*_props);
102 cherokee_config_node_foreach (i, conf) {
103 cherokee_config_node_t *subconf = CONFIG_NODE(i);
105 if (equal_buf_str (&subconf->key, "service_type")) {
106 cherokee_buffer_add_buffer (&props->service_type, &subconf->val);
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 if (!(props->threaded_poll = avahi_threaded_poll_new())) {
116 return ret_error;
119 client_callback(NULL, AVAHI_CLIENT_FAILURE, props);
121 /* Finally, start the event loop thread */
122 if (avahi_threaded_poll_start(props->threaded_poll) < 0) {
123 return ret_error;
127 return ret_ok;
130 ret_t
131 cherokee_handler_clusterstats_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
133 ret_t ret;
135 CHEROKEE_NEW_STRUCT (n, handler_clusterstats);
137 /* Init the base class object
139 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(clusterstats));
141 MODULE(n)->init = (handler_func_init_t) cherokee_handler_clusterstats_init;
142 MODULE(n)->free = (module_func_free_t) cherokee_handler_clusterstats_free;
143 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_clusterstats_step;
144 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_clusterstats_add_headers;
146 HANDLER(n)->support = hsupport_length | hsupport_range;
148 /* Init
150 ret = cherokee_buffer_init (&n->buffer);
151 if (unlikely(ret != ret_ok))
152 return ret;
154 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
155 if (unlikely(ret != ret_ok))
156 return ret;
158 *hdl = HANDLER(n);
160 return ret_ok;
164 ret_t
165 cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t *hdl)
167 cherokee_buffer_mrproper (&hdl->buffer);
169 return ret_ok;
172 static ret_t
173 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
174 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
175 AvahiStringList *list = (AvahiStringList *)value;
176 char *avahi_key, *avahi_value;
177 unsigned int len;
179 cherokee_buffer_add_str (buf, " <domain>\n");
180 cherokee_buffer_add_va (buf, " <name>%s</name>\n", key->buf);
182 if ((len = avahi_string_list_length (list)) > 0) {
183 unsigned int i;
184 cherokee_buffer_add_str (buf, " <properties>\n");
186 for (i = 0; i < len; i++) {
187 avahi_string_list_get_pair (list, &avahi_key, &avahi_value, NULL);
188 cherokee_buffer_add_va (buf, " <property name=\"%s\">%s</property>\n", avahi_key, avahi_value);
189 avahi_free(avahi_key);
190 avahi_free(avahi_value);
191 list = avahi_string_list_get_next(list);
194 cherokee_buffer_add_str (buf, " </properties>\n");
195 } else {
196 cherokee_buffer_add_str (buf, " <properties/>\n");
199 cherokee_buffer_add_str (buf, " </domain>\n");
201 return ret_ok;
204 static void
205 clusterstats_build_page (cherokee_handler_clusterstats_t *hdl)
207 cherokee_buffer_t *buf;
208 size_t len;
210 /* Init
212 buf = &hdl->buffer;
214 /* Useful output
217 /* First, block the event loop */
218 // avahi_threaded_poll_lock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
220 /* Than, do your stuff */
221 if (cherokee_avl_r_len(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &len) == ret_ok && len > 0) {
222 cherokee_buffer_add_str (buf, "<domains>\n");
223 cherokee_avl_r_while (&HDL_CLUSTERSTATS_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL);
224 cherokee_buffer_add_str (buf, "</domains>");
225 } else {
226 cherokee_buffer_add_str (buf, "<domains/>");
229 /* Finally, unblock the event loop */
230 // avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
233 ret_t
234 cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t *hdl)
236 cint_t web_interface = 1;
238 /* Build the page
240 if (web_interface) {
241 clusterstats_build_page (hdl);
244 hdl->action = send_page;
246 return ret_ok;
250 ret_t
251 cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
253 cuint_t tosend;
255 if (cherokee_buffer_is_empty (&hdl->buffer))
256 return ret_eof;
258 tosend = (hdl->buffer.len > 1024 ? 1024 : hdl->buffer.len);
260 cherokee_buffer_add (buffer, hdl->buffer.buf, tosend);
261 cherokee_buffer_move_to_begin (&hdl->buffer, tosend);
263 if (cherokee_buffer_is_empty (&hdl->buffer))
264 return ret_eof_have_data;
266 return ret_ok;
270 ret_t
271 cherokee_handler_clusterstats_add_headers (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
273 if (hdl->buffer.len == 0) {
274 cherokee_connection_t *conn = HANDLER_CONN(hdl);
275 conn->error_code = http_not_found;
278 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
280 switch (hdl->action) {
281 case send_page:
282 default:
283 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
284 break;
287 return ret_ok;
291 /* Avahi example stuff */
293 static void resolve_callback(
294 AvahiServiceResolver *r,
295 AVAHI_GCC_UNUSED AvahiIfIndex interface,
296 AVAHI_GCC_UNUSED AvahiProtocol protocol,
297 AvahiResolverEvent event,
298 const char *name,
299 const char *type,
300 const char *domain,
301 const char *host_name,
302 const AvahiAddress *address,
303 uint16_t port,
304 AvahiStringList *txt,
305 AvahiLookupResultFlags flags,
306 void* userdata) {
307 assert(r);
309 /* Called whenever a service has been resolved successfully or timed out */
311 switch (event) {
312 case AVAHI_RESOLVER_FAILURE:
313 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))));
314 avahi_service_resolver_free(r);
315 break;
317 case AVAHI_RESOLVER_FOUND: {
318 char a[AVAHI_ADDRESS_STR_MAX];
319 AvahiStringList *val;
320 AvahiStringList *nonvol = avahi_string_list_copy(txt);
322 avahi_address_snprint(a, sizeof(a), address);
325 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
326 cherokee_buffer_add(&buf, name, strlen(name));
328 if (cherokee_avl_r_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, (void *) &val) == ret_ok) {
329 avahi_string_list_free(val);
332 nonvol = avahi_string_list_add_pair(nonvol, "dom0", host_name);
334 cherokee_avl_r_add(&PROP_CLUSTERSTATS(userdata)->entries, &buf, (void* ) nonvol);
335 cherokee_buffer_mrproper(&buf);
337 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
342 static void browse_callback(
343 AvahiServiceBrowser *b,
344 AvahiIfIndex interface,
345 AvahiProtocol protocol,
346 AvahiBrowserEvent event,
347 const char *name,
348 const char *type,
349 const char *domain,
350 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
351 void* userdata) {
353 assert(b);
355 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
357 switch (event) {
358 case AVAHI_BROWSER_FAILURE:
359 TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
360 avahi_service_browser_free(b);
361 // avahi_threaded_poll_stop(PROP_CLUSTERSTATS(userdata)->threaded_poll);
362 return;
364 case AVAHI_BROWSER_NEW:
365 TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
367 /* We ignore the returned resolver object. In the callback
368 function we free it. If the server is terminated before
369 the callback function is called the server will free
370 the resolver for us. */
372 if (!(avahi_service_resolver_new(avahi_service_browser_get_client(b), interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
373 TRACE("avahi", "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
375 break;
377 case AVAHI_BROWSER_REMOVE: {
378 void *val;
379 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
380 cherokee_buffer_add(&buf, name, strlen(name));
381 if (cherokee_avl_r_del(&PROP_CLUSTERSTATS(userdata)->entries, &buf, &val) == ret_ok) {
382 avahi_string_list_free((AvahiStringList*) val);
384 cherokee_buffer_mrproper(&buf);
386 // cherokee_avl_r_del_ptr(&PROP_CLUSTERSTATS(userdata)->entries, name, val);
388 TRACE("avahi", "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
389 break;
391 case AVAHI_BROWSER_ALL_FOR_NOW:
392 case AVAHI_BROWSER_CACHE_EXHAUSTED:
393 TRACE("avahi", "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
394 break;
399 static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
400 assert(c);
402 cherokee_handler_clusterstats_props_t *props = userdata;
404 /* Called whenever the client or server state changes */
405 switch (state) {
406 case AVAHI_CLIENT_S_RUNNING: {
407 if (!(props->sb = avahi_service_browser_new(props->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, props->service_type.buf, NULL, 0, browse_callback, props))) {
408 TRACE ("avahi", "Failed to create service browser: %s (%s)\n", avahi_strerror(avahi_client_errno(props->client)), props->service_type.buf);
410 break;
413 case AVAHI_CLIENT_FAILURE: {
414 int error;
415 if (c)
416 avahi_client_free(c);
418 props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), AVAHI_CLIENT_NO_FAIL, client_callback, props, &error);
419 break;
422 default:
423 break;
427 ret_t
428 cherokee_handler_clusterstats_props_init_base (cherokee_handler_clusterstats_props_t *props, module_func_props_free_t free_func)
430 cherokee_buffer_init (&props->service_type);
432 return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func);