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>
32 #include <libgnomevfs/gnome-vfs-address.h>
33 #include <libgnomevfs/gnome-vfs-resolve.h>
35 /* stupid howl includes howl_config.h */
40 #include "rb-daap-mdns-browser.h"
41 #include "rb-marshal.h"
44 static void rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass
*klass
);
45 static void rb_daap_mdns_browser_init (RBDaapMdnsBrowser
*browser
);
46 static void rb_daap_mdns_browser_finalize (GObject
*object
);
48 #define RB_DAAP_MDNS_BROWSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserPrivate))
50 struct RBDaapMdnsBrowserPrivate
52 sw_discovery
*discovery
;
53 sw_discovery_oid
*oid
;
55 GnomeVFSAddress
*local_address
;
70 static guint signals
[LAST_SIGNAL
] = { 0, };
72 G_DEFINE_TYPE (RBDaapMdnsBrowser
, rb_daap_mdns_browser
, G_TYPE_OBJECT
)
74 static gpointer browser_object
= NULL
;
77 rb_daap_mdns_browser_error_quark (void)
79 static GQuark quark
= 0;
81 quark
= g_quark_from_static_string ("rb_daap_mdns_browser_error");
87 howl_in_cb (GIOChannel
*io_channel
,
88 GIOCondition condition
,
89 RBDaapMdnsBrowser
*browser
)
93 if (sw_discovery_salt (*browser
->priv
->discovery
, &salt
) == SW_OKAY
) {
95 sw_discovery_read_socket (*browser
->priv
->discovery
);
96 sw_salt_unlock (salt
);
103 howl_client_init (RBDaapMdnsBrowser
*browser
)
109 browser
->priv
->discovery
= g_new0 (sw_discovery
, 1);
110 result
= sw_discovery_init (browser
->priv
->discovery
);
112 if (result
!= SW_OKAY
) {
113 g_free (browser
->priv
->discovery
);
114 browser
->priv
->discovery
= NULL
;
118 fd
= sw_discovery_socket (*browser
->priv
->discovery
);
120 channel
= g_io_channel_unix_new (fd
);
121 browser
->priv
->watch_id
= g_io_add_watch (channel
, G_IO_IN
, (GIOFunc
)howl_in_cb
, browser
);
122 g_io_channel_unref (channel
);
126 host_is_local (RBDaapMdnsBrowser
*browser
,
129 GnomeVFSAddress
*remote
;
134 if (browser
->priv
->local_address
== NULL
) {
135 g_warning ("Unable to resolve address");
139 remote
= gnome_vfs_address_new_from_string (host
);
140 if (remote
== NULL
) {
141 g_warning ("Unable to resolve address for %s", host
);
145 l_ip
= gnome_vfs_address_get_ipv4 (browser
->priv
->local_address
);
146 r_ip
= gnome_vfs_address_get_ipv4 (remote
);
147 equal
= l_ip
== r_ip
;
149 /* FIXME: Use this when we can depend on gnome-vfs 2.14 */
150 /*equal = gnome_vfs_address_equal (browser->priv->local_address, remote);*/
152 gnome_vfs_address_free (remote
);
158 set_local_address (RBDaapMdnsBrowser
*browser
)
160 char host_name
[256];
161 GnomeVFSResolveHandle
*rh
;
162 GnomeVFSAddress
*address
;
165 if (gethostname (host_name
, sizeof (host_name
)) != 0) {
166 g_warning ("gethostname failed: %s", g_strerror (errno
));
170 res
= gnome_vfs_resolve (host_name
, &rh
);
172 if (res
!= GNOME_VFS_OK
) {
177 while (gnome_vfs_resolve_next_address (rh
, &address
)) {
178 if (browser
->priv
->local_address
== NULL
) {
179 browser
->priv
->local_address
= gnome_vfs_address_dup (address
);
181 gnome_vfs_address_free (address
);
184 gnome_vfs_resolve_free (rh
);
188 resolve_cb (sw_discovery discovery
,
189 sw_discovery_oid oid
,
190 sw_uint32 interface_index
,
191 sw_const_string service_name
,
192 sw_const_string type
,
193 sw_const_string domain
,
194 sw_ipv4_address address
,
196 sw_octets text_record
,
197 sw_ulong text_record_length
,
198 RBDaapMdnsBrowser
*browser
)
202 sw_text_record_iterator it
;
205 host
= g_malloc (16);
208 sw_ipv4_address_name (address
, host
, 16);
210 /* skip local services */
211 if (host_is_local (browser
, host
)) {
215 if (sw_text_record_iterator_init (&it
, text_record
, text_record_length
) == SW_OKAY
) {
216 sw_char key
[SW_TEXT_RECORD_MAX_LEN
];
217 sw_octet val
[SW_TEXT_RECORD_MAX_LEN
];
220 while (sw_text_record_iterator_next (it
, (char *)key
, val
, &val_len
) == SW_OKAY
) {
221 if (strcmp ((char *)key
, "Password") == 0) {
222 if (val_len
>= 4 && strncmp ((char *)val
, "true", 4) == 0) {
226 if (strcmp ((char *)key
, "Machine Name") == 0) {
229 name
= g_strdup ((char *)val
);
233 sw_text_record_iterator_fina (it
);
237 name
= g_strdup (service_name
);
240 g_signal_emit (browser
,
241 signals
[SERVICE_ADDED
],
256 rb_daap_mdns_browser_resolve (RBDaapMdnsBrowser
*browser
,
260 sw_discovery_oid oid
;
262 result
= sw_discovery_resolve (*browser
->priv
->discovery
,
267 (sw_discovery_resolve_reply
) resolve_cb
,
269 (sw_discovery_oid
*) &oid
);
275 browser_add_service (RBDaapMdnsBrowser
*browser
,
276 const char *service_name
)
278 rb_daap_mdns_browser_resolve (browser
, service_name
);
282 browser_remove_service (RBDaapMdnsBrowser
*browser
,
283 const char *service_name
)
285 g_signal_emit (browser
, signals
[SERVICE_REMOVED
], 0, service_name
);
289 browse_cb (sw_discovery discovery
,
290 sw_discovery_oid oid
,
291 sw_discovery_browse_status status
,
292 sw_uint32 interface_index
,
293 sw_const_string name
,
294 sw_const_string type
,
295 sw_const_string domain
,
296 RBDaapMdnsBrowser
*browser
)
298 if (status
== SW_DISCOVERY_BROWSE_ADD_SERVICE
) {
299 browser_add_service (browser
, name
);
300 } else if (status
== SW_DISCOVERY_BROWSE_REMOVE_SERVICE
) {
301 browser_remove_service (browser
, name
);
308 rb_daap_mdns_browser_start (RBDaapMdnsBrowser
*browser
,
313 if (browser
->priv
->discovery
== NULL
) {
315 RB_DAAP_MDNS_BROWSER_ERROR
,
316 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING
,
318 _("MDNS service is not running"));
322 if (browser
->priv
->oid
!= NULL
) {
324 RB_DAAP_MDNS_BROWSER_ERROR
,
325 RB_DAAP_MDNS_BROWSER_ERROR_FAILED
,
327 _("Browser already active"));
331 browser
->priv
->oid
= g_new0 (sw_discovery_oid
, 1);
333 result
= sw_discovery_browse (*browser
->priv
->discovery
,
337 (sw_discovery_browse_reply
) browse_cb
,
339 (sw_discovery_oid
*) browser
->priv
->oid
);
342 if (result
!= SW_OKAY
) {
343 rb_debug ("Error starting mDNS discovery using Howl");
345 RB_DAAP_MDNS_BROWSER_ERROR
,
346 RB_DAAP_MDNS_BROWSER_ERROR_FAILED
,
348 _("Unable to activate browser"));
357 rb_daap_mdns_browser_stop (RBDaapMdnsBrowser
*browser
,
360 if (browser
->priv
->discovery
== NULL
) {
362 RB_DAAP_MDNS_BROWSER_ERROR
,
363 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING
,
365 _("MDNS service is not running"));
368 if (browser
->priv
->oid
== NULL
) {
370 RB_DAAP_MDNS_BROWSER_ERROR
,
371 RB_DAAP_MDNS_BROWSER_ERROR_FAILED
,
373 _("Browser is not active"));
378 sw_discovery_cancel (*browser
->priv
->discovery
, *browser
->priv
->oid
);
380 g_free (browser
->priv
->oid
);
381 browser
->priv
->oid
= NULL
;
387 rb_daap_mdns_browser_set_property (GObject
*object
,
394 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
400 rb_daap_mdns_browser_get_property (GObject
*object
,
407 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
413 rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass
*klass
)
415 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
417 object_class
->finalize
= rb_daap_mdns_browser_finalize
;
418 object_class
->get_property
= rb_daap_mdns_browser_get_property
;
419 object_class
->set_property
= rb_daap_mdns_browser_set_property
;
421 signals
[SERVICE_ADDED
] =
422 g_signal_new ("service-added",
423 G_TYPE_FROM_CLASS (object_class
),
425 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass
, service_added
),
428 rb_marshal_VOID__STRING_STRING_STRING_UINT_BOOLEAN
,
430 5, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_UINT
, G_TYPE_BOOLEAN
);
431 signals
[SERVICE_REMOVED
] =
432 g_signal_new ("service-removed",
433 G_TYPE_FROM_CLASS (object_class
),
435 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass
, service_removed
),
438 g_cclosure_marshal_VOID__STRING
,
442 g_type_class_add_private (klass
, sizeof (RBDaapMdnsBrowserPrivate
));
446 rb_daap_mdns_browser_init (RBDaapMdnsBrowser
*browser
)
448 browser
->priv
= RB_DAAP_MDNS_BROWSER_GET_PRIVATE (browser
);
450 set_local_address (browser
);
452 howl_client_init (browser
);
456 resolver_free (sw_discovery_oid
*oid
,
457 RBDaapMdnsBrowser
*browser
)
459 sw_discovery_cancel (*browser
->priv
->discovery
,
466 rb_daap_mdns_browser_finalize (GObject
*object
)
468 RBDaapMdnsBrowser
*browser
;
470 g_return_if_fail (object
!= NULL
);
471 g_return_if_fail (RB_IS_DAAP_MDNS_BROWSER (object
));
473 browser
= RB_DAAP_MDNS_BROWSER (object
);
475 g_return_if_fail (browser
->priv
!= NULL
);
477 if (browser
->priv
->oid
) {
478 rb_daap_mdns_browser_stop (browser
, NULL
);
481 if (browser
->priv
->resolvers
) {
482 g_slist_foreach (browser
->priv
->resolvers
,
483 (GFunc
)resolver_free
,
485 g_slist_free (browser
->priv
->resolvers
);
488 if (browser
->priv
->discovery
) {
489 sw_discovery_fina (*browser
->priv
->discovery
);
490 g_free (browser
->priv
->discovery
);
493 if (browser
->priv
->watch_id
> 0) {
494 g_source_remove (browser
->priv
->watch_id
);
497 if (browser
->priv
->local_address
) {
498 gnome_vfs_address_free (browser
->priv
->local_address
);
501 G_OBJECT_CLASS (rb_daap_mdns_browser_parent_class
)->finalize (object
);
505 rb_daap_mdns_browser_new (void)
507 if (browser_object
) {
508 g_object_ref (browser_object
);
510 browser_object
= g_object_new (RB_TYPE_DAAP_MDNS_BROWSER
, NULL
);
511 g_object_add_weak_pointer (browser_object
,
512 (gpointer
*) &browser_object
);
515 return RB_DAAP_MDNS_BROWSER (browser_object
);