1 /*
2 * ga-service-resolver.c - Source for GaServiceResolver
3 * Copyright (C) 2006-2007 Collabora Ltd.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include "ga-service-resolver.h"
28 #include "signals-marshal.h"
29
30 #include "ga-error.h"
31
32 #include "ga-enums.h"
33 #include "ga-enums-enumtypes.h"
34
35 #include <avahi-client/lookup.h>
36
37 G_DEFINE_TYPE(GaServiceResolver, ga_service_resolver, G_TYPE_OBJECT)
38
39 /* signal enum */
40 enum {
41 FOUND,
42 FAILURE,
43 LAST_SIGNAL
44 };
45
46 static guint signals[LAST_SIGNAL] = { 0 };
47
48 /* properties */
49 enum {
50 PROP_PROTOCOL = 1,
51 PROP_IFINDEX,
52 PROP_NAME,
53 PROP_TYPE,
54 PROP_DOMAIN,
55 PROP_FLAGS,
56 PROP_APROTOCOL
57 };
58
59 /* private structure */
60 typedef struct _GaServiceResolverPrivate GaServiceResolverPrivate;
61
62 struct _GaServiceResolverPrivate {
63 GaClient *client;
64 AvahiServiceResolver *resolver;
65 AvahiIfIndex interface;
66 AvahiProtocol protocol;
67 AvahiAddress address;
68 uint16_t port;
69 char *name;
70 char *type;
71 char *domain;
72 AvahiProtocol aprotocol;
73 AvahiLookupFlags flags;
74 gboolean dispose_has_run;
75 };
76
77 #define GA_SERVICE_RESOLVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_SERVICE_RESOLVER, GaServiceResolverPrivate))
78
ga_service_resolver_init(GaServiceResolver * obj)79 static void ga_service_resolver_init(GaServiceResolver * obj) {
80 GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(obj);
81
82 /* allocate any data required by the object here */
83 priv->client = NULL;
84 priv->resolver = NULL;
85 priv->name = NULL;
86 priv->type = NULL;
87 priv->domain = NULL;
88 priv->port = 0;
89 }
90
91 static void ga_service_resolver_dispose(GObject * object);
92 static void ga_service_resolver_finalize(GObject * object);
93
ga_service_resolver_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)94 static void ga_service_resolver_set_property(GObject * object,
95 guint property_id,
96 const GValue * value, GParamSpec * pspec) {
97 GaServiceResolver *resolver = GA_SERVICE_RESOLVER(object);
98 GaServiceResolverPrivate *priv =
99 GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
100
101 g_assert(priv->resolver == NULL);
102 switch (property_id) {
103 case PROP_PROTOCOL:
104 priv->protocol = g_value_get_enum(value);
105 break;
106 case PROP_APROTOCOL:
107 priv->aprotocol = g_value_get_enum(value);
108 break;
109 case PROP_IFINDEX:
110 priv->interface = g_value_get_int(value);
111 break;
112 case PROP_NAME:
113 priv->name = g_strdup(g_value_get_string(value));
114 break;
115 case PROP_TYPE:
116 priv->type = g_strdup(g_value_get_string(value));
117 break;
118 case PROP_DOMAIN:
119 priv->domain = g_strdup(g_value_get_string(value));
120 break;
121 case PROP_FLAGS:
122 priv->flags = g_value_get_enum(value);
123 break;
124 default:
125 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
126 break;
127 }
128 }
129
ga_service_resolver_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)130 static void ga_service_resolver_get_property(GObject * object,
131 guint property_id,
132 GValue * value, GParamSpec * pspec) {
133 GaServiceResolver *resolver = GA_SERVICE_RESOLVER(object);
134 GaServiceResolverPrivate *priv =
135 GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
136
137 switch (property_id) {
138 case PROP_APROTOCOL:
139 g_value_set_enum(value, priv->aprotocol);
140 break;
141 case PROP_PROTOCOL:
142 g_value_set_enum(value, priv->protocol);
143 break;
144 case PROP_IFINDEX:
145 g_value_set_int(value, priv->interface);
146 break;
147 case PROP_NAME:
148 g_value_set_string(value, priv->name);
149 break;
150 case PROP_TYPE:
151 g_value_set_string(value, priv->type);
152 break;
153 case PROP_DOMAIN:
154 g_value_set_string(value, priv->domain);
155 break;
156 case PROP_FLAGS:
157 g_value_set_enum(value, priv->flags);
158 break;
159 default:
160 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
161 break;
162 }
163 }
164
165
ga_service_resolver_class_init(GaServiceResolverClass * ga_service_resolver_class)166 static void ga_service_resolver_class_init(GaServiceResolverClass *
167 ga_service_resolver_class) {
168 GObjectClass *object_class = G_OBJECT_CLASS(ga_service_resolver_class);
169 GParamSpec *param_spec;
170
171 g_type_class_add_private(ga_service_resolver_class,
172 sizeof (GaServiceResolverPrivate));
173
174 object_class->set_property = ga_service_resolver_set_property;
175 object_class->get_property = ga_service_resolver_get_property;
176
177 object_class->dispose = ga_service_resolver_dispose;
178 object_class->finalize = ga_service_resolver_finalize;
179
180 signals[FOUND] =
181 g_signal_new("found",
182 G_OBJECT_CLASS_TYPE(ga_service_resolver_class),
183 G_SIGNAL_RUN_LAST,
184 0,
185 NULL, NULL,
186 _ga_signals_marshal_VOID__INT_ENUM_STRING_STRING_STRING_STRING_POINTER_INT_POINTER_INT,
187 G_TYPE_NONE, 10,
188 G_TYPE_INT,
189 GA_TYPE_PROTOCOL,
190 G_TYPE_STRING,
191 G_TYPE_STRING,
192 G_TYPE_STRING,
193 G_TYPE_STRING,
194 G_TYPE_POINTER,
195 G_TYPE_INT,
196 G_TYPE_POINTER, GA_TYPE_LOOKUP_RESULT_FLAGS);
197
198 signals[FAILURE] =
199 g_signal_new("failure",
200 G_OBJECT_CLASS_TYPE(ga_service_resolver_class),
201 G_SIGNAL_RUN_LAST,
202 0,
203 NULL, NULL,
204 g_cclosure_marshal_VOID__POINTER,
205 G_TYPE_NONE, 1, G_TYPE_POINTER);
206
207 param_spec = g_param_spec_enum("protocol", "Avahi protocol to resolve on",
208 "Avahi protocol to resolve on",
209 GA_TYPE_PROTOCOL,
210 GA_PROTOCOL_UNSPEC,
211 G_PARAM_READWRITE |
212 G_PARAM_STATIC_NAME |
213 G_PARAM_STATIC_BLURB);
214 g_object_class_install_property(object_class, PROP_PROTOCOL, param_spec);
215
216 param_spec = g_param_spec_enum("aprotocol", "Address protocol",
217 "Avahi protocol of the address to be resolved",
218 GA_TYPE_PROTOCOL,
219 GA_PROTOCOL_UNSPEC,
220 G_PARAM_READWRITE |
221 G_PARAM_STATIC_NAME |
222 G_PARAM_STATIC_BLURB);
223 g_object_class_install_property(object_class, PROP_APROTOCOL, param_spec);
224
225 param_spec = g_param_spec_int("interface", "interface index",
226 "Interface use for resolver",
227 AVAHI_IF_UNSPEC,
228 G_MAXINT,
229 AVAHI_IF_UNSPEC,
230 G_PARAM_READWRITE |
231 G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB);
232 g_object_class_install_property(object_class, PROP_IFINDEX, param_spec);
233
234 param_spec = g_param_spec_string("name", "service name",
235 "name to resolve",
236 NULL,
237 G_PARAM_READWRITE |
238 G_PARAM_STATIC_NAME |
239 G_PARAM_STATIC_BLURB);
240 g_object_class_install_property(object_class, PROP_NAME, param_spec);
241
242 param_spec = g_param_spec_string("type", "service type",
243 "Service type to browse for",
244 NULL,
245 G_PARAM_READWRITE |
246 G_PARAM_STATIC_NAME |
247 G_PARAM_STATIC_BLURB);
248 g_object_class_install_property(object_class, PROP_TYPE, param_spec);
249
250 param_spec = g_param_spec_string("domain", "service domain",
251 "Domain to browse in",
252 NULL,
253 G_PARAM_READWRITE |
254 G_PARAM_STATIC_NAME |
255 G_PARAM_STATIC_BLURB);
256 g_object_class_install_property(object_class, PROP_DOMAIN, param_spec);
257
258 param_spec = g_param_spec_enum("flags", "Lookup flags for the resolver",
259 "Resolver lookup flags",
260 GA_TYPE_LOOKUP_FLAGS,
261 GA_LOOKUP_NO_FLAGS,
262 G_PARAM_READWRITE |
263 G_PARAM_STATIC_NAME |
264 G_PARAM_STATIC_BLURB);
265 g_object_class_install_property(object_class, PROP_FLAGS, param_spec);
266 }
267
ga_service_resolver_dispose(GObject * object)268 void ga_service_resolver_dispose(GObject * object) {
269 GaServiceResolver *self = GA_SERVICE_RESOLVER(object);
270 GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(self);
271
272 if (priv->dispose_has_run)
273 return;
274
275 priv->dispose_has_run = TRUE;
276
277 if (priv->client)
278 g_object_unref(priv->client);
279 priv->client = NULL;
280
281 if (priv->resolver)
282 avahi_service_resolver_free(priv->resolver);
283 priv->resolver = NULL;
284
285 /* release any references held by the object here */
286
287 if (G_OBJECT_CLASS(ga_service_resolver_parent_class)->dispose)
288 G_OBJECT_CLASS(ga_service_resolver_parent_class)->dispose(object);
289 }
290
ga_service_resolver_finalize(GObject * object)291 void ga_service_resolver_finalize(GObject * object) {
292 GaServiceResolver *self = GA_SERVICE_RESOLVER(object);
293 GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(self);
294
295 /* free any data held directly by the object here */
296 g_free(priv->name);
297 priv->name = NULL;
298
299 g_free(priv->type);
300 priv->type = NULL;
301
302 g_free(priv->domain);
303 priv->domain = NULL;
304
305 G_OBJECT_CLASS(ga_service_resolver_parent_class)->finalize(object);
306 }
307
_avahi_service_resolver_cb(AVAHI_GCC_UNUSED AvahiServiceResolver * resolver,AvahiIfIndex interface,AvahiProtocol protocol,AvahiResolverEvent event,const char * name,const char * type,const char * domain,const char * host_name,const AvahiAddress * a,uint16_t port,AvahiStringList * txt,AvahiLookupResultFlags flags,void * userdata)308 static void _avahi_service_resolver_cb(AVAHI_GCC_UNUSED AvahiServiceResolver * resolver,
309 AvahiIfIndex interface,
310 AvahiProtocol protocol,
311 AvahiResolverEvent event,
312 const char *name, const char *type,
313 const char *domain, const char *host_name,
314 const AvahiAddress * a,
315 uint16_t port,
316 AvahiStringList * txt,
317 AvahiLookupResultFlags flags, void *userdata) {
318 GaServiceResolver *self = GA_SERVICE_RESOLVER(userdata);
319 GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(self);
320
321 switch (event) {
322 case AVAHI_RESOLVER_FOUND:{
323 /* FIXME: Double check if this address is always the same */
324 priv->address = *a;
325 priv->port = port;
326 g_signal_emit(self, signals[FOUND], 0,
327 interface, protocol,
328 name, type,
329 domain, host_name, a, port, txt, flags);
330 break;
331 }
332 case AVAHI_RESOLVER_FAILURE:{
333 GError *error;
334 int aerrno = avahi_client_errno(priv->client->avahi_client);
335 error = g_error_new(GA_ERROR, aerrno,
336 "Resolving failed: %s",
337 avahi_strerror(aerrno));
338 g_signal_emit(self, signals[FAILURE], 0, error);
339 g_error_free(error);
340 break;
341 }
342 }
343 }
344
345
ga_service_resolver_new(AvahiIfIndex interface,AvahiProtocol protocol,const gchar * name,const gchar * type,const gchar * domain,AvahiProtocol address_protocol,GaLookupFlags flags)346 GaServiceResolver *ga_service_resolver_new(AvahiIfIndex interface,
347 AvahiProtocol protocol,
348 const gchar * name,
349 const gchar * type,
350 const gchar * domain,
351 AvahiProtocol address_protocol,
352 GaLookupFlags flags) {
353 return g_object_new(GA_TYPE_SERVICE_RESOLVER, "interface", interface,
354 "protocol", protocol, "name", name, "type", type,
355 "domain", domain, "aprotocol", address_protocol,
356 "flags", flags, NULL);
357 }
358
ga_service_resolver_attach(GaServiceResolver * resolver,GaClient * client,GError ** error)359 gboolean ga_service_resolver_attach(GaServiceResolver * resolver,
360 GaClient * client, GError ** error) {
361 GaServiceResolverPrivate *priv =
362 GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
363
364 g_assert(client != NULL);
365 g_object_ref(client);
366
367 priv->client = client;
368
369 priv->resolver = avahi_service_resolver_new(client->avahi_client,
370 priv->interface,
371 priv->protocol,
372 priv->name,
373 priv->type, priv->domain,
374 priv->aprotocol,
375 priv->flags,
376 _avahi_service_resolver_cb,
377 resolver);
378 if (priv->resolver == NULL) {
379 if (error != NULL) {
380 int aerrno = avahi_client_errno(client->avahi_client);
381 *error = g_error_new(GA_ERROR, aerrno,
382 "Attaching group failed: %s",
383 avahi_strerror(aerrno));
384 }
385 /* printf("Failed to add resolver\n"); */
386 return FALSE;
387 }
388 return TRUE;
389 }
390
ga_service_resolver_get_address(GaServiceResolver * resolver,AvahiAddress * address,uint16_t * port)391 gboolean ga_service_resolver_get_address(GaServiceResolver * resolver,
392 AvahiAddress * address, uint16_t * port) {
393 GaServiceResolverPrivate *priv =
394 GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
395 if (priv->port == 0) {
396 /* printf("PORT == 0\n"); */
397 return FALSE;
398 }
399
400 *address = priv->address;
401 *port = priv->port;
402 return TRUE;
403 }
404