Remmina - The GTK+ Remote Desktop Client  v1.4.33
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
remmina_avahi.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2010 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  * In addition, as a special exception, the copyright holders give
23  * permission to link the code of portions of this program with the
24  * OpenSSL library under certain conditions as described in each
25  * individual source file, and distribute linked combinations
26  * including the two.
27  * You must obey the GNU General Public License in all respects
28  * for all of the code used other than OpenSSL. * If you modify
29  * file(s) with this exception, you may extend this exception to your
30  * version of the file(s), but you are not obligated to do so. * If you
31  * do not wish to do so, delete this exception statement from your
32  * version. * If you delete this exception statement from all source
33  * files in the program, then also delete it here.
34  *
35  */
36 
37 #include "config.h"
38 #include "remmina_avahi.h"
40 
41 #ifdef HAVE_LIBAVAHI_CLIENT
42 
43 #include <avahi-client/client.h>
44 #include <avahi-client/lookup.h>
45 #include <avahi-common/simple-watch.h>
46 #include <avahi-common/malloc.h>
47 #include <avahi-common/error.h>
48 
50  AvahiSimplePoll* simple_poll;
51  AvahiClient* client;
52  AvahiServiceBrowser* sb;
54  gboolean has_event;
55 };
56 
57 static void
59  AvahiServiceResolver* r,
60  AVAHI_GCC_UNUSED AvahiIfIndex interface,
61  AVAHI_GCC_UNUSED AvahiProtocol protocol,
62  AvahiResolverEvent event,
63  const char* name,
64  const char* type,
65  const char* domain,
66  const char* host_name,
67  const AvahiAddress* address,
68  uint16_t port,
69  AvahiStringList* txt,
70  AvahiLookupResultFlags flags,
71  AVAHI_GCC_UNUSED void* userdata)
72 {
73  TRACE_CALL(__func__);
74  gchar* key;
75  gchar* value;
76  RemminaAvahi* ga = (RemminaAvahi*)userdata;
77 
78  assert(r);
79 
80  ga->priv->has_event = TRUE;
81 
82  switch (event) {
83  case AVAHI_RESOLVER_FAILURE:
84  g_print("(remmina-applet avahi-resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n",
85  name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
86  break;
87 
88  case AVAHI_RESOLVER_FOUND:
89  key = g_strdup_printf("%s,%s,%s", name, type, domain);
90  if (g_hash_table_lookup(ga->discovered_services, key)) {
91  g_free(key);
92  break;
93  }
94  value = g_strdup_printf("[%s]:%i", host_name, port);
95  g_hash_table_insert(ga->discovered_services, key, value);
96  /* key and value will be freed with g_free when the has table is freed */
97 
98  g_print("(remmina-applet avahi-resolver) Added service '%s'\n", value);
99 
100  break;
101  }
102 
103  avahi_service_resolver_free(r);
104 }
105 
106 static void
108  AvahiServiceBrowser* b,
109  AvahiIfIndex interface,
110  AvahiProtocol protocol,
111  AvahiBrowserEvent event,
112  const char* name,
113  const char* type,
114  const char* domain,
115  AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
116  void* userdata)
117 {
118  TRACE_CALL(__func__);
119  gchar* key;
120  RemminaAvahi* ga = (RemminaAvahi*)userdata;
121 
122  assert(b);
123 
124  ga->priv->has_event = TRUE;
125 
126  switch (event) {
127  case AVAHI_BROWSER_FAILURE:
128  g_print("(remmina-applet avahi-browser) %s\n",
129  avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
130  return;
131 
132  case AVAHI_BROWSER_NEW:
133  key = g_strdup_printf("%s,%s,%s", name, type, domain);
134  if (g_hash_table_lookup(ga->discovered_services, key)) {
135  g_free(key);
136  break;
137  }
138  g_free(key);
139 
140  g_print("(remmina-applet avahi-browser) Found service '%s' of type '%s' in domain '%s'\n", name, type, domain);
141 
142  if (!(avahi_service_resolver_new(ga->priv->client, interface, protocol, name, type, domain,
143  AVAHI_PROTO_UNSPEC, 0, remmina_avahi_resolve_callback, ga))) {
144  g_print("(remmina-applet avahi-browser) Failed to resolve service '%s': %s\n",
145  name, avahi_strerror(avahi_client_errno(ga->priv->client)));
146  }
147  break;
148 
149  case AVAHI_BROWSER_REMOVE:
150  g_print("(remmina-applet avahi-browser) Removed service '%s' of type '%s' in domain '%s'\n", name, type, domain);
151  key = g_strdup_printf("%s,%s,%s", name, type, domain);
152  g_hash_table_remove(ga->discovered_services, key);
153  g_free(key);
154  break;
155 
156  case AVAHI_BROWSER_ALL_FOR_NOW:
157  case AVAHI_BROWSER_CACHE_EXHAUSTED:
158  break;
159  }
160 }
161 
162 static void remmina_avahi_client_callback(AvahiClient* c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata)
163 {
164  TRACE_CALL(__func__);
165  RemminaAvahi* ga = (RemminaAvahi*)userdata;
166 
167  ga->priv->has_event = TRUE;
168 
169  if (state == AVAHI_CLIENT_FAILURE) {
170  g_print("(remmina-applet avahi) Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
171  }
172 }
173 
175 {
176  TRACE_CALL(__func__);
177  while (TRUE) {
178  /* Call the iteration until no further events */
179  ga->priv->has_event = FALSE;
180  avahi_simple_poll_iterate(ga->priv->simple_poll, 0);
181  if (!ga->priv->has_event)
182  break;
183  }
184 
185  return TRUE;
186 }
187 
189 {
190  TRACE_CALL(__func__);
191  RemminaAvahi* ga;
192 
193  ga = g_new(RemminaAvahi, 1);
194  ga->discovered_services = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
195  ga->started = FALSE;
196  ga->priv = g_new(RemminaAvahiPriv, 1);
197  ga->priv->simple_poll = NULL;
198  ga->priv->client = NULL;
199  ga->priv->sb = NULL;
200  ga->priv->iterate_handler = 0;
201  ga->priv->has_event = FALSE;
202 
203  return ga;
204 }
205 
207 {
208  TRACE_CALL(__func__);
209  int error;
210 
211  if (ga->started)
212  return;
213 
214  ga->started = TRUE;
215 
216  ga->priv->simple_poll = avahi_simple_poll_new();
217  if (!ga->priv->simple_poll) {
218  g_print("Failed to create simple poll object.\n");
219  return;
220  }
221 
222  ga->priv->client = avahi_client_new(avahi_simple_poll_get(ga->priv->simple_poll), 0, remmina_avahi_client_callback, ga,
223  &error);
224  if (!ga->priv->client) {
225  g_print("Failed to create client: %s\n", avahi_strerror(error));
226  return;
227  }
228 
230  ga->priv->sb = avahi_service_browser_new(ga->priv->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_rfb._tcp", NULL, 0,
232  if (!ga->priv->sb) {
233  g_print("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(ga->priv->client)));
234  return;
235  }
236 
237  ga->priv->iterate_handler = g_timeout_add(5000, (GSourceFunc)remmina_avahi_iterate, ga);
238 }
239 
241 {
242  TRACE_CALL(__func__);
243  g_hash_table_remove_all(ga->discovered_services);
244  if (ga->priv->iterate_handler) {
245  g_source_remove(ga->priv->iterate_handler);
246  ga->priv->iterate_handler = 0;
247  }
248  if (ga->priv->sb) {
249  avahi_service_browser_free(ga->priv->sb);
250  ga->priv->sb = NULL;
251  }
252  if (ga->priv->client) {
253  avahi_client_free(ga->priv->client);
254  ga->priv->client = NULL;
255  }
256  if (ga->priv->simple_poll) {
257  avahi_simple_poll_free(ga->priv->simple_poll);
258  ga->priv->simple_poll = NULL;
259  }
260  ga->started = FALSE;
261 }
262 
264 {
265  TRACE_CALL(__func__);
266  if (ga == NULL)
267  return;
268 
269  remmina_avahi_stop(ga);
270 
271  g_free(ga->priv);
272  g_hash_table_destroy(ga->discovered_services);
273  g_free(ga);
274 }
275 
276 #else
277 
279 {
280  TRACE_CALL(__func__);
281  return NULL;
282 }
283 
285 {
286  TRACE_CALL(__func__);
287 }
288 
290 {
291  TRACE_CALL(__func__);
292 }
293 
295 {
296  TRACE_CALL(__func__);
297 }
298 
299 #endif
300 
static void remmina_avahi_client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void *userdata)
RemminaAvahi * remmina_avahi_new(void)
RemminaAvahiPriv * priv
Definition: remmina_avahi.h:48
typedefG_BEGIN_DECLS struct _RemminaAvahiPriv RemminaAvahiPriv
Definition: remmina_avahi.h:42
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)
Definition: remmina_avahi.c:58
static gboolean remmina_avahi_iterate(RemminaAvahi *ga)
AvahiServiceBrowser * sb
Definition: remmina_avahi.c:52
void remmina_avahi_stop(RemminaAvahi *ga)
AvahiClient * client
Definition: remmina_avahi.c:51
void remmina_avahi_free(RemminaAvahi *ga)
gboolean started
Definition: remmina_avahi.h:46
GHashTable * discovered_services
Definition: remmina_avahi.h:45
void remmina_avahi_start(RemminaAvahi *ga)
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)
AvahiSimplePoll * simple_poll
Definition: remmina_avahi.c:50