1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
4 * Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <glib/gi18n.h>
30 #include <glib-object.h>
33 #include <avahi-client/lookup.h>
34 #include <avahi-client/publish.h>
36 #include <avahi-client/client.h>
37 #include <avahi-common/error.h>
38 #include <avahi-glib/glib-malloc.h>
39 #include <avahi-glib/glib-watch.h>
41 #include "rb-daap-mdns-browser.h"
42 #include "rb-marshal.h"
46 #define AVAHI_ADDRESS_STR_MAX (40) /* IPv6 Max = 4*8 + 7 + 1 for NUL */
49 static void rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass
*klass
);
50 static void rb_daap_mdns_browser_init (RBDaapMdnsBrowser
*browser
);
51 static void rb_daap_mdns_browser_finalize (GObject
*object
);
53 #define RB_DAAP_MDNS_BROWSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserPrivate))
55 struct RBDaapMdnsBrowserPrivate
59 AvahiServiceBrowser
*service_browser
;
74 static GObjectClass
*parent_class
= NULL
;
75 static guint signals
[LAST_SIGNAL
] = { 0, };
77 G_DEFINE_TYPE (RBDaapMdnsBrowser
, rb_daap_mdns_browser
, G_TYPE_OBJECT
)
79 static gpointer browser_object
= NULL
;
82 rb_daap_mdns_browser_error_quark (void)
84 static GQuark quark
= 0;
86 quark
= g_quark_from_static_string ("rb_daap_mdns_browser_error");
92 client_cb (AvahiClient
*client
,
93 AvahiClientState state
,
94 RBDaapMdnsBrowser
*browser
)
96 /* Called whenever the client or server state changes */
100 case AVAHI_CLIENT_FAILURE
:
102 g_warning ("Client failure: %s\n", avahi_strerror (avahi_client_errno (client
)));
111 avahi_client_init (RBDaapMdnsBrowser
*browser
)
115 avahi_set_allocator (avahi_glib_allocator ());
117 browser
->priv
->poll
= avahi_glib_poll_new (NULL
, G_PRIORITY_DEFAULT
);
119 if (! browser
->priv
->poll
) {
120 rb_debug ("Unable to create AvahiGlibPoll object for mDNS");
123 #ifdef HAVE_AVAHI_0_5
124 browser
->priv
->client
= avahi_client_new (avahi_glib_poll_get (browser
->priv
->poll
),
125 (AvahiClientCallback
) client_cb
,
129 #ifdef HAVE_AVAHI_0_6
131 AvahiClientFlags flags
;
134 browser
->priv
->client
= avahi_client_new (avahi_glib_poll_get (browser
->priv
->poll
),
136 (AvahiClientCallback
)client_cb
,
144 resolve_cb (AvahiServiceResolver
*service_resolver
,
145 AvahiIfIndex interface
,
146 AvahiProtocol protocol
,
147 AvahiResolverEvent event
,
148 const char *service_name
,
151 const char *host_name
,
152 const AvahiAddress
*address
,
154 AvahiStringList
*text
,
155 #ifdef HAVE_AVAHI_0_6
156 AvahiLookupResultFlags flags
,
158 RBDaapMdnsBrowser
*browser
)
160 if (event
== AVAHI_RESOLVER_FOUND
) {
162 char host
[AVAHI_ADDRESS_STR_MAX
];
168 for (l
= text
; l
!= NULL
; l
= l
->next
) {
174 ret
= avahi_string_list_get_pair (l
, &key
, &value
, &size
);
175 if (ret
!= 0 || key
== NULL
) {
179 if (strcmp (key
, "Password") == 0) {
180 if (size
>= 4 && strncmp (value
, "true", 4) == 0) {
183 } else if (strcmp (key
, "Machine Name") == 0) {
184 name
= g_strdup (value
);
193 name
= g_strdup (service_name
);
196 avahi_address_snprint (host
, AVAHI_ADDRESS_STR_MAX
, address
);
198 g_signal_emit (browser
,
199 signals
[SERVICE_ADDED
],
210 browser
->priv
->resolvers
= g_slist_remove (browser
->priv
->resolvers
, service_resolver
);
211 avahi_service_resolver_free (service_resolver
);
215 rb_daap_mdns_browser_resolve (RBDaapMdnsBrowser
*browser
,
218 AvahiServiceResolver
*service_resolver
;
220 service_resolver
= avahi_service_resolver_new (browser
->priv
->client
,
227 #ifdef HAVE_AVAHI_0_6
230 (AvahiServiceResolverCallback
)resolve_cb
,
232 if (service_resolver
== NULL
) {
233 rb_debug ("Error starting mDNS resolving using AvahiServiceResolver");
237 browser
->priv
->resolvers
= g_slist_prepend (browser
->priv
->resolvers
, service_resolver
);
243 browser_add_service (RBDaapMdnsBrowser
*browser
,
244 const char *service_name
)
246 rb_daap_mdns_browser_resolve (browser
, service_name
);
250 browser_remove_service (RBDaapMdnsBrowser
*browser
,
251 const char *service_name
)
253 g_signal_emit (browser
, signals
[SERVICE_REMOVED
], 0, service_name
);
257 browse_cb (AvahiServiceBrowser
*service_browser
,
258 AvahiIfIndex interface
,
259 AvahiProtocol protocol
,
260 AvahiBrowserEvent event
,
264 #ifdef HAVE_AVAHI_0_6
265 AvahiLookupResultFlags flags
,
267 RBDaapMdnsBrowser
*browser
)
271 #ifdef HAVE_AVAHI_0_5
272 local
= avahi_client_is_service_local (browser
->priv
->client
, interface
, protocol
, name
, type
, domain
);
274 #ifdef HAVE_AVAHI_0_6
275 local
= ((flags
& AVAHI_LOOKUP_RESULT_LOCAL
) != 0);
278 rb_debug ("Ignoring local service %s", name
);
282 if (event
== AVAHI_BROWSER_NEW
) {
283 browser_add_service (browser
, name
);
284 } else if (event
== AVAHI_BROWSER_REMOVE
) {
285 browser_remove_service (browser
, name
);
290 rb_daap_mdns_browser_start (RBDaapMdnsBrowser
*browser
,
293 if (browser
->priv
->client
== NULL
) {
295 RB_DAAP_MDNS_BROWSER_ERROR
,
296 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING
,
298 _("MDNS service is not running"));
301 if (browser
->priv
->service_browser
!= NULL
) {
303 RB_DAAP_MDNS_BROWSER_ERROR
,
304 RB_DAAP_MDNS_BROWSER_ERROR_FAILED
,
306 _("Browser already active"));
310 browser
->priv
->service_browser
= avahi_service_browser_new (browser
->priv
->client
,
315 #ifdef HAVE_AVAHI_0_6
318 (AvahiServiceBrowserCallback
)browse_cb
,
320 if (browser
->priv
->service_browser
== NULL
) {
321 rb_debug ("Error starting mDNS discovery using AvahiServiceBrowser");
323 RB_DAAP_MDNS_BROWSER_ERROR
,
324 RB_DAAP_MDNS_BROWSER_ERROR_FAILED
,
326 _("Unable to activate browser"));
335 rb_daap_mdns_browser_stop (RBDaapMdnsBrowser
*browser
,
338 if (browser
->priv
->client
== NULL
) {
340 RB_DAAP_MDNS_BROWSER_ERROR
,
341 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING
,
343 _("MDNS service is not running"));
346 if (browser
->priv
->service_browser
== NULL
) {
348 RB_DAAP_MDNS_BROWSER_ERROR
,
349 RB_DAAP_MDNS_BROWSER_ERROR_FAILED
,
351 _("Browser is not active"));
355 avahi_service_browser_free (browser
->priv
->service_browser
);
356 browser
->priv
->service_browser
= NULL
;
362 rb_daap_mdns_browser_set_property (GObject
*object
,
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
375 rb_daap_mdns_browser_get_property (GObject
*object
,
382 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
388 rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass
*klass
)
390 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
392 parent_class
= g_type_class_peek_parent (klass
);
394 object_class
->finalize
= rb_daap_mdns_browser_finalize
;
395 object_class
->get_property
= rb_daap_mdns_browser_get_property
;
396 object_class
->set_property
= rb_daap_mdns_browser_set_property
;
398 signals
[SERVICE_ADDED
] =
399 g_signal_new ("service-added",
400 G_TYPE_FROM_CLASS (object_class
),
402 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass
, service_added
),
405 rb_marshal_VOID__STRING_STRING_STRING_UINT_BOOLEAN
,
407 5, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_UINT
, G_TYPE_BOOLEAN
);
408 signals
[SERVICE_REMOVED
] =
409 g_signal_new ("service-removed",
410 G_TYPE_FROM_CLASS (object_class
),
412 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass
, service_removed
),
415 g_cclosure_marshal_VOID__STRING
,
419 g_type_class_add_private (klass
, sizeof (RBDaapMdnsBrowserPrivate
));
423 rb_daap_mdns_browser_init (RBDaapMdnsBrowser
*browser
)
425 browser
->priv
= RB_DAAP_MDNS_BROWSER_GET_PRIVATE (browser
);
427 avahi_client_init (browser
);
431 rb_daap_mdns_browser_finalize (GObject
*object
)
433 RBDaapMdnsBrowser
*browser
;
435 g_return_if_fail (object
!= NULL
);
436 g_return_if_fail (RB_IS_DAAP_MDNS_BROWSER (object
));
438 browser
= RB_DAAP_MDNS_BROWSER (object
);
440 g_return_if_fail (browser
->priv
!= NULL
);
442 if (browser
->priv
->resolvers
) {
443 g_slist_foreach (browser
->priv
->resolvers
,
444 (GFunc
)avahi_service_resolver_free
,
446 g_slist_free (browser
->priv
->resolvers
);
449 if (browser
->priv
->service_browser
) {
450 avahi_service_browser_free (browser
->priv
->service_browser
);
453 if (browser
->priv
->client
) {
454 avahi_client_free (browser
->priv
->client
);
457 if (browser
->priv
->poll
) {
458 avahi_glib_poll_free (browser
->priv
->poll
);
461 G_OBJECT_CLASS (parent_class
)->finalize (object
);
465 rb_daap_mdns_browser_new (void)
467 if (browser_object
) {
468 g_object_ref (browser_object
);
470 browser_object
= g_object_new (RB_TYPE_DAAP_MDNS_BROWSER
, NULL
);
471 g_object_add_weak_pointer (browser_object
,
472 (gpointer
*) &browser_object
);
475 return RB_DAAP_MDNS_BROWSER (browser_object
);