If something goes bad with loading, but the file actually exist, give a internal...
[handlervirt.git] / handler_avahi.c
blob2e6ce1b39dc84b721d2a521703d9329e1a590403
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;
127 return ret_ok;
130 ret_t
131 cherokee_handler_avahi_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
133 ret_t ret;
135 CHEROKEE_NEW_STRUCT (n, handler_avahi);
137 /* Init the base class object
139 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(avahi));
141 MODULE(n)->init = (handler_func_init_t) cherokee_handler_avahi_init;
142 MODULE(n)->free = (module_func_free_t) cherokee_handler_avahi_free;
143 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_avahi_step;
144 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_avahi_add_headers;
146 HANDLER(n)->support = hsupport_length | hsupport_range;
148 /* Init
150 ret = cherokee_buffer_init (&n->buffer);
151 if (unlikely(ret != ret_ok))
152 return ret;
154 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
155 if (unlikely(ret != ret_ok))
156 return ret;
158 *hdl = HANDLER(n);
160 return ret_ok;
164 ret_t
165 cherokee_handler_avahi_free (cherokee_handler_avahi_t *hdl)
167 cherokee_buffer_mrproper (&hdl->buffer);
169 return ret_ok;
172 static ret_t
173 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
174 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
175 cherokee_buffer_t *buf2 = (cherokee_buffer_t *)value;
177 cherokee_buffer_add_buffer (buf, key);
178 cherokee_buffer_add_str (buf, " - ");
179 cherokee_buffer_add_buffer (buf, buf2);
180 // cherokee_buffer_add (buf, value, strlen(value));
181 cherokee_buffer_add_str (buf, "\n");
183 return ret_ok;
186 static void
187 avahi_build_page (cherokee_handler_avahi_t *hdl)
189 ret_t ret;
190 cherokee_buffer_t *buf;
192 /* Init
194 buf = &hdl->buffer;
196 /* Useful output
199 /* First, block the event loop */
200 // avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
202 /* Than, do your stuff */
203 cherokee_avl_r_while (&HDL_AVAHI_PROPS(hdl)->entries, (cherokee_avl_while_func_t) while_func_entries, (void *) buf, NULL, NULL);
205 /* Finally, unblock the event loop */
206 // avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
209 ret_t
210 cherokee_handler_avahi_init (cherokee_handler_avahi_t *hdl)
212 ret_t ret;
213 void *param;
214 cint_t web_interface = 1;
216 /* Build the page
218 if (web_interface) {
219 avahi_build_page (hdl);
222 hdl->action = send_page;
224 return ret_ok;
228 ret_t
229 cherokee_handler_avahi_step (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
231 cherokee_buffer_add_buffer (buffer, &hdl->buffer);
232 return ret_eof_have_data;
236 ret_t
237 cherokee_handler_avahi_add_headers (cherokee_handler_avahi_t *hdl, cherokee_buffer_t *buffer)
239 if (hdl->buffer.len == 0) {
240 cherokee_connection_t *conn = HANDLER_CONN(hdl);
241 conn->error_code = http_not_found;
244 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
246 switch (hdl->action) {
247 case send_page:
248 default:
249 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
250 break;
253 return ret_ok;
257 /* Avahi example stuff */
259 static void resolve_callback(
260 AvahiServiceResolver *r,
261 AVAHI_GCC_UNUSED AvahiIfIndex interface,
262 AVAHI_GCC_UNUSED AvahiProtocol protocol,
263 AvahiResolverEvent event,
264 const char *name,
265 const char *type,
266 const char *domain,
267 const char *host_name,
268 const AvahiAddress *address,
269 uint16_t port,
270 AvahiStringList *txt,
271 AvahiLookupResultFlags flags,
272 void* userdata) {
273 assert(r);
275 /* Called whenever a service has been resolved successfully or timed out */
277 switch (event) {
278 case AVAHI_RESOLVER_FAILURE:
279 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))));
280 break;
282 case AVAHI_RESOLVER_FOUND: {
283 char a[AVAHI_ADDRESS_STR_MAX];
284 cherokee_buffer_t buf = CHEROKEE_BUF_INIT;
285 cherokee_buffer_t *buf2 = malloc(sizeof(cherokee_buffer_t));
288 // avahi_address_snprint(a, sizeof(a), address);
289 cherokee_buffer_add (&buf, name, strlen(name));
290 cherokee_buffer_init (buf2);
291 // cherokee_buffer_add (buf2, a, strlen(a));
292 cherokee_buffer_add (buf2, host_name, strlen(host_name));
293 cherokee_avl_r_add(&PROP_AVAHI(userdata)->entries, &buf, buf2);
294 cherokee_buffer_mrproper(&buf);
296 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
300 avahi_service_resolver_free(r);
303 static void browse_callback(
304 AvahiServiceBrowser *b,
305 AvahiIfIndex interface,
306 AvahiProtocol protocol,
307 AvahiBrowserEvent event,
308 const char *name,
309 const char *type,
310 const char *domain,
311 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
312 void* userdata) {
313 cherokee_handler_avahi_props_t *props = userdata;
314 assert(b);
316 /* 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(&props->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);