e7754f3a26497d3195772c2d94e225f9bf7dbb16
[handlervirt.git] / handler_avahi.c
blobe7754f3a26497d3195772c2d94e225f9bf7dbb16
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 ret_t
52 cherokee_handler_avahi_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_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_avahi_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
77 cherokee_list_t *i;
78 cherokee_handler_avahi_props_t *props;
79 int error;
81 if (*_props == NULL) {
82 CHEROKEE_NEW_STRUCT (n, handler_avahi_props);
84 cherokee_module_props_init_base (MODULE_PROPS(n),
85 MODULE_PROPS_FREE(cherokee_handler_avahi_props_free));
87 /* Look at handler_avahi.h
88 * This is an avahi of configuration.
90 cherokee_buffer_init (&n->service_type);
92 *_props = MODULE_PROPS(n);
95 props = PROP_AVAHI(*_props);
97 cherokee_config_node_foreach (i, conf) {
98 cherokee_config_node_t *subconf = CONFIG_NODE(i);
100 if (equal_buf_str (&subconf->key, "service_type")) {
101 cherokee_buffer_add_buffer (&props->service_type, &subconf->val);
105 /* If the configuration for avahi was not set, we should not continue */
106 if (props->service_type.len == 0) {
107 return ret_error;
110 props->client = NULL;
111 props->sb = NULL;
112 props->threaded_poll = NULL;
114 cherokee_avl_r_init(&props->entries);
116 if (!(props->threaded_poll = avahi_threaded_poll_new())) {
117 return ret_error;
120 client_callback(props->client, AVAHI_CLIENT_FAILURE, props); /* create the avahi client in a creative way */
122 /* Finally, start the event loop thread */
123 if (avahi_threaded_poll_start(props->threaded_poll) < 0) {
124 return ret_error;
128 return ret_ok;
131 ret_t
132 cherokee_handler_avahi_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
134 ret_t ret;
136 CHEROKEE_NEW_STRUCT (n, handler_avahi);
138 /* Init the base class object
140 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(avahi));
142 MODULE(n)->init = (handler_func_init_t) cherokee_handler_avahi_init;
143 MODULE(n)->free = (module_func_free_t) cherokee_handler_avahi_free;
144 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_avahi_step;
145 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_avahi_add_headers;
147 HANDLER(n)->support = hsupport_length | hsupport_range;
149 /* Init
151 ret = cherokee_buffer_init (&n->buffer);
152 if (unlikely(ret != ret_ok))
153 return ret;
155 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
156 if (unlikely(ret != ret_ok))
157 return ret;
159 *hdl = HANDLER(n);
161 return ret_ok;
165 ret_t
166 cherokee_handler_avahi_free (cherokee_handler_avahi_t *hdl)
168 cherokee_buffer_mrproper (&hdl->buffer);
170 return ret_ok;
173 static ret_t
174 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
175 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
176 cherokee_buffer_t *buf2 = (cherokee_buffer_t *)value;
178 cherokee_buffer_add_buffer (buf, key);
179 cherokee_buffer_add_str (buf, " - ");
180 cherokee_buffer_add_buffer (buf, buf2);
181 // cherokee_buffer_add (buf, value, strlen(value));
182 cherokee_buffer_add_str (buf, "\n");
184 return ret_ok;
187 static void
188 avahi_build_page (cherokee_handler_avahi_t *hdl)
190 ret_t ret;
191 cherokee_buffer_t *buf;
193 /* Init
195 buf = &hdl->buffer;
197 /* Useful output
200 /* First, block the event loop */
201 // avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
203 /* Than, do your stuff */
204 cherokee_avl_r_while (&HDL_AVAHI_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL);
206 /* Finally, unblock the event loop */
207 // avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
210 ret_t
211 cherokee_handler_avahi_init (cherokee_handler_avahi_t *hdl)
213 ret_t ret;
214 void *param;
215 cint_t web_interface = 1;
217 /* Build the page
219 if (web_interface) {
220 avahi_build_page (hdl);
223 hdl->action = send_page;
225 return ret_ok;
229 ret_t
230 cherokee_handler_avahi_step (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
232 cherokee_buffer_add_buffer (buffer, &hdl->buffer);
233 return ret_eof_have_data;
237 ret_t
238 cherokee_handler_avahi_add_headers (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
240 if (hdl->buffer.len == 0) {
241 cherokee_connection_t *conn = HANDLER_CONN(hdl);
242 conn->error_code = http_not_found;
245 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
247 switch (hdl->action) {
248 case send_page:
249 default:
250 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
251 break;
254 return ret_ok;
258 /* Avahi example stuff */
260 static void resolve_callback(
261 AvahiServiceResolver *r,
262 AVAHI_GCC_UNUSED AvahiIfIndex interface,
263 AVAHI_GCC_UNUSED AvahiProtocol protocol,
264 AvahiResolverEvent event,
265 const char *name,
266 const char *type,
267 const char *domain,
268 const char *host_name,
269 const AvahiAddress *address,
270 uint16_t port,
271 AvahiStringList *txt,
272 AvahiLookupResultFlags flags,
273 void* userdata) {
274 assert(r);
276 /* Called whenever a service has been resolved successfully or timed out */
278 switch (event) {
279 case AVAHI_RESOLVER_FAILURE:
280 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))));
281 break;
283 case AVAHI_RESOLVER_FOUND: {
284 char a[AVAHI_ADDRESS_STR_MAX];
285 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
286 cherokee_buffer_t *buf2 = malloc(sizeof(cherokee_buffer_t));
289 // avahi_address_snprint(a, sizeof(a), address);
290 cherokee_buffer_add (&buf, name, strlen(name));
291 cherokee_buffer_init (buf2);
292 // cherokee_buffer_add (buf2, a, strlen(a));
293 cherokee_buffer_add (buf2, host_name, strlen(host_name));
294 cherokee_avl_r_add(&PROP_AVAHI(userdata)->entries, &buf, buf2);
295 cherokee_buffer_mrproper(&buf);
297 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
301 avahi_service_resolver_free(r);
304 static void browse_callback(
305 AvahiServiceBrowser *b,
306 AvahiIfIndex interface,
307 AvahiProtocol protocol,
308 AvahiBrowserEvent event,
309 const char *name,
310 const char *type,
311 const char *domain,
312 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
313 void* userdata) {
315 assert(b);
317 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
319 switch (event) {
320 case AVAHI_BROWSER_FAILURE:
321 TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
322 avahi_service_browser_free(b);
323 return;
325 case AVAHI_BROWSER_NEW:
326 TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
328 /* We ignore the returned resolver object. In the callback
329 function we free it. If the server is terminated before
330 the callback function is called the server will free
331 the resolver for us. */
333 if (!(avahi_service_resolver_new(avahi_service_browser_get_client(b), interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
334 TRACE("avahi", "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
336 break;
338 case AVAHI_BROWSER_REMOVE: {
339 void *val;
340 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
341 cherokee_buffer_add(&buf, name, strlen(name));
342 if (cherokee_avl_r_del(&PROP_AVAHI(userdata)->entries, &buf, &val) == ret_ok) {
343 cherokee_buffer_mrproper((cherokee_buffer_t *) val);
345 cherokee_buffer_mrproper(&buf);
347 // cherokee_avl_r_del_ptr(&PROP_AVAHI(userdata)->entries, name, val);
349 TRACE("avahi", "%s, (Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", __func__, name, type, domain);
350 break;
353 case AVAHI_BROWSER_ALL_FOR_NOW:
354 case AVAHI_BROWSER_CACHE_EXHAUSTED:
355 TRACE("avahi", "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
356 break;
360 static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
361 // assert(c);
363 cherokee_handler_avahi_props_t *props = userdata;
365 /* Called whenever the client or server state changes */
367 switch (state) {
368 case AVAHI_CLIENT_S_RUNNING:
369 /* create some browsers on the client object here, if you wish */
370 if (!(props->sb = avahi_service_browser_new(c, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, props->service_type.buf, NULL, 0, browse_callback, props))) {
371 TRACE ("avahi", "Failed to create service browser: %s (%s)\n", avahi_strerror(avahi_client_errno(c)), props->service_type.buf);
373 break;
374 case AVAHI_CLIENT_FAILURE: {
375 int error;
376 if (c)
377 avahi_client_free(c);
378 props->client = avahi_client_new(avahi_threaded_poll_get(props->threaded_poll), AVAHI_CLIENT_NO_FAIL, client_callback, props, &error);
379 break;
381 default:
382 break;
386 ret_t
387 cherokee_handler_avahi_props_init_base (cherokee_handler_avahi_props_t *props, module_func_props_free_t free_func)
389 cherokee_buffer_init (&props->service_type);
391 return cherokee_handler_props_init_base (HANDLER_PROPS(props), free_func);