Kernelcmdline, end for rrd
[handlervirt.git] / handler_avahi.c
blob0d70930a055b78e6f56da3c968237a6360196dca
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_avahi.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 (avahi, http_get);
48 /* Methods implementation
51 static ret_t
52 props_free (cherokee_handler_avahi_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);
69 // cherokee_avl_mrproper (&props->entries, NULL);
71 return cherokee_module_props_free_base (MODULE_PROPS(props));
75 ret_t
76 cherokee_handler_avahi_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
78 cherokee_list_t *i;
79 cherokee_handler_avahi_props_t *props;
80 int error;
82 if (*_props == NULL) {
83 CHEROKEE_NEW_STRUCT (n, handler_avahi_props);
85 cherokee_module_props_init_base (MODULE_PROPS(n),
86 MODULE_PROPS_FREE(props_free));
88 /* Look at handler_avahi.h
89 * This is an avahi of configuration.
91 cherokee_buffer_init (&n->service_type);
93 *_props = MODULE_PROPS(n);
96 props = PROP_AVAHI(*_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);
104 /* else {
105 PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", subconf->key.buf);
106 return ret_error;
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 props->client = NULL;
116 props->sb = NULL;
117 props->threaded_poll = NULL;
119 cherokee_avl_init(&props->entries);
121 if (!(props->threaded_poll = avahi_threaded_poll_new())) {
122 return ret_error;
125 if (!(props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), 0, client_callback, props, &error))) {
126 return ret_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);
132 return ret_error;
135 /* Finally, start the event loop thread */
136 if (avahi_threaded_poll_start(props->threaded_poll) < 0) {
137 return ret_error;
141 return ret_ok;
144 ret_t
145 cherokee_handler_avahi_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
147 ret_t ret;
149 CHEROKEE_NEW_STRUCT (n, handler_avahi);
151 /* Init the base class object
153 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(avahi));
155 MODULE(n)->init = (handler_func_init_t) cherokee_handler_avahi_init;
156 MODULE(n)->free = (module_func_free_t) cherokee_handler_avahi_free;
157 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_avahi_step;
158 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_avahi_add_headers;
160 HANDLER(n)->support = hsupport_length | hsupport_range;
162 /* Init
164 ret = cherokee_buffer_init (&n->buffer);
165 if (unlikely(ret != ret_ok))
166 return ret;
168 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
169 if (unlikely(ret != ret_ok))
170 return ret;
172 *hdl = HANDLER(n);
174 return ret_ok;
178 ret_t
179 cherokee_handler_avahi_free (cherokee_handler_avahi_t *hdl)
181 cherokee_buffer_mrproper (&hdl->buffer);
183 return ret_ok;
186 static ret_t
187 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
188 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
189 cherokee_buffer_t *buf2 = (cherokee_buffer_t *)value;
191 cherokee_buffer_add_buffer (buf, key);
192 cherokee_buffer_add_str (buf, " - ");
193 cherokee_buffer_add_buffer (buf, buf2);
194 // cherokee_buffer_add (buf, value, strlen(value));
195 cherokee_buffer_add_str (buf, "\n");
197 return ret_ok;
200 static void
201 avahi_build_page (cherokee_handler_avahi_t *hdl)
203 ret_t ret;
204 cherokee_buffer_t *buf;
206 /* Init
208 buf = &hdl->buffer;
210 /* Useful output
213 /* First, block the event loop */
214 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
216 /* Than, do your stuff */
217 cherokee_avl_while (&HDL_AVAHI_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL);
219 /* Finally, unblock the event loop */
220 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
223 ret_t
224 cherokee_handler_avahi_init (cherokee_handler_avahi_t *hdl)
226 ret_t ret;
227 void *param;
228 cint_t web_interface = 1;
230 /* Build the page
232 if (web_interface) {
233 avahi_build_page (hdl);
236 hdl->action = send_page;
238 return ret_ok;
242 ret_t
243 cherokee_handler_avahi_step (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
245 cherokee_buffer_add_buffer (buffer, &hdl->buffer);
246 return ret_eof_have_data;
250 ret_t
251 cherokee_handler_avahi_add_headers (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
253 if (hdl->buffer.len == 0) {
254 cherokee_connection_t *conn = HANDLER_CONN(hdl);
255 conn->error_code = http_not_found;
258 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
260 switch (hdl->action) {
261 case send_page:
262 default:
263 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
264 break;
267 return ret_ok;
271 /* Avahi example stuff */
273 static void resolve_callback(
274 AvahiServiceResolver *r,
275 AVAHI_GCC_UNUSED AvahiIfIndex interface,
276 AVAHI_GCC_UNUSED AvahiProtocol protocol,
277 AvahiResolverEvent event,
278 const char *name,
279 const char *type,
280 const char *domain,
281 const char *host_name,
282 const AvahiAddress *address,
283 uint16_t port,
284 AvahiStringList *txt,
285 AvahiLookupResultFlags flags,
286 void* userdata) {
287 assert(r);
289 /* Called whenever a service has been resolved successfully or timed out */
291 switch (event) {
292 case AVAHI_RESOLVER_FAILURE:
293 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))));
294 break;
296 case AVAHI_RESOLVER_FOUND: {
297 char a[AVAHI_ADDRESS_STR_MAX], *t;
299 avahi_address_snprint(a, sizeof(a), address);
301 cherokee_buffer_t buf;
302 cherokee_buffer_t buf2;
303 cherokee_buffer_t *buf2a;
304 cherokee_buffer_init(&buf);
305 cherokee_buffer_init(&buf2);
306 cherokee_buffer_add(&buf, name, strlen(name));
307 // cherokee_buffer_add(&buf2, a, strlen(a));
308 cherokee_buffer_add (&buf2, host_name, strlen(host_name));
309 cherokee_buffer_dup(&buf2, &buf2a);
310 cherokee_avl_add(&PROP_AVAHI(userdata)->entries, &buf, buf2a);
311 cherokee_buffer_mrproper(&buf);
312 cherokee_buffer_mrproper(&buf2);
314 // cherokee_avl_add_ptr (&PROP_AVAHI(userdata)->entries, name, (void *) host_name);
316 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
318 t = avahi_string_list_to_string(txt);
319 TRACE("avahi",
320 "\t%s:%u (%s)\n"
321 "\tTXT=%s\n"
322 "\tcookie is %u\n"
323 "\tis_local: %i\n"
324 "\tour_own: %i\n"
325 "\twide_area: %i\n"
326 "\tmulticast: %i\n"
327 "\tcached: %i\n",
328 host_name, port, a,
330 avahi_string_list_get_service_cookie(txt),
331 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
332 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
333 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
334 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
335 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
337 avahi_free(t);
341 avahi_service_resolver_free(r);
344 static void browse_callback(
345 AvahiServiceBrowser *b,
346 AvahiIfIndex interface,
347 AvahiProtocol protocol,
348 AvahiBrowserEvent event,
349 const char *name,
350 const char *type,
351 const char *domain,
352 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
353 void* userdata) {
355 AvahiClient *c = PROP_AVAHI(userdata)->client;
356 assert(b);
358 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
360 switch (event) {
361 case AVAHI_BROWSER_FAILURE:
362 TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
363 avahi_threaded_poll_stop(PROP_AVAHI(userdata)->threaded_poll);
364 return;
366 case AVAHI_BROWSER_NEW:
367 TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
369 /* We ignore the returned resolver object. In the callback
370 function we free it. If the server is terminated before
371 the callback function is called the server will free
372 the resolver for us. */
374 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
375 TRACE("avahi", "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
377 break;
379 case AVAHI_BROWSER_REMOVE: {
380 void **val;
381 cherokee_buffer_t buf;
382 cherokee_buffer_init(&buf);
383 cherokee_buffer_add(&buf, name, strlen(name));
384 if (cherokee_avl_del(&PROP_AVAHI(userdata)->entries, &buf, val) == ret_ok) {
385 cherokee_buffer_mrproper((cherokee_buffer_t *) *val);
387 cherokee_buffer_mrproper(&buf);
389 // cherokee_avl_del_ptr(&PROP_AVAHI(userdata)->entries, name, val);
391 TRACE("avahi", "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
392 break;
395 case AVAHI_BROWSER_ALL_FOR_NOW:
396 case AVAHI_BROWSER_CACHE_EXHAUSTED:
397 TRACE("avahi", "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
398 break;
402 static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
403 assert(c);
405 /* Called whenever the client or server state changes */
407 if (state == AVAHI_CLIENT_FAILURE) {
408 TRACE("avahi", "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
409 avahi_threaded_poll_stop(PROP_AVAHI(userdata)->threaded_poll);
413 ret_t
414 cherokee_handler_avahi_props_init_base (cherokee_handler_avahi_props_t *props, module_func_props_free_t free_func)
416 cherokee_buffer_init (&props->service_type);
418 return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func);