File gnome-vfs2-bonjour-support.patch of Package gnome-vfs2
Index: configure.in
================================================================================
--- configure.in
+++ configure.in
@@ -705,17 +705,67 @@
fi
AC_ARG_ENABLE(howl, [ --disable-howl build without howl support])
-msg_howl=no
+msg_zeroconf=no
if test "x$msg_avahi" = "xno" -a "x$enable_howl" != "xno"; then
PKG_CHECK_MODULES(HOWL, howl >= 0.9.6,
[AM_CONDITIONAL(HAVE_HOWL, true)
AC_DEFINE(HAVE_HOWL, [], [Set if we can use howl])]
- msg_howl=yes,
+ msg_zeroconf=howl,
[AM_CONDITIONAL(HAVE_HOWL, false)])
AC_SUBST(HOWL_CFLAGS)
AC_SUBST(HOWL_LIBS)
fi
+ dnl ****************************
+dnl Bonjour
+dnl ****************************
+
+AM_CONDITIONAL(HAVE_BONJOUR, false)
+AC_ARG_ENABLE(bonjour, [ --enable-bonjour build with bonjour support])
+if test "x$enable_bonjour" = "xyes"; then
+ if test "x${HOWL_LIBS}" != "x"; then
+ AC_MSG_ERROR([*** Can't use both howl and bonjour at the same time. Please pick one only. ***])
+ else
+ CPPFLAGS_save="$CPPFLAGS"
+ LDFLAGS_save="$LDFLAGS"
+
+ AC_ARG_WITH(bonjour-includes, [ --with-bonjour-includes=PREFIX
+ Location of Bonjour includes.],
+ with_bonjour_includes="$withval",
+ with_bonjour_includes="/usr/include")
+
+ CPPFLAGS="$CPPFLAGS -I$with_bonjour_includes"
+ AC_CHECK_HEADER(dns_sd.h, , AC_MSG_ERROR([Unable to find Bonjour includes]))
+ CPPFLAGS="$CPPFLAGS_save"
+
+ if test x$with_bonjour_includes != x/usr/include; then
+ BONJOUR_CFLAGS="-I$with_bonjour_includes"
+ else
+ BONJOUR_CFLAGS=""
+ fi
+
+ AC_ARG_WITH(bonjour-libs, [ --with-bonjour-libs=PREFIX
+ Location of Bonjour libs.],
+ with_bonjour_libs="$withval", with_bonjour_libs="/usr/lib")
+
+ LDFLAGS="$LDFLAGS -L$with_bonjour_libs -ldns_sd"
+ AC_TRY_LINK_FUNC(DNSServiceResolve, , AC_MSG_ERROR([Unable to find Bonjour libs]))
+ LDFLAGS="$LDFLAGS_save"
+
+ if test x$with_bonjour_libs != x/usr/lib; then
+ BONJOUR_LIBS="-L$with_bonjour_libs -ldns_sd"
+ else
+ BONJOUR_LIBS="-ldns_sd"
+ fi
+
+ msg_zeroconf="bonjour"
+ AM_CONDITIONAL(HAVE_BONJOUR, true)
+ AC_DEFINE(HAVE_BONJOUR, 1, [Define to 1 if Bonjour is available and desired])
+ AC_SUBST(BONJOUR_CFLAGS)
+ AC_SUBST(BONJOUR_LIBS)
+ fi
+fi
+
dnl ****************************
dnl HAL stuff
dnl ****************************
@@ -1019,8 +1069,8 @@
dnl ==============================================================================
PKG_CHECK_MODULES(LIBGNOMEVFS, glib-2.0 >= $GLIB_REQUIRED gmodule-no-export-2.0 >= $GLIB_REQUIRED gthread-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gconf-2.0 >= $GCONF_REQUIRED libxml-2.0 >= $XML_REQUIRED gnome-mime-data-2.0 dbus-glib-1 >= 0.60)
-LIBGNOMEVFS_CFLAGS="$LIBGNOMEVFS_CFLAGS $OPENSSL_CFLAGS $LIBGNUTLS_CFLAGS $HOWL_CFLAGS $AVAHI_CFLAGS"
-LIBGNOMEVFS_LIBS="$LIBGNOMEVFS_LIBS $OPENSSL_LIBS $LIBGNUTLS_LIBS $HOWL_LIBS $AVAHI_LIBS $RESOLVER_LIBS"
+LIBGNOMEVFS_CFLAGS="$LIBGNOMEVFS_CFLAGS $OPENSSL_CFLAGS $LIBGNUTLS_CFLAGS $HOWL_CFLAGS $BONJOUR_CFLAGS $AVAHI_CFLAGS"
+LIBGNOMEVFS_LIBS="$LIBGNOMEVFS_LIBS $OPENSSL_LIBS $LIBGNUTLS_LIBS $HOWL_LIBS $BONJOUR_LIBS $AVAHI_LIBS $RESOLVER_LIBS"
AC_SUBST(LIBGNOMEVFS_CFLAGS)
AC_SUBST(LIBGNOMEVFS_LIBS)
@@ -1327,7 +1377,7 @@
IPv6 support: $have_ipv6
SSL support: $msg_ssl
Avahi support: $msg_avahi
- Howl support: $msg_howl
+ Zeroconf support: $msg_zeroconf
HAL support: $msg_hal
SELinux support: $msg_selinux
File ACL backends: $acl_backends
--- libgnomevfs/gnome-vfs-dns-sd.c
+++ libgnomevfs/gnome-vfs-dns-sd.c
@@ -52,6 +52,11 @@
#include <howl.h>
#endif
+/* Only one of HAVE_HOWL and HAVE_BONJOUR can be defined */
+#ifdef HAVE_BONJOUR
+# include <dns_sd.h>
+#endif
+
#define PATH_GCONF_GNOME_VFS_DNS_SD "/system/dns_sd"
#define PATH_GCONF_GNOME_VFS_DNS_SD_EXTRA_DOMAINS "/system/dns_sd/extra_domains"
@@ -839,6 +844,40 @@
#endif /* HAVE_HOWL */
+#ifdef HAVE_BONJOUR
+
+static gboolean
+bonjour_input (GIOChannel *io_channel,
+ GIOCondition cond,
+ gpointer callback_data)
+{
+ DNSServiceRef session;
+
+ session = callback_data;
+ DNSServiceProcessResult (session);
+
+ return TRUE;
+}
+
+static guint
+set_up_bonjour_session (DNSServiceRef session)
+{
+ int fd;
+ GIOChannel *channel;
+ guint watch_id;
+
+ fd = DNSServiceRefSockFD (session);
+
+ channel = g_io_channel_unix_new (fd);
+ watch_id = g_io_add_watch (channel,
+ G_IO_IN,
+ bonjour_input, session);
+ g_io_channel_unref (channel);
+ return watch_id;
+}
+
+#endif /* HAVE_BONJOUR */
+
struct GnomeVFSDNSSDBrowseHandle {
char *domain;
char *type;
@@ -858,6 +897,12 @@
#ifdef HAVE_HOWL
sw_discovery_oid howl_id;
#endif
+
+#ifdef HAVE_BONJOUR
+ gboolean is_bonjour;
+ DNSServiceRef bonjour_session;
+ guint bonjour_input_id;
+#endif
/* unicast data: */
int n_services;
@@ -885,6 +930,14 @@
if (handle->callback_data_destroy_func != NULL)
handle->callback_data_destroy_func (handle->callback_data);
+
+#ifdef HAVE_BONJOUR
+ if (handle->is_bonjour) {
+ if (handle->bonjour_input_id != 0)
+ g_source_remove (handle->bonjour_input_id);
+ DNSServiceRefDeallocate (handle->bonjour_session);
+ }
+#endif
g_free (handle);
}
@@ -966,9 +1019,9 @@
}
#endif
-#ifdef HAVE_HOWL
+#if defined (HAVE_HOWL) || defined (HAVE_BONJOUR)
-struct howl_browse_idle_data {
+struct zc_browse_idle_data {
GnomeVFSDNSSDBrowseHandle *handle;
GnomeVFSDNSSDServiceStatus status;
GnomeVFSDNSSDService service;
@@ -977,9 +1030,9 @@
static gboolean
-howl_browse_idle (gpointer data)
+zc_browse_idle (gpointer data)
{
- struct howl_browse_idle_data *idle_data;
+ struct zc_browse_idle_data *idle_data;
GnomeVFSDNSSDBrowseHandle *handle;
idle_data = data;
@@ -997,7 +1050,7 @@
}
static void
-browse_idle_data_free (struct howl_browse_idle_data *idle_data)
+browse_idle_data_free (struct zc_browse_idle_data *idle_data)
{
g_free (idle_data->service.name);
g_free (idle_data->service.type);
@@ -1012,6 +1065,10 @@
return FALSE;
}
+#endif
+
+#ifdef HAVE_HOWL
+
static sw_result
howl_browse_reply (sw_discovery discovery,
sw_discovery_oid oid,
@@ -1023,7 +1080,7 @@
sw_opaque extra)
{
GnomeVFSDNSSDBrowseHandle *handle;
- struct howl_browse_idle_data *idle_data;
+ struct zc_browse_idle_data *idle_data;
int len;
handle = extra;
@@ -1038,7 +1095,7 @@
if (handle->cancelled)
return SW_OKAY;
- idle_data = g_new (struct howl_browse_idle_data, 1);
+ idle_data = g_new (struct zc_browse_idle_data, 1);
idle_data->handle = handle;
if (status == SW_DISCOVERY_BROWSE_ADD_SERVICE) {
@@ -1064,7 +1121,7 @@
idle_data->service.domain[len-1] = 0;
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
- howl_browse_idle,
+ zc_browse_idle,
idle_data,
(GDestroyNotify) browse_idle_data_free);
return SW_OKAY;
@@ -1072,6 +1129,63 @@
#endif /* HAVE_HOWL */
+#ifdef HAVE_BONJOUR
+
+static void
+bonjour_browse_reply (DNSServiceRef session,
+ DNSServiceFlags flags,
+ uint32_t interface_index,
+ DNSServiceErrorType error_code,
+ const char *name,
+ const char *type,
+ const char *domain,
+ void *context)
+{
+ GnomeVFSDNSSDBrowseHandle *handle;
+ struct zc_browse_idle_data *idle_data;
+ int len;
+
+ handle = context;
+
+ if (error_code != kDNSServiceErr_NoError) {
+ /* free in an idle to make sure the other idles are done,
+ and to give sane environment for destroy callback */
+ g_idle_add (free_browse_handle_idle, handle);
+ return;
+ }
+
+ if (handle->cancelled)
+ return;
+
+ idle_data = g_new (struct zc_browse_idle_data, 1);
+ idle_data->handle = handle;
+
+ if (flags & kDNSServiceFlagsAdd) {
+ idle_data->status = GNOME_VFS_DNS_SD_SERVICE_ADDED;
+ } else {
+ idle_data->status = GNOME_VFS_DNS_SD_SERVICE_REMOVED;
+ }
+
+ idle_data->service.name = g_strdup (name);
+ idle_data->service.type = g_strdup (type);
+ idle_data->service.domain = g_strdup (domain);
+
+ /* We don't want last dots in the domain or type */
+ len = strlen (idle_data->service.type);
+ if (len > 0 && idle_data->service.type[len-1] == '.')
+ idle_data->service.type[len-1] = 0;
+ len = strlen (idle_data->service.domain);
+ if (len > 0 && idle_data->service.domain[len-1] == '.')
+ idle_data->service.domain[len-1] = 0;
+
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ zc_browse_idle,
+ idle_data,
+ (GDestroyNotify) browse_idle_data_free);
+}
+
+#endif /* HAVE_BONJOUR */
+
/**
* gnome_vfs_dns_sd_browse:
* @handle: pointer to a pointer to a #GnomeVFSDNSSDBrowseHandle object.
@@ -1154,8 +1268,32 @@
}
return GNOME_VFS_ERROR_GENERIC;
#else
+# ifdef HAVE_BONJOUR
+ DNSServiceErrorType res;
+
+ handle->is_local = TRUE;
+ handle->is_bonjour = TRUE;
+
+ res = DNSServiceBrowse (&handle->bonjour_session,
+ 0 /* flags (none needed) */,
+ 0 /* interface (-1 for local, 0 for all) */,
+ type,
+ domain,
+ bonjour_browse_reply,
+ handle);
+
+ if (res != kDNSServiceErr_NoError) {
+ return GNOME_VFS_ERROR_GENERIC;
+ }
+
+ handle->bonjour_input_id = set_up_bonjour_session (handle->bonjour_session);
+
+ *handle_out = handle;
+ return GNOME_VFS_OK;
+# else
free_browse_handle (handle);
return GNOME_VFS_ERROR_NOT_SUPPORTED;
+# endif
#endif
} else {
handle->is_local = FALSE;
@@ -1192,6 +1330,12 @@
handle->cancelled = TRUE;
sw_discovery_cancel (get_global_howl_session (), handle->howl_id);
#endif
+#ifdef HAVE_BONJOUR
+ handle->cancelled = TRUE;
+ g_source_remove (handle->bonjour_input_id);
+ handle->bonjour_input_id = 0;
+ g_idle_add (free_browse_handle_idle, handle);
+#endif
return GNOME_VFS_OK;
} else {
if (handle->finished)
@@ -1226,6 +1370,12 @@
sw_discovery_oid howl_id;
guint timeout_tag;
#endif
+#ifdef HAVE_BONJOUR
+ gboolean is_bonjour;
+ DNSServiceRef bonjour_session;
+ guint bonjour_input_id;
+ guint timeout_tag;
+#endif
/* unicast data: */
gboolean cancelled;
@@ -1246,7 +1396,15 @@
if (handle->callback_data_destroy_func != NULL)
handle->callback_data_destroy_func (handle->callback_data);
-
+
+#ifdef HAVE_BONJOUR
+ if (handle->is_bonjour) {
+ if (handle->bonjour_input_id != 0)
+ g_source_remove (handle->bonjour_input_id);
+ DNSServiceRefDeallocate (handle->bonjour_session);
+ }
+#endif
+
g_free (handle);
}
@@ -1368,10 +1526,10 @@
#endif
+#if defined (HAVE_HOWL) || defined (HAVE_BONJOUR)
-#ifdef HAVE_HOWL
static gboolean
-howl_resolve_idle (gpointer data)
+zc_resolve_idle (gpointer data)
{
GnomeVFSDNSSDResolveHandle *handle;
GnomeVFSDNSSDService service;
@@ -1405,7 +1563,9 @@
return FALSE;
}
+#endif
+#ifdef HAVE_HOWL
static sw_result
howl_resolve_reply (sw_discovery discovery,
@@ -1438,7 +1598,7 @@
g_source_remove (handle->timeout_tag);
handle->idle_tag = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
- howl_resolve_idle,
+ zc_resolve_idle,
handle,
(GDestroyNotify) NULL);
return SW_OKAY;
@@ -1476,6 +1636,98 @@
#endif
+#ifdef HAVE_BONJOUR
+
+static void
+bonjour_resolve_reply (DNSServiceRef session,
+ DNSServiceFlags flags,
+ uint32_t interface_index,
+ DNSServiceErrorType error_code,
+ const char *full_name,
+ const char *host_name,
+ uint16_t port,
+ uint16_t text_record_len,
+ const char *text_record,
+ void *context)
+{
+ GnomeVFSDNSSDResolveHandle *handle;
+ gint host_len, domain_len;
+
+ handle = context;
+
+ g_assert (handle->idle_tag == 0);
+
+ handle->host = g_strdup (host_name);
+ handle->port = g_ntohs (port);
+ handle->text = g_memdup (text_record, text_record_len);
+ handle->text_len = text_record_len;
+
+ domain_len = strlen (handle->domain);
+ host_len = strlen (handle->host);
+
+ /* The hostname includes the .local domain and a trailing dot. Strip it. */
+
+ /* hostname.[domain.] */
+ if (host_len > domain_len && !strcmp (handle->host + host_len - domain_len, handle->domain) &&
+ handle->host [host_len - domain_len - 1] == '.') {
+ handle->host [host_len - domain_len - 1] = 0;
+ host_len -= domain_len - 1;
+ } else if (host_len > 0 && handle->host [host_len - 1] == '.') {
+ handle->host [host_len - 1] = 0;
+ host_len--;
+
+ /* hostname.[domain] */
+ if (host_len > domain_len && !strcmp (handle->host + host_len - domain_len, handle->domain) &&
+ handle->host [host_len - domain_len - 1] == '.') {
+ handle->host [host_len - domain_len - 1] = 0;
+ host_len -= domain_len - 1;
+ }
+ }
+
+ /* We want no more replies */
+ if (handle->is_bonjour) {
+ if (handle->bonjour_input_id != 0) {
+ g_source_remove (handle->bonjour_input_id);
+ handle->bonjour_input_id = 0;
+ }
+ DNSServiceRefDeallocate (handle->bonjour_session);
+ handle->is_bonjour = FALSE;
+ }
+
+ g_source_remove (handle->timeout_tag);
+
+ handle->idle_tag = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ zc_resolve_idle,
+ handle,
+ (GDestroyNotify) NULL);
+}
+
+static gboolean
+bonjour_resolve_timeout (gpointer data)
+{
+ GnomeVFSDNSSDResolveHandle *handle;
+
+ handle = data;
+
+ handle->callback (handle,
+ GNOME_VFS_ERROR_HOST_NOT_FOUND,
+ NULL,
+ NULL, 0,
+ NULL, 0, NULL,
+ handle->callback_data);
+
+ if (handle->idle_tag) {
+ /* We already resolved, but the idle hasn't run yet */
+ g_source_remove (handle->idle_tag);
+ }
+
+ free_resolve_handle (handle);
+
+ return FALSE;
+}
+
+#endif /* HAVE_BONJOUR */
+
/**
* gnome_vfs_dns_sd_resolve:
* @handle: pointer to a pointer to a #GnomeVFSDNSSDResolveHandle object.
@@ -1569,7 +1821,38 @@
}
return GNOME_VFS_ERROR_GENERIC;
#else
+# ifdef HAVE_BONJOUR
+ DNSServiceErrorType res;
+
+ handle->is_local = TRUE;
+ handle->is_bonjour = TRUE;
+
+ res = DNSServiceResolve (&handle->bonjour_session,
+ 0 /* flags (none needed) */,
+ 0 /* interface (-1 for local, 0 for all) */,
+ name,
+ type,
+ domain,
+ bonjour_resolve_reply,
+ handle);
+
+ if (res != kDNSServiceErr_NoError) {
+ return GNOME_VFS_ERROR_GENERIC;
+ }
+
+ handle->bonjour_input_id = set_up_bonjour_session (handle->bonjour_session);
+
+ if (timeout != 0) {
+ handle->timeout_tag = g_timeout_add (timeout,
+ bonjour_resolve_timeout,
+ handle);
+ }
+
+ *handle_out = handle;
+ return GNOME_VFS_OK;
+# else
return GNOME_VFS_ERROR_NOT_SUPPORTED;
+# endif
#endif
} else {
handle->is_local = FALSE;
@@ -1614,7 +1897,14 @@
handle->howl_id);
}
free_resolve_handle (handle);
-
+#endif
+#ifdef HAVE_BONJOUR
+ g_source_remove (handle->timeout_tag);
+ if (handle->idle_tag) {
+ /* We already resolved, but the idle hasn't run yet */
+ g_source_remove (handle->idle_tag);
+ }
+ free_resolve_handle (handle);
#endif
return GNOME_VFS_OK;
} else {
@@ -1623,7 +1913,7 @@
}
}
-#if defined(HAVE_AVAHI) || defined(HAVE_HOWL)
+#if defined(HAVE_AVAHI) || defined(HAVE_HOWL) || defined (HAVE_BONJOUR)
static int
find_existing_service (GArray *array,
const char *name,
@@ -1794,6 +2084,115 @@
}
#endif /* HAVE_HOWL */
+#ifdef HAVE_BONJOUR
+
+static void
+bonjour_run_sync (DNSServiceRef session, gint timeout_msec, gboolean *stop_processing_flag)
+{
+ struct timeval duration_tv, end_tv, tv;
+
+ gettimeofday (&end_tv, NULL);
+ tv = end_tv;
+
+ end_tv.tv_sec += timeout_msec / 1000;
+ end_tv.tv_usec += (timeout_msec % 1000) * 1000;
+ end_tv.tv_sec += end_tv.tv_usec / 1000000;
+ end_tv.tv_usec %= 1000000;
+
+ while ((end_tv.tv_sec > tv.tv_sec ||
+ (end_tv.tv_sec == tv.tv_sec && end_tv.tv_usec > tv.tv_usec)) &&
+ !(stop_processing_flag && *stop_processing_flag)) {
+ gint n_ready;
+ fd_set read_fds;
+ gint fd;
+
+
+ duration_tv.tv_sec = end_tv.tv_sec - tv.tv_sec;
+ if (tv.tv_usec <= end_tv.tv_usec) {
+ duration_tv.tv_usec = end_tv.tv_usec - tv.tv_usec;
+ } else {
+ duration_tv.tv_sec--;
+ duration_tv.tv_usec = end_tv.tv_usec + 1000000 - tv.tv_usec;
+ }
+
+ fd = DNSServiceRefSockFD (session);
+ if (fd < 0)
+ break;
+
+ FD_ZERO (&read_fds);
+ FD_SET (fd, &read_fds);
+
+ n_ready = select (fd + 1, &read_fds, NULL, NULL, &duration_tv);
+ gettimeofday (&tv, NULL);
+
+ if (n_ready < 1)
+ continue;
+
+ DNSServiceProcessResult (session);
+ }
+}
+
+static void
+bonjour_browse_reply_sync (DNSServiceRef session,
+ DNSServiceFlags flags,
+ uint32_t interface_index,
+ DNSServiceErrorType error_code,
+ const char *name,
+ const char *type,
+ const char *domain,
+ void *context)
+{
+ GnomeVFSDNSSDService service, *existing;
+ GArray *array;
+ int i, len;
+ gboolean free_service;
+
+ array = context;
+ if (error_code != kDNSServiceErr_NoError)
+ return;
+
+ free_service = TRUE;
+ service.name = g_strdup (name);
+ service.type = g_strdup (type);
+ service.domain = g_strdup (domain);
+
+ /* We don't want last dots in the domain or type */
+ len = strlen (service.type);
+ if (len > 0 && service.type[len-1] == '.')
+ service.type[len-1] = 0;
+ len = strlen (service.domain);
+ if (len > 0 && service.domain[len-1] == '.')
+ service.domain[len-1] = 0;
+
+ if (flags & kDNSServiceFlagsAdd) {
+ if (find_existing_service (array, service.name, service.type,
+ service.domain) == -1) {
+ free_service = FALSE;
+ g_array_append_val (array, service);
+ }
+ } else {
+ i = find_existing_service (array, service.name, service.type,
+ service.domain);
+ if (i != -1) {
+ existing = &g_array_index (array, GnomeVFSDNSSDService,
+ i);
+ g_free (existing->name);
+ g_free (existing->type);
+ g_free (existing->domain);
+ g_array_remove_index (array, i);
+ }
+ }
+
+ if (free_service) {
+ g_free (service.name);
+ g_free (service.type);
+ g_free (service.domain);
+ }
+}
+
+#endif /* HAVE_BONJOUR */
+
+
/**
* gnome_vfs_dns_sd_browse_sync:
* @domain: The dns domain to browse, or "local" for multicast DNS.
@@ -1946,7 +2345,32 @@
return GNOME_VFS_OK;
#else
+# ifdef HAVE_BONJOUR
+ DNSServiceRef session;
+ DNSServiceErrorType error_code;
+ GArray *array;
+
+ array = g_array_new (FALSE, FALSE, sizeof (GnomeVFSDNSSDService));
+ error_code = DNSServiceBrowse (&session,
+ 0 /* flags (none needed) */,
+ 0 /* interface (-1 for local, 0 for all) */,
+ type,
+ domain,
+ bonjour_browse_reply_sync,
+ array);
+ if (error_code != kDNSServiceErr_NoError) {
+ g_warning ("gnome_vfs_dns_sd_browse_sync - bonjour browse failed\n");
+ g_array_free (array, TRUE);
+ return GNOME_VFS_ERROR_GENERIC;
+ }
+
+ bonjour_run_sync (session, timeout_msec, NULL);
+
+ DNSServiceRefDeallocate (session);
+ return GNOME_VFS_OK;
+# else
return GNOME_VFS_ERROR_NOT_SUPPORTED;
+# endif
#endif
} else {
return unicast_browse_sync (domain, type,
@@ -2012,14 +2436,18 @@
#endif
-#ifdef HAVE_HOWL
+#if defined HAVE_HOWL || defined (HAVE_BONJOUR)
struct sync_resolve_data {
gboolean got_data;
+ const char *domain;
char *host;
int port;
char *text;
int text_len;
};
+#endif
+
+#ifdef HAVE_HOWL
static sw_result
howl_resolve_reply_sync (sw_discovery discovery,
@@ -2048,6 +2476,55 @@
}
#endif
+#ifdef HAVE_BONJOUR
+
+static void
+bonjour_resolve_reply_sync (DNSServiceRef session,
+ DNSServiceFlags flags,
+ uint32_t interface_index,
+ DNSServiceErrorType error_code,
+ const char *full_name,
+ const char *host_name,
+ uint16_t port,
+ uint16_t text_record_len,
+ const char *text_record,
+ void *context)
+{
+ struct sync_resolve_data *data;
+ gint host_len, domain_len;
+
+ data = context;
+ data->got_data = TRUE;
+
+ data->host = g_strdup (host_name);
+ data->port = g_ntohs (port);
+ data->text = g_memdup (text_record, text_record_len);
+ data->text_len = text_record_len;
+
+ domain_len = strlen (data->domain);
+ host_len = strlen (data->host);
+
+ /* The hostname includes the .local domain and a trailing dot. Strip it. */
+ /* hostname.[domain.] */
+ if (host_len > domain_len && !strcmp (data->host + host_len - domain_len, data->domain) &&
+ data->host [host_len - domain_len - 1] == '.') {
+ data->host [host_len - domain_len - 1] = 0;
+ host_len -= domain_len - 1;
+ } else if (host_len > 0 && data->host [host_len - 1] == '.') {
+ data->host [host_len - 1] = 0;
+ host_len--;
+
+ /* hostname.[domain] */
+ if (host_len > domain_len && !strcmp (data->host + host_len - domain_len, data->domain) &&
+ data->host [host_len - domain_len - 1] == '.') {
+ data->host [host_len - domain_len - 1] = 0;
+ host_len -= domain_len - 1;
+ }
+ }
+}
+
+#endif /* HAVE_BONJOUR */
+
/**
* gnome_vfs_dns_sd_resolve_sync:
* @name: name of the service to resolve in UTF-8 encoding.
@@ -2211,7 +2688,49 @@
return GNOME_VFS_ERROR_HOST_NOT_FOUND;
#else
+# ifdef HAVE_BONJOUR
+ DNSServiceRef session;
+ DNSServiceErrorType error_code;
+ struct sync_resolve_data resolve_data = {0};
+
+ resolve_data.domain = domain;
+
+ error_code = DNSServiceResolve (&session,
+ 0 /* flags (none needed) */,
+ 0 /* interface (-1 for local, 0
+ for all) */,
+ name,
+ type,
+ domain,
+ bonjour_resolve_reply_sync,
+ &resolve_data);
+ if (error_code != kDNSServiceErr_NoError) {
+ g_warning ("gnome_vfs_dns_sd_resolve_sync - bonjour resolve failed\n");
+ return GNOME_VFS_ERROR_GENERIC;
+ }
+
+ bonjour_run_sync (session, timeout_msec, &resolve_data.got_data);
+
+ DNSServiceRefDeallocate (session);
+
+ if (resolve_data.got_data) {
+ *host = resolve_data.host;
+ *port = resolve_data.port;
+ if (text != NULL)
+ *text = decode_txt_record (resolve_data.text, resolve_data.text_len);
+ if (text_raw_len_out != NULL && text_raw_out) {
+ *text_raw_len_out = resolve_data.text_len;
+ *text_raw_out = resolve_data.text;
+ } else {
+ g_free (resolve_data.text);
+ }
+ return GNOME_VFS_OK;
+ }
+
+ return GNOME_VFS_ERROR_HOST_NOT_FOUND;
+# else
return GNOME_VFS_ERROR_NOT_SUPPORTED;
+# endif
#endif
} else {
res = unicast_resolve_sync (name, type, domain,
--- modules/Makefile.am
+++ modules/Makefile.am
@@ -7,6 +7,7 @@
$(MODULES_XML_GCONF_CFLAGS) \
$(MODULES_FILE_CFLAGS) \
$(HOWL_CFLAGS) \
+ $(BONJOUR_CFLAGS) \
$(AVAHI_CFLAGS) \
$(LIBEFS_CFLAGS) \
$(SAMBA_CFLAGS) \
@@ -115,7 +116,7 @@
libdns_sd_la_SOURCES = dns-sd-method.c
libdns_sd_la_LDFLAGS = $(module_flags)
-libdns_sd_la_LIBADD = $(MODULES_LIBS) $(HOWL_LIBS) $(AVAHI_LIBS) ../libgnomevfs/libgnomevfs-2.la
+libdns_sd_la_LIBADD = $(MODULES_LIBS) $(HOWL_LIBS) $(BONJOUR_LIBS) $(AVAHI_LIBS) ../libgnomevfs/libgnomevfs-2.la
### `file' method
--- modules/dns-sd-method.c
+++ modules/dns-sd-method.c
@@ -45,6 +45,11 @@
#include <howl.h>
#endif
+/* Only one of HAVE_HOWL and HAVE_BONJOUR can be defined */
+#ifdef HAVE_BONJOUR
+# include <dns_sd.h>
+#endif
+
#include <libgnomevfs/gnome-vfs-ops.h>
#include <libgnomevfs/gnome-vfs-directory.h>
#include <libgnomevfs/gnome-vfs-module-shared.h>
@@ -71,12 +76,12 @@
{"_sftp-ssh._tcp", "sftp", "gnome-fs-ssh"},
};
-#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI) || defined (HAVE_BONJOUR)
G_LOCK_DEFINE_STATIC (local);
static gboolean started_local = FALSE;
static GList *local_files = NULL;
static GList *local_monitors = NULL;
-#endif /* HAVE_HOWL || HAVE_AVAHI */
+#endif /* HAVE_HOWL || HAVE_AVAHI || HAVE_BONJOUR*/
typedef struct {
char *data;
@@ -226,7 +231,7 @@
return g_string_free (string, FALSE);
}
-#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI) || defined (HAVE_BONJOUR)
static void
call_monitors (gboolean add, char *filename)
{
@@ -312,7 +317,7 @@
G_UNLOCK (local);
}
-#endif /* HAVE_HOWL || HAVE_AVAHI */
+#endif /* HAVE_HOWL || HAVE_AVAHI || HAVE_BONJOUR*/
#ifdef HAVE_AVAHI
@@ -535,10 +540,130 @@
sw_discovery_fina (session);
}
}
+
#endif /* HAVE_HOWL */
+#ifdef HAVE_BONJOUR
+
+static void
+local_browse_callback_sync (DNSServiceRef session,
+ DNSServiceFlags flags,
+ uint32_t interface_index,
+ DNSServiceErrorType error_code,
+ const char *name,
+ const char *type,
+ const char *domain,
+ void *context)
+{
+ if (flags & kDNSServiceFlagsAdd)
+ local_browse (TRUE, name, type, domain);
+ else
+ local_browse (FALSE, name, type, domain);
+}
+
+static void
+bonjour_run_multi_sync (DNSServiceRef *session_handles, gint n_sessions, gint timeout_msec)
+{
+ struct timeval duration_tv, end_tv, tv;
+
+ gettimeofday (&end_tv, NULL);
+ tv = end_tv;
+
+ end_tv.tv_sec += timeout_msec / 1000;
+ end_tv.tv_usec += (timeout_msec % 1000) * 1000;
+ end_tv.tv_sec += end_tv.tv_usec / 1000000;
+ end_tv.tv_usec %= 1000000;
+
+ while (end_tv.tv_sec > tv.tv_sec ||
+ (end_tv.tv_sec == tv.tv_sec && end_tv.tv_usec > tv.tv_usec)) {
+ gint n_ready;
+ fd_set read_fds;
+ gint high_fd = 0;
+ gint i;
+
+ duration_tv.tv_sec = end_tv.tv_sec - tv.tv_sec;
+ if (tv.tv_usec <= end_tv.tv_usec) {
+ duration_tv.tv_usec = end_tv.tv_usec - tv.tv_usec;
+ } else {
+ duration_tv.tv_sec--;
+ duration_tv.tv_usec = end_tv.tv_usec + 1000000 - tv.tv_usec;
+ }
+
+ FD_ZERO (&read_fds);
+
+ for (i = 0; i < n_sessions; i++) {
+ gint fd;
+
+ fd = DNSServiceRefSockFD (session_handles [i]);
+ if (fd < 0)
+ continue;
+
+ FD_SET (fd, &read_fds);
+ high_fd = MAX (fd, high_fd);
+ }
+
+ n_ready = select (high_fd + 1, &read_fds, NULL, NULL, &duration_tv);
+ gettimeofday (&tv, NULL);
+
+ if (n_ready < 1)
+ continue;
+ for (i = 0; i < n_sessions; i++) {
+ gint fd;
+ fd = DNSServiceRefSockFD (session_handles [i]);
+
+ if (FD_ISSET (fd, &read_fds))
+ DNSServiceProcessResult (session_handles [i]);
+ }
+ }
+}
+
+static void
+init_local (void)
+{
+ int i;
+ GnomeVFSResult res;
+
+ if (!started_local) {
+ DNSServiceRef *session_handles;
+
+ started_local = TRUE;
+
+ for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++) {
+ GnomeVFSDNSSDBrowseHandle *handle;
+ res = gnome_vfs_dns_sd_browse (&handle,
+ "local",
+ dns_sd_types [i].type,
+ local_browse_callback,
+ NULL, NULL);
+ if (res == GNOME_VFS_OK) {
+ dns_sd_types [i].handle = handle;
+ }
+ }
+
+ session_handles = g_new0 (DNSServiceRef, G_N_ELEMENTS (dns_sd_types));
+
+ for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++) {
+ DNSServiceBrowse (&session_handles [i],
+ 0 /* flags (none needed) */,
+ 0 /* interface (-1 for local, 0 for all) */,
+ dns_sd_types [i].type,
+ "local",
+ local_browse_callback_sync,
+ NULL);
+ }
+
+ bonjour_run_multi_sync (session_handles, G_N_ELEMENTS (dns_sd_types),
+ LOCAL_SYNC_BROWSE_DELAY_MSEC);
+
+ for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++) {
+ DNSServiceRefDeallocate (session_handles [i]);
+ }
+ }
+}
+
+#endif
static GnomeVFSResult
do_open (GnomeVFSMethod *method,
@@ -827,7 +952,7 @@
}
}
-#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI) || defined (HAVE_BONJOUR)
static void
directory_handle_add_filenames (DirectoryHandle *dir_handle, GList *files)
{
@@ -836,7 +961,7 @@
files = files->next;
}
}
-#endif /* HAVE_HOWL || HAVE_AVAHI */
+#endif /* HAVE_HOWL || HAVE_AVAHI || HAVE_BONJOUR*/
static GnomeVFSResult
do_open_directory (GnomeVFSMethod *method,
@@ -866,14 +991,14 @@
dir_handle = directory_handle_new (options);
if (strcmp (domain, "local") == 0) {
-#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI) || defined (HAVE_BONJOUR)
G_LOCK (local);
init_local ();
directory_handle_add_filenames (dir_handle, local_files);
G_UNLOCK (local);
-#endif /* HAVE_HOWL || HAVE_AVAHI */
+#endif /* HAVE_HOWL || HAVE_AVAHI || HAVE_BONJOUR */
} else {
for (i=0; i < G_N_ELEMENTS (dns_sd_types); i++) {
int n_services;
@@ -1140,7 +1265,7 @@
return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
-#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI) || defined (HAVE_BONJOUR)
if (strcmp (uri->text, "") == 0 ||
strcmp (uri->text, "/") == 0) {
int *handle;
@@ -1158,7 +1283,7 @@
return GNOME_VFS_OK;
} else
-#endif /* HAVE_HOWL || HAVE_AVAHI */
+#endif /* HAVE_HOWL || HAVE_AVAHI || HAVE_BONJOUR */
return GNOME_VFS_ERROR_NOT_SUPPORTED;
}
@@ -1166,7 +1291,7 @@
do_monitor_cancel (GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle)
{
-#if defined (HAVE_HOWL) || defined (HAVE_AVAHI)
+#if defined (HAVE_HOWL) || defined (HAVE_AVAHI) || defined (HAVE_BONJOUR)
G_LOCK (local);
local_monitors = g_list_remove (local_monitors, method_handle);
@@ -1177,7 +1302,7 @@
return GNOME_VFS_OK;
#else
return GNOME_VFS_ERROR_NOT_SUPPORTED;
-#endif /* HAVE_HOWL || HAVE_AVAHI */
+#endif /* HAVE_HOWL || HAVE_AVAHI || HAVE_BONJOUR */
}