Remove annoying update message
[handlervirt.git] / handler_avahi.c
blob26ea03a1363f0b8659e6250123725a31352521cd
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 props->client = NULL;
111 props->sb = NULL;
112 props->threaded_poll = NULL;
114 cherokee_avl_init(&props->entries);
116 if (!(props->threaded_poll = avahi_threaded_poll_new())) {
117 return ret_error;
120 if (!(props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), 0, client_callback, props, &error))) {
121 return ret_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);
127 return ret_error;
130 /* Finally, start the event loop thread */
131 if (avahi_threaded_poll_start(props->threaded_poll) < 0) {
132 return ret_error;
136 return ret_ok;
139 ret_t
140 cherokee_handler_avahi_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
142 ret_t ret;
144 CHEROKEE_NEW_STRUCT (n, handler_avahi);
146 /* Init the base class object
148 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(avahi));
150 MODULE(n)->init = (handler_func_init_t) cherokee_handler_avahi_init;
151 MODULE(n)->free = (module_func_free_t) cherokee_handler_avahi_free;
152 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_avahi_step;
153 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_avahi_add_headers;
155 HANDLER(n)->support = hsupport_length | hsupport_range;
157 /* Init
159 ret = cherokee_buffer_init (&n->buffer);
160 if (unlikely(ret != ret_ok))
161 return ret;
163 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
164 if (unlikely(ret != ret_ok))
165 return ret;
167 *hdl = HANDLER(n);
169 return ret_ok;
173 ret_t
174 cherokee_handler_avahi_free (cherokee_handler_avahi_t *hdl)
176 cherokee_buffer_mrproper (&hdl->buffer);
178 return ret_ok;
181 static ret_t
182 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
183 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
184 cherokee_buffer_t *buf2 = (cherokee_buffer_t *)value;
186 cherokee_buffer_add_buffer (buf, key);
187 cherokee_buffer_add_str (buf, " - ");
188 cherokee_buffer_add_buffer (buf, buf2);
189 // cherokee_buffer_add (buf, value, strlen(value));
190 cherokee_buffer_add_str (buf, "\n");
192 return ret_ok;
195 static void
196 avahi_build_page (cherokee_handler_avahi_t *hdl)
198 ret_t ret;
199 cherokee_buffer_t *buf;
201 /* Init
203 buf = &hdl->buffer;
205 /* Useful output
208 /* First, block the event loop */
209 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
211 /* Than, do your stuff */
212 cherokee_avl_while (&HDL_AVAHI_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL);
214 /* Finally, unblock the event loop */
215 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
218 ret_t
219 cherokee_handler_avahi_init (cherokee_handler_avahi_t *hdl)
221 ret_t ret;
222 void *param;
223 cint_t web_interface = 1;
225 /* Build the page
227 if (web_interface) {
228 avahi_build_page (hdl);
231 hdl->action = send_page;
233 return ret_ok;
237 ret_t
238 cherokee_handler_avahi_step (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
240 cherokee_buffer_add_buffer (buffer, &hdl->buffer);
241 return ret_eof_have_data;
245 ret_t
246 cherokee_handler_avahi_add_headers (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
248 if (hdl->buffer.len == 0) {
249 cherokee_connection_t *conn = HANDLER_CONN(hdl);
250 conn->error_code = http_not_found;
253 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
255 switch (hdl->action) {
256 case send_page:
257 default:
258 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
259 break;
262 return ret_ok;
266 /* Avahi example stuff */
268 static void resolve_callback(
269 AvahiServiceResolver *r,
270 AVAHI_GCC_UNUSED AvahiIfIndex interface,
271 AVAHI_GCC_UNUSED AvahiProtocol protocol,
272 AvahiResolverEvent event,
273 const char *name,
274 const char *type,
275 const char *domain,
276 const char *host_name,
277 const AvahiAddress *address,
278 uint16_t port,
279 AvahiStringList *txt,
280 AvahiLookupResultFlags flags,
281 void* userdata) {
282 assert(r);
284 /* Called whenever a service has been resolved successfully or timed out */
286 switch (event) {
287 case AVAHI_RESOLVER_FAILURE:
288 fprintf(stderr, "(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))));
289 break;
291 case AVAHI_RESOLVER_FOUND: {
292 char a[AVAHI_ADDRESS_STR_MAX], *t;
294 avahi_address_snprint(a, sizeof(a), address);
296 cherokee_buffer_t buf;
297 cherokee_buffer_t buf2;
298 cherokee_buffer_t *buf2a;
299 cherokee_buffer_init(&buf);
300 cherokee_buffer_init(&buf2);
301 cherokee_buffer_add(&buf, name, strlen(name));
302 // cherokee_buffer_add(&buf2, a, strlen(a));
303 cherokee_buffer_add (&buf2, host_name, strlen(host_name));
304 cherokee_buffer_dup(&buf2, &buf2a);
305 cherokee_avl_add(&PROP_AVAHI(userdata)->entries, &buf, buf2a);
306 cherokee_buffer_mrproper(&buf);
307 cherokee_buffer_mrproper(&buf2);
309 // cherokee_avl_add_ptr (&PROP_AVAHI(userdata)->entries, name, (void *) host_name);
311 fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
313 t = avahi_string_list_to_string(txt);
314 fprintf(stderr,
315 "\t%s:%u (%s)\n"
316 "\tTXT=%s\n"
317 "\tcookie is %u\n"
318 "\tis_local: %i\n"
319 "\tour_own: %i\n"
320 "\twide_area: %i\n"
321 "\tmulticast: %i\n"
322 "\tcached: %i\n",
323 host_name, port, a,
325 avahi_string_list_get_service_cookie(txt),
326 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
327 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
328 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
329 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
330 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
332 avahi_free(t);
336 avahi_service_resolver_free(r);
339 static void browse_callback(
340 AvahiServiceBrowser *b,
341 AvahiIfIndex interface,
342 AvahiProtocol protocol,
343 AvahiBrowserEvent event,
344 const char *name,
345 const char *type,
346 const char *domain,
347 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
348 void* userdata) {
350 AvahiClient *c = PROP_AVAHI(userdata)->client;
351 assert(b);
353 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
355 switch (event) {
356 case AVAHI_BROWSER_FAILURE:
357 fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
358 avahi_threaded_poll_stop(PROP_AVAHI(userdata)->threaded_poll);
359 return;
361 case AVAHI_BROWSER_NEW:
362 fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
364 /* We ignore the returned resolver object. In the callback
365 function we free it. If the server is terminated before
366 the callback function is called the server will free
367 the resolver for us. */
369 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
370 fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
372 break;
374 case AVAHI_BROWSER_REMOVE: {
375 void **val;
376 cherokee_buffer_t buf;
377 cherokee_buffer_init(&buf);
378 cherokee_buffer_add(&buf, name, strlen(name));
379 if (cherokee_avl_del(&PROP_AVAHI(userdata)->entries, &buf, val) == ret_ok) {
380 cherokee_buffer_mrproper((cherokee_buffer_t *) *val);
382 cherokee_buffer_mrproper(&buf);
384 // cherokee_avl_del_ptr(&PROP_AVAHI(userdata)->entries, name, val);
386 fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
387 break;
390 case AVAHI_BROWSER_ALL_FOR_NOW:
391 case AVAHI_BROWSER_CACHE_EXHAUSTED:
392 fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
393 break;
397 static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
398 assert(c);
400 /* Called whenever the client or server state changes */
402 if (state == AVAHI_CLIENT_FAILURE) {
403 fprintf(stderr, "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
404 avahi_threaded_poll_stop(PROP_AVAHI(userdata)->threaded_poll);
408 ret_t
409 cherokee_handler_avahi_props_init_base (cherokee_handler_avahi_props_t *props, module_func_props_free_t free_func)
411 cherokee_buffer_init (&props->service_type);
413 return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func);