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
);
69 // cherokee_avl_mrproper (&props->entries, NULL);
71 return cherokee_module_props_free_base (MODULE_PROPS(props
));
76 cherokee_handler_clusterstats_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
79 cherokee_handler_clusterstats_props_t
*props
;
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
);
105 PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", subconf->key.buf);
110 /* If the configuration for avahi was not set, we should not continue */
111 if (props
->service_type
.len
== 0) {
115 props
->client
= NULL
;
117 props
->threaded_poll
= NULL
;
119 cherokee_avl_init(&props
->entries
);
121 if (!(props
->threaded_poll
= avahi_threaded_poll_new())) {
125 if (!(props
->client
= avahi_client_new(avahi_threaded_poll_get(props
->threaded_poll
), 0, client_callback
, props
, &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
);
135 /* Finally, start the event loop thread */
136 if (avahi_threaded_poll_start(props
->threaded_poll
) < 0) {
145 cherokee_handler_clusterstats_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
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
;
164 ret
= cherokee_buffer_init (&n
->buffer
);
165 if (unlikely(ret
!= ret_ok
))
168 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
169 if (unlikely(ret
!= ret_ok
))
179 cherokee_handler_clusterstats_free (cherokee_handler_clusterstats_t
*hdl
)
181 cherokee_buffer_mrproper (&hdl
->buffer
);
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
;
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) {
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");
210 cherokee_buffer_add_str (buf
, " <properties/>\n");
213 cherokee_buffer_add_str (buf
, " </domain>\n");
219 clusterstats_build_page (cherokee_handler_clusterstats_t
*hdl
)
222 cherokee_buffer_t
*buf
;
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>");
241 cherokee_buffer_add_str (buf
, "<domains/>");
244 /* Finally, unblock the event loop */
245 avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl
)->threaded_poll
);
249 cherokee_handler_clusterstats_init (cherokee_handler_clusterstats_t
*hdl
)
253 cint_t web_interface
= 1;
258 clusterstats_build_page (hdl
);
261 hdl
->action
= send_page
;
268 cherokee_handler_clusterstats_step (cherokee_handler_clusterstats_t
*hdl
, cherokee_buffer_t
*buffer
)
270 if (cherokee_buffer_is_empty (&hdl
->buffer
))
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
;
281 // cherokee_buffer_add_buffer (buffer, &hdl->buffer);
282 // return ret_eof_have_data;
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
) {
299 cherokee_buffer_add_str (buffer
, "Content-Type: application/xml"CRLF
);
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
,
317 const char *host_name
,
318 const AvahiAddress
*address
,
320 AvahiStringList
*txt
,
321 AvahiLookupResultFlags flags
,
325 /* Called whenever a service has been resolved successfully or timed out */
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
);
333 case AVAHI_RESOLVER_FOUND
: {
334 char a
[AVAHI_ADDRESS_STR_MAX
], *t
;
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
);
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
));
383 static void browse_callback(
384 AvahiServiceBrowser
*b
,
385 AvahiIfIndex interface
,
386 AvahiProtocol protocol
,
387 AvahiBrowserEvent event
,
391 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
394 AvahiClient
*c
= PROP_CLUSTERSTATS(userdata
)->client
;
397 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
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
);
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
)));
418 case AVAHI_BROWSER_REMOVE
: {
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
);
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");
441 static void client_callback(AvahiClient
*c
, AvahiClientState state
, void * userdata
) {
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
);
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
);