1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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
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
52 props_free (cherokee_handler_clusterstats_props_t
*props
)
54 if (props
->threaded_poll
)
55 avahi_threaded_poll_stop(props
->threaded_poll
);
58 avahi_service_browser_free(props
->sb
);
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
));
75 cherokee_handler_clusterstats_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
78 cherokee_handler_clusterstats_props_t
*props
;
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
);
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) {
116 if (!(props
->threaded_poll
= avahi_threaded_poll_new())) {
120 if (!(props
->client
= avahi_client_new(avahi_threaded_poll_get(props
->threaded_poll
), 0, client_callback
, props
, &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
);
130 /* Finally, start the event loop thread */
131 if (avahi_threaded_poll_start(props
->threaded_poll
) < 0) {
140 cherokee_handler_clusterstats_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
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
;
159 ret
= cherokee_buffer_init (&n
->buffer
);
160 if (unlikely(ret
!= ret_ok
))
163 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
164 if (unlikely(ret
!= ret_ok
))
174 cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t
*hdl
)
176 cherokee_buffer_mrproper (&hdl
->buffer
);
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
;
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) {
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");
205 cherokee_buffer_add_str (buf
, " <properties/>\n");
208 cherokee_buffer_add_str (buf
, " </domain>\n");
214 clusterstats_build_page (cherokee_handler_clusterstats_t
*hdl
)
216 cherokee_buffer_t
*buf
;
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>");
235 cherokee_buffer_add_str (buf
, "<domains/>");
238 /* Finally, unblock the event loop */
239 avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl
)->threaded_poll
);
243 cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t
*hdl
)
245 cint_t web_interface
= 1;
250 clusterstats_build_page (hdl
);
253 hdl
->action
= send_page
;
260 cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t
*hdl
, cherokee_buffer_t
*buffer
)
264 if (cherokee_buffer_is_empty (&hdl
->buffer
))
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
;
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
) {
292 cherokee_buffer_add_str (buffer
, "Content-Type: application/xml"CRLF
);
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
,
310 const char *host_name
,
311 const AvahiAddress
*address
,
313 AvahiStringList
*txt
,
314 AvahiLookupResultFlags flags
,
318 /* Called whenever a service has been resolved successfully or timed out */
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
);
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
);
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
));
375 static void browse_callback(
376 AvahiServiceBrowser
*b
,
377 AvahiIfIndex interface
,
378 AvahiProtocol protocol
,
379 AvahiBrowserEvent event
,
383 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
386 AvahiClient
*c
= PROP_CLUSTERSTATS(userdata
)->client
;
389 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
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
);
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
)));
410 case AVAHI_BROWSER_REMOVE
: {
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
);
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");
432 static void client_callback(AvahiClient
*c
, AvahiClientState state
, void * userdata
) {
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
);
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
);