Prettify
[handlervirt.git] / handler_clusterstats.c
blobf18dfc26bffebda26481250bc8ab0b85047f4ab4
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 ret_t
52 cherokee_handler_clusterstats_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(cherokee_handler_clusterstats_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);
101 props = PROP_CLUSTERSTATS(*_props);
103 cherokee_avl_r_init(&props->entries);
105 cherokee_config_node_foreach (i, conf) {
106 cherokee_config_node_t *subconf = CONFIG_NODE(i);
108 if (equal_buf_str (&subconf->key, "service_type")) {
109 cherokee_buffer_add_buffer (&props->service_type, &subconf->val);
113 /* If the configuration for avahi was not set, we should not continue */
114 if (props->service_type.len == 0) {
115 return ret_error;
118 if (!(props->threaded_poll = avahi_threaded_poll_new())) {
119 return ret_error;
122 client_callback(NULL, AVAHI_CLIENT_FAILURE, props);
124 /* Finally, start the event loop thread */
125 if (avahi_threaded_poll_start(props->threaded_poll) < 0) {
126 return ret_error;
130 return ret_ok;
133 ret_t
134 cherokee_handler_clusterstats_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
136 ret_t ret;
138 CHEROKEE_NEW_STRUCT (n, handler_clusterstats);
140 /* Init the base class object
142 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(clusterstats));
144 MODULE(n)->init = (handler_func_init_t) cherokee_handler_clusterstats_init;
145 MODULE(n)->free = (module_func_free_t) cherokee_handler_clusterstats_free;
146 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_clusterstats_step;
147 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_clusterstats_add_headers;
149 HANDLER(n)->support = hsupport_length | hsupport_range;
151 /* Init
153 ret = cherokee_buffer_init (&n->buffer);
154 if (unlikely(ret != ret_ok))
155 return ret;
157 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
158 if (unlikely(ret != ret_ok))
159 return ret;
161 *hdl = HANDLER(n);
163 return ret_ok;
167 ret_t
168 cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t *hdl)
170 cherokee_buffer_mrproper (&hdl->buffer);
172 return ret_ok;
175 ret_t
176 cherokee_handler_clusterstats_while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
177 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
178 AvahiStringList *list = (AvahiStringList *)value;
179 char *avahi_key, *avahi_value;
180 unsigned int len;
182 cherokee_buffer_add_str (buf, " <domain status=\"running\">\n");
183 cherokee_buffer_add_va (buf, " <name>%s</name>\n", key->buf);
185 if ((len = avahi_string_list_length (list)) > 0) {
186 unsigned int i;
187 cherokee_buffer_add_str (buf, " <properties>\n");
189 for (i = 0; i < len; i++) {
190 avahi_string_list_get_pair (list, &avahi_key, &avahi_value, NULL);
191 cherokee_buffer_add_va (buf, " <property name=\"%s\">%s</property>\n", avahi_key, avahi_value);
192 avahi_free(avahi_key);
193 avahi_free(avahi_value);
194 list = avahi_string_list_get_next(list);
197 cherokee_buffer_add_str (buf, " </properties>\n");
198 } else {
199 cherokee_buffer_add_str (buf, " <properties/>\n");
202 cherokee_buffer_add_str (buf, " </domain>\n");
204 return ret_ok;
207 static void
208 clusterstats_build_page (cherokee_handler_clusterstats_t *hdl)
210 cherokee_buffer_t *buf;
211 size_t len;
213 /* Init
215 buf = &hdl->buffer;
217 /* Useful output
220 /* First, block the event loop */
221 // avahi_threaded_poll_lock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
223 /* Than, do your stuff */
224 if (cherokee_avl_r_len(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &len) == ret_ok && len > 0) {
225 cherokee_buffer_add_str (buf, "<domains>\n");
226 cherokee_avl_r_while (&HDL_CLUSTERSTATS_PROPS(hdl)->entries, (cherokee_avl_while_func_t) cherokee_handler_clusterstats_while_func_entries, (void *) buf, NULL, NULL);
227 cherokee_buffer_add_str (buf, "</domains>");
228 } else {
229 cherokee_buffer_add_str (buf, "<domains/>");
232 /* Finally, unblock the event loop */
233 // avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
236 ret_t
237 cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t *hdl)
239 cint_t web_interface = 1;
241 /* Build the page
243 if (web_interface) {
244 clusterstats_build_page (hdl);
247 hdl->action = send_page;
249 return ret_ok;
253 ret_t
254 cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
256 cuint_t tosend;
258 if (cherokee_buffer_is_empty (&hdl->buffer))
259 return ret_eof;
261 tosend = (hdl->buffer.len > 1024 ? 1024 : hdl->buffer.len);
263 cherokee_buffer_add (buffer, hdl->buffer.buf, tosend);
264 cherokee_buffer_move_to_begin (&hdl->buffer, tosend);
266 if (cherokee_buffer_is_empty (&hdl->buffer))
267 return ret_eof_have_data;
269 return ret_ok;
273 ret_t
274 cherokee_handler_clusterstats_add_headers (cherokee_handler_clusterstats_t *hdl, cherokee_buffer_t *buffer)
276 if (hdl->buffer.len == 0) {
277 cherokee_connection_t *conn = HANDLER_CONN(hdl);
278 conn->error_code = http_not_found;
281 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
283 switch (hdl->action) {
284 case send_page:
285 default:
286 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
287 break;
290 return ret_ok;
294 /* Avahi example stuff */
296 static void resolve_callback(
297 AvahiServiceResolver *r,
298 AVAHI_GCC_UNUSED AvahiIfIndex interface,
299 AVAHI_GCC_UNUSED AvahiProtocol protocol,
300 AvahiResolverEvent event,
301 const char *name,
302 const char *type,
303 const char *domain,
304 const char *host_name,
305 const AvahiAddress *address,
306 uint16_t port,
307 AvahiStringList *txt,
308 AvahiLookupResultFlags flags,
309 void* userdata) {
310 cherokee_handler_clusterstats_props_t *props = userdata;
311 assert(r);
313 /* Called whenever a service has been resolved successfully or timed out */
315 switch (event) {
316 case AVAHI_RESOLVER_FAILURE:
317 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))));
318 avahi_service_resolver_free(r);
319 break;
321 case AVAHI_RESOLVER_FOUND: {
322 char a[AVAHI_ADDRESS_STR_MAX];
323 AvahiStringList *val;
324 AvahiStringList *nonvol = avahi_string_list_copy(txt);
326 avahi_address_snprint(a, sizeof(a), address);
329 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
330 cherokee_buffer_add(&buf, name, strlen(name));
332 if (cherokee_avl_r_del(&props->entries, &buf, (void *) &val) == ret_ok) {
333 avahi_string_list_free(val);
336 nonvol = avahi_string_list_add_pair(nonvol, "dom0", host_name);
338 cherokee_avl_r_add(&props->entries, &buf, (void* ) nonvol);
339 cherokee_buffer_mrproper(&buf);
341 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
346 static void browse_callback(
347 AvahiServiceBrowser *b,
348 AvahiIfIndex interface,
349 AvahiProtocol protocol,
350 AvahiBrowserEvent event,
351 const char *name,
352 const char *type,
353 const char *domain,
354 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
355 void* userdata) {
356 cherokee_handler_clusterstats_props_t *props = userdata;
357 assert(b);
359 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
361 switch (event) {
362 case AVAHI_BROWSER_FAILURE:
363 TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
364 avahi_service_browser_free(b);
365 return;
367 case AVAHI_BROWSER_NEW:
368 TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
370 /* We ignore the returned resolver object. In the callback
371 function we free it. If the server is terminated before
372 the callback function is called the server will free
373 the resolver for us. */
375 if (!(avahi_service_resolver_new(avahi_service_browser_get_client(b), interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
376 TRACE("avahi", "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
378 break;
380 case AVAHI_BROWSER_REMOVE: {
381 void *val;
382 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
383 cherokee_buffer_add(&buf, name, strlen(name));
384 if (cherokee_avl_r_del(&props->entries, &buf, &val) == ret_ok) {
385 avahi_string_list_free((AvahiStringList*) val);
387 cherokee_buffer_mrproper(&buf);
389 // cherokee_avl_r_del_ptr(&PROP_CLUSTERSTATS(userdata)->entries, name, val);
391 TRACE("avahi", "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
392 break;
394 case AVAHI_BROWSER_ALL_FOR_NOW:
395 case AVAHI_BROWSER_CACHE_EXHAUSTED:
396 TRACE("avahi", "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
397 break;
401 static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
402 cherokee_handler_clusterstats_props_t *props = userdata;
404 /* Called whenever the client or server state changes */
406 switch (state) {
407 case AVAHI_CLIENT_S_RUNNING: {
408 if (!(props->sb = avahi_service_browser_new(c, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, props->service_type.buf, NULL, 0, browse_callback, props))) {
409 TRACE ("avahi", "Failed to create service browser: %s (%s)\n", avahi_strerror(avahi_client_errno(c)), props->service_type.buf);
411 break;
414 case AVAHI_CLIENT_FAILURE: {
415 int error;
416 if (c)
417 avahi_client_free(c);
419 props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), AVAHI_CLIENT_NO_FAIL, client_callback, props, &error);
420 break;
423 default:
424 break;
428 ret_t
429 cherokee_handler_clusterstats_props_init_base (cherokee_handler_clusterstats_props_t *props, module_func_props_free_t free_func)
431 cherokee_buffer_init (&props->service_type);
433 return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func);