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_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
52 props_free (cherokee_handler_avahi_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_avahi_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
79 cherokee_handler_avahi_props_t
*props
;
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
);
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_avahi_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
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
;
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_avahi_free (cherokee_handler_avahi_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 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");
201 avahi_build_page (cherokee_handler_avahi_t
*hdl
)
204 cherokee_buffer_t
*buf
;
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
);
224 cherokee_handler_avahi_init (cherokee_handler_avahi_t
*hdl
)
228 cint_t web_interface
= 1;
233 avahi_build_page (hdl
);
236 hdl
->action
= send_page
;
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
;
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
) {
263 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
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
,
281 const char *host_name
,
282 const AvahiAddress
*address
,
284 AvahiStringList
*txt
,
285 AvahiLookupResultFlags flags
,
289 /* Called whenever a service has been resolved successfully or timed out */
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
))));
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
);
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
));
341 avahi_service_resolver_free(r
);
344 static void browse_callback(
345 AvahiServiceBrowser
*b
,
346 AvahiIfIndex interface
,
347 AvahiProtocol protocol
,
348 AvahiBrowserEvent event
,
352 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
355 AvahiClient
*c
= PROP_AVAHI(userdata
)->client
;
358 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
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
);
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
)));
379 case AVAHI_BROWSER_REMOVE
: {
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
);
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");
402 static void client_callback(AvahiClient
*c
, AvahiClientState state
, void * userdata
) {
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
);
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
);