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 cherokee_handler_avahi_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
);
70 return cherokee_module_props_free_base (MODULE_PROPS(props
));
75 cherokee_handler_avahi_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
78 cherokee_handler_avahi_props_t
*props
;
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
);
104 PRINT_MSG ("ERROR: Handler file: Unknown key: '%s'\n", subconf->key.buf);
109 /* If the configuration for avahi was not set, we should not continue */
110 if (props
->service_type
.len
== 0) {
114 props
->client
= NULL
;
116 props
->threaded_poll
= NULL
;
118 cherokee_avl_init(&props
->entries
);
120 if (!(props
->threaded_poll
= avahi_threaded_poll_new())) {
124 if (!(props
->client
= avahi_client_new(avahi_threaded_poll_get(props
->threaded_poll
), 0, client_callback
, props
, &error
))) {
128 /* create some browsers on the client object here, if you wish */
129 if (!(props
->sb
= avahi_service_browser_new(props
->client
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, props
->service_type
.buf
, NULL
, 0, browse_callback
, props
))) {
130 TRACE ("avahi", "Failed to create service browser: %s (%s)\n", avahi_strerror(avahi_client_errno(props
->client
)), props
->service_type
.buf
);
134 /* Finally, start the event loop thread */
135 if (avahi_threaded_poll_start(props
->threaded_poll
) < 0) {
144 cherokee_handler_avahi_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
148 CHEROKEE_NEW_STRUCT (n
, handler_avahi
);
150 /* Init the base class object
152 cherokee_handler_init_base(HANDLER(n
), cnt
, HANDLER_PROPS(props
), PLUGIN_INFO_HANDLER_PTR(avahi
));
154 MODULE(n
)->init
= (handler_func_init_t
) cherokee_handler_avahi_init
;
155 MODULE(n
)->free
= (module_func_free_t
) cherokee_handler_avahi_free
;
156 HANDLER(n
)->step
= (handler_func_step_t
) cherokee_handler_avahi_step
;
157 HANDLER(n
)->add_headers
= (handler_func_add_headers_t
) cherokee_handler_avahi_add_headers
;
159 HANDLER(n
)->support
= hsupport_length
| hsupport_range
;
163 ret
= cherokee_buffer_init (&n
->buffer
);
164 if (unlikely(ret
!= ret_ok
))
167 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
168 if (unlikely(ret
!= ret_ok
))
178 cherokee_handler_avahi_free (cherokee_handler_avahi_t
*hdl
)
180 cherokee_buffer_mrproper (&hdl
->buffer
);
186 while_func_entries (cherokee_buffer_t
*key
, void *value
, void *param
) {
187 cherokee_buffer_t
*buf
= (cherokee_buffer_t
*)param
;
188 cherokee_buffer_t
*buf2
= (cherokee_buffer_t
*)value
;
190 cherokee_buffer_add_buffer (buf
, key
);
191 cherokee_buffer_add_str (buf
, " - ");
192 cherokee_buffer_add_buffer (buf
, buf2
);
193 // cherokee_buffer_add (buf, value, strlen(value));
194 cherokee_buffer_add_str (buf
, "\n");
200 avahi_build_page (cherokee_handler_avahi_t
*hdl
)
203 cherokee_buffer_t
*buf
;
212 /* First, block the event loop */
213 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
215 /* Than, do your stuff */
216 cherokee_avl_while (&HDL_AVAHI_PROPS(hdl
)->entries
, (cherokee_avl_while_func_t
) while_func_entries
, (void *) buf
, NULL
, NULL
);
218 /* Finally, unblock the event loop */
219 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
223 cherokee_handler_avahi_init (cherokee_handler_avahi_t
*hdl
)
227 cint_t web_interface
= 1;
232 avahi_build_page (hdl
);
235 hdl
->action
= send_page
;
242 cherokee_handler_avahi_step (cherokee_handler_avahi_t
*hdl
, cherokee_buffer_t
*buffer
)
244 cherokee_buffer_add_buffer (buffer
, &hdl
->buffer
);
245 return ret_eof_have_data
;
250 cherokee_handler_avahi_add_headers (cherokee_handler_avahi_t
*hdl
, cherokee_buffer_t
*buffer
)
252 if (hdl
->buffer
.len
== 0) {
253 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
254 conn
->error_code
= http_not_found
;
257 cherokee_buffer_add_va (buffer
, "Content-Length: %d"CRLF
, hdl
->buffer
.len
);
259 switch (hdl
->action
) {
262 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
270 /* Avahi example stuff */
272 static void resolve_callback(
273 AvahiServiceResolver
*r
,
274 AVAHI_GCC_UNUSED AvahiIfIndex interface
,
275 AVAHI_GCC_UNUSED AvahiProtocol protocol
,
276 AvahiResolverEvent event
,
280 const char *host_name
,
281 const AvahiAddress
*address
,
283 AvahiStringList
*txt
,
284 AvahiLookupResultFlags flags
,
288 /* Called whenever a service has been resolved successfully or timed out */
291 case AVAHI_RESOLVER_FAILURE
:
292 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
))));
295 case AVAHI_RESOLVER_FOUND
: {
296 char a
[AVAHI_ADDRESS_STR_MAX
], *t
;
298 avahi_address_snprint(a
, sizeof(a
), address
);
300 cherokee_buffer_t buf
;
301 cherokee_buffer_t buf2
;
302 cherokee_buffer_t
*buf2a
;
303 cherokee_buffer_init(&buf
);
304 cherokee_buffer_init(&buf2
);
305 cherokee_buffer_add(&buf
, name
, strlen(name
));
306 // cherokee_buffer_add(&buf2, a, strlen(a));
307 cherokee_buffer_add (&buf2
, host_name
, strlen(host_name
));
308 cherokee_buffer_dup(&buf2
, &buf2a
);
309 cherokee_avl_add(&PROP_AVAHI(userdata
)->entries
, &buf
, buf2a
);
310 cherokee_buffer_mrproper(&buf
);
311 cherokee_buffer_mrproper(&buf2
);
313 // cherokee_avl_add_ptr (&PROP_AVAHI(userdata)->entries, name, (void *) host_name);
315 TRACE("avahi", "Service '%s' of type '%s' in domain '%s':\n", name
, type
, domain
);
317 t
= avahi_string_list_to_string(txt
);
329 avahi_string_list_get_service_cookie(txt
),
330 !!(flags
& AVAHI_LOOKUP_RESULT_LOCAL
),
331 !!(flags
& AVAHI_LOOKUP_RESULT_OUR_OWN
),
332 !!(flags
& AVAHI_LOOKUP_RESULT_WIDE_AREA
),
333 !!(flags
& AVAHI_LOOKUP_RESULT_MULTICAST
),
334 !!(flags
& AVAHI_LOOKUP_RESULT_CACHED
));
340 avahi_service_resolver_free(r
);
343 static void browse_callback(
344 AvahiServiceBrowser
*b
,
345 AvahiIfIndex interface
,
346 AvahiProtocol protocol
,
347 AvahiBrowserEvent event
,
351 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
354 AvahiClient
*c
= PROP_AVAHI(userdata
)->client
;
357 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
360 case AVAHI_BROWSER_FAILURE
:
361 TRACE("avahi", "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
362 // avahi_threaded_poll_stop(PROP_AVAHI(userdata)->threaded_poll);
365 case AVAHI_BROWSER_NEW
:
366 TRACE("avahi", "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
368 /* We ignore the returned resolver object. In the callback
369 function we free it. If the server is terminated before
370 the callback function is called the server will free
371 the resolver for us. */
373 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, resolve_callback
, userdata
)))
374 TRACE("avahi", "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
378 case AVAHI_BROWSER_REMOVE
: {
380 cherokee_buffer_t buf
;
381 cherokee_buffer_init(&buf
);
382 cherokee_buffer_add(&buf
, name
, strlen(name
));
383 if (cherokee_avl_del(&PROP_AVAHI(userdata
)->entries
, &buf
, val
) == ret_ok
) {
384 cherokee_buffer_mrproper((cherokee_buffer_t
*) *val
);
386 cherokee_buffer_mrproper(&buf
);
388 // cherokee_avl_del_ptr(&PROP_AVAHI(userdata)->entries, name, val);
390 TRACE("avahi", "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
394 case AVAHI_BROWSER_ALL_FOR_NOW
:
395 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
396 TRACE("avahi", "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
401 static void client_callback(AvahiClient
*c
, AvahiClientState state
, void * userdata
) {
404 /* Called whenever the client or server state changes */
406 if (state
== AVAHI_CLIENT_FAILURE
) {
407 TRACE("avahi", "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c
)));
408 // avahi_threaded_poll_stop(PROP_AVAHI(userdata)->threaded_poll);
413 cherokee_handler_avahi_props_init_base (cherokee_handler_avahi_props_t
*props
, module_func_props_free_t free_func
)
415 cherokee_buffer_init (&props
->service_type
);
417 return cherokee_handler_props_init_base (HANDLER_PROPS(props
), free_func
);