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 props
->client
= NULL
;
112 props
->threaded_poll
= NULL
;
114 cherokee_avl_init(&props
->entries
);
116 if (!(props
->threaded_poll
= avahi_threaded_poll_new())) {
120 if (!(props
->client
= avahi_client_new(avahi_threaded_poll_get(props
->threaded_poll
), 0, client_callback
, props
, &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
);
130 /* Finally, start the event loop thread */
131 if (avahi_threaded_poll_start(props
->threaded_poll
) < 0) {
140 cherokee_handler_avahi_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
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
;
159 ret
= cherokee_buffer_init (&n
->buffer
);
160 if (unlikely(ret
!= ret_ok
))
163 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
164 if (unlikely(ret
!= ret_ok
))
174 cherokee_handler_avahi_free (cherokee_handler_avahi_t
*hdl
)
176 cherokee_buffer_mrproper (&hdl
->buffer
);
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");
196 avahi_build_page (cherokee_handler_avahi_t
*hdl
)
199 cherokee_buffer_t
*buf
;
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
);
219 cherokee_handler_avahi_init (cherokee_handler_avahi_t
*hdl
)
223 cint_t web_interface
= 1;
228 avahi_build_page (hdl
);
231 hdl
->action
= send_page
;
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
;
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
) {
258 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
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
,
276 const char *host_name
,
277 const AvahiAddress
*address
,
279 AvahiStringList
*txt
,
280 AvahiLookupResultFlags flags
,
284 /* Called whenever a service has been resolved successfully or timed out */
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
))));
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
);
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
));
336 avahi_service_resolver_free(r
);
339 static void browse_callback(
340 AvahiServiceBrowser
*b
,
341 AvahiIfIndex interface
,
342 AvahiProtocol protocol
,
343 AvahiBrowserEvent event
,
347 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
350 AvahiClient
*c
= PROP_AVAHI(userdata
)->client
;
353 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
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
);
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
)));
374 case AVAHI_BROWSER_REMOVE
: {
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
);
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");
397 static void client_callback(AvahiClient
*c
, AvahiClientState state
, void * userdata
) {
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
);
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
);