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 37G_DEFINE_TYPE(GaServiceResolver, ga_service_resolver, G_TYPE_OBJECT) 38 39/* signal enum */ 40enum { 41 FOUND, 42 FAILURE, 43 LAST_SIGNAL 44}; 45 46static guint signals[LAST_SIGNAL] = { 0 }; 47 48/* properties */ 49enum { 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 */ 60typedef struct _GaServiceResolverPrivate GaServiceResolverPrivate; 61 62struct _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 79static 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 91static void ga_service_resolver_dispose(GObject * object); 92static void ga_service_resolver_finalize(GObject * object); 93 94static 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 130static 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 166static 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 268void 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 291void 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 308static 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 346GaServiceResolver *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 359gboolean 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 391gboolean 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