diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 17:06:32 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 17:06:32 +0000 |
commit | 2dad5357405ad33cfa792f04b3ab62a5d188841e (patch) | |
tree | b8f8893942060fe3cfb04ac374cda96fdfc8f453 /src/remmina_avahi.c | |
parent | Initial commit. (diff) | |
download | remmina-2dad5357405ad33cfa792f04b3ab62a5d188841e.tar.xz remmina-2dad5357405ad33cfa792f04b3ab62a5d188841e.zip |
Adding upstream version 1.4.34+dfsg.upstream/1.4.34+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/remmina_avahi.c')
-rw-r--r-- | src/remmina_avahi.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/remmina_avahi.c b/src/remmina_avahi.c new file mode 100644 index 0000000..e51cfbf --- /dev/null +++ b/src/remmina_avahi.c @@ -0,0 +1,300 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2009-2010 Vic Lee + * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo + * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. * If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. * If you + * do not wish to do so, delete this exception statement from your + * version. * If you delete this exception statement from all source + * files in the program, then also delete it here. + * + */ + +#include "config.h" +#include "remmina_avahi.h" +#include "remmina/remmina_trace_calls.h" + +#ifdef HAVE_LIBAVAHI_CLIENT + +#include <avahi-client/client.h> +#include <avahi-client/lookup.h> +#include <avahi-common/simple-watch.h> +#include <avahi-common/malloc.h> +#include <avahi-common/error.h> + +struct _RemminaAvahiPriv { + AvahiSimplePoll* simple_poll; + AvahiClient* client; + AvahiServiceBrowser* sb; + guint iterate_handler; + gboolean has_event; +}; + +static void +remmina_avahi_resolve_callback( + AvahiServiceResolver* r, + AVAHI_GCC_UNUSED AvahiIfIndex interface, + AVAHI_GCC_UNUSED AvahiProtocol protocol, + AvahiResolverEvent event, + const char* name, + const char* type, + const char* domain, + const char* host_name, + const AvahiAddress* address, + uint16_t port, + AvahiStringList* txt, + AvahiLookupResultFlags flags, + AVAHI_GCC_UNUSED void* userdata) +{ + TRACE_CALL(__func__); + gchar* key; + gchar* value; + RemminaAvahi* ga = (RemminaAvahi*)userdata; + + assert(r); + + ga->priv->has_event = TRUE; + + switch (event) { + case AVAHI_RESOLVER_FAILURE: + g_print("(remmina-applet 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)))); + break; + + case AVAHI_RESOLVER_FOUND: + key = g_strdup_printf("%s,%s,%s", name, type, domain); + if (g_hash_table_lookup(ga->discovered_services, key)) { + g_free(key); + break; + } + value = g_strdup_printf("[%s]:%i", host_name, port); + g_hash_table_insert(ga->discovered_services, key, value); + /* key and value will be freed with g_free when the has table is freed */ + + g_print("(remmina-applet avahi-resolver) Added service '%s'\n", value); + + break; + } + + avahi_service_resolver_free(r); +} + +static void +remmina_avahi_browse_callback( + AvahiServiceBrowser* b, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char* name, + const char* type, + const char* domain, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, + void* userdata) +{ + TRACE_CALL(__func__); + gchar* key; + RemminaAvahi* ga = (RemminaAvahi*)userdata; + + assert(b); + + ga->priv->has_event = TRUE; + + switch (event) { + case AVAHI_BROWSER_FAILURE: + g_print("(remmina-applet avahi-browser) %s\n", + avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); + return; + + case AVAHI_BROWSER_NEW: + key = g_strdup_printf("%s,%s,%s", name, type, domain); + if (g_hash_table_lookup(ga->discovered_services, key)) { + g_free(key); + break; + } + g_free(key); + + g_print("(remmina-applet avahi-browser) Found service '%s' of type '%s' in domain '%s'\n", name, type, domain); + + if (!(avahi_service_resolver_new(ga->priv->client, interface, protocol, name, type, domain, + AVAHI_PROTO_UNSPEC, 0, remmina_avahi_resolve_callback, ga))) { + g_print("(remmina-applet avahi-browser) Failed to resolve service '%s': %s\n", + name, avahi_strerror(avahi_client_errno(ga->priv->client))); + } + break; + + case AVAHI_BROWSER_REMOVE: + g_print("(remmina-applet avahi-browser) Removed service '%s' of type '%s' in domain '%s'\n", name, type, domain); + key = g_strdup_printf("%s,%s,%s", name, type, domain); + g_hash_table_remove(ga->discovered_services, key); + g_free(key); + break; + + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; + } +} + +static void remmina_avahi_client_callback(AvahiClient* c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) +{ + TRACE_CALL(__func__); + RemminaAvahi* ga = (RemminaAvahi*)userdata; + + ga->priv->has_event = TRUE; + + if (state == AVAHI_CLIENT_FAILURE) { + g_print("(remmina-applet avahi) Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c))); + } +} + +static gboolean remmina_avahi_iterate(RemminaAvahi* ga) +{ + TRACE_CALL(__func__); + while (TRUE) { + /* Call the iteration until no further events */ + ga->priv->has_event = FALSE; + avahi_simple_poll_iterate(ga->priv->simple_poll, 0); + if (!ga->priv->has_event) + break; + } + + return TRUE; +} + +RemminaAvahi* remmina_avahi_new(void) +{ + TRACE_CALL(__func__); + RemminaAvahi* ga; + + ga = g_new(RemminaAvahi, 1); + ga->discovered_services = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + ga->started = FALSE; + ga->priv = g_new(RemminaAvahiPriv, 1); + ga->priv->simple_poll = NULL; + ga->priv->client = NULL; + ga->priv->sb = NULL; + ga->priv->iterate_handler = 0; + ga->priv->has_event = FALSE; + + return ga; +} + +void remmina_avahi_start(RemminaAvahi* ga) +{ + TRACE_CALL(__func__); + int error; + + if (ga->started) + return; + + ga->started = TRUE; + + ga->priv->simple_poll = avahi_simple_poll_new(); + if (!ga->priv->simple_poll) { + g_print("Failed to create simple poll object.\n"); + return; + } + + ga->priv->client = avahi_client_new(avahi_simple_poll_get(ga->priv->simple_poll), 0, remmina_avahi_client_callback, ga, + &error); + if (!ga->priv->client) { + g_print("Failed to create client: %s\n", avahi_strerror(error)); + return; + } + + /** @todo Customize the default domain here */ + ga->priv->sb = avahi_service_browser_new(ga->priv->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_rfb._tcp", NULL, 0, + remmina_avahi_browse_callback, ga); + if (!ga->priv->sb) { + g_print("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(ga->priv->client))); + return; + } + + ga->priv->iterate_handler = g_timeout_add(5000, (GSourceFunc)remmina_avahi_iterate, ga); +} + +void remmina_avahi_stop(RemminaAvahi* ga) +{ + TRACE_CALL(__func__); + g_hash_table_remove_all(ga->discovered_services); + if (ga->priv->iterate_handler) { + g_source_remove(ga->priv->iterate_handler); + ga->priv->iterate_handler = 0; + } + if (ga->priv->sb) { + avahi_service_browser_free(ga->priv->sb); + ga->priv->sb = NULL; + } + if (ga->priv->client) { + avahi_client_free(ga->priv->client); + ga->priv->client = NULL; + } + if (ga->priv->simple_poll) { + avahi_simple_poll_free(ga->priv->simple_poll); + ga->priv->simple_poll = NULL; + } + ga->started = FALSE; +} + +void remmina_avahi_free(RemminaAvahi* ga) +{ + TRACE_CALL(__func__); + if (ga == NULL) + return; + + remmina_avahi_stop(ga); + + g_free(ga->priv); + g_hash_table_destroy(ga->discovered_services); + g_free(ga); +} + +#else + +RemminaAvahi* remmina_avahi_new(void) +{ + TRACE_CALL(__func__); + return NULL; +} + +void remmina_avahi_start(RemminaAvahi* ga) +{ + TRACE_CALL(__func__); +} + +void remmina_avahi_stop(RemminaAvahi* ga) +{ + TRACE_CALL(__func__); +} + +void remmina_avahi_free(RemminaAvahi* ga) +{ + TRACE_CALL(__func__); +} + +#endif + |