1/* 2 * ga-service-browser.c - Source for GaServiceBrowser 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 <avahi-client/client.h> 28#include <avahi-client/lookup.h> 29#include <avahi-common/error.h> 30 31#include "ga-service-browser.h" 32#include "signals-marshal.h" 33#include "ga-error.h" 34#include "ga-enums-enumtypes.h" 35 36G_DEFINE_TYPE(GaServiceBrowser, ga_service_browser, G_TYPE_OBJECT) 37 38/* signal enum */ 39enum { 40 NEW, 41 REMOVED, 42 CACHE_EXHAUSTED, 43 ALL_FOR_NOW, 44 FAILURE, 45 LAST_SIGNAL 46}; 47 48static guint signals[LAST_SIGNAL] = { 0 }; 49 50/* properties */ 51enum { 52 PROP_PROTOCOL = 1, 53 PROP_IFINDEX, 54 PROP_TYPE, 55 PROP_DOMAIN, 56 PROP_FLAGS 57}; 58 59/* private structure */ 60typedef struct _GaServiceBrowserPrivate GaServiceBrowserPrivate; 61 62struct _GaServiceBrowserPrivate { 63 GaClient *client; 64 AvahiServiceBrowser *browser; 65 AvahiIfIndex interface; 66 AvahiProtocol protocol; 67 char *type; 68 char *domain; 69 AvahiLookupFlags flags; 70 gboolean dispose_has_run; 71}; 72 73#define GA_SERVICE_BROWSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_SERVICE_BROWSER, GaServiceBrowserPrivate)) 74 75static void ga_service_browser_init(GaServiceBrowser * obj) { 76 GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(obj); 77 78 /* allocate any data required by the object here */ 79 priv->client = NULL; 80 priv->browser = NULL; 81 priv->type = NULL; 82 priv->domain = NULL; 83 84} 85 86static void ga_service_browser_dispose(GObject * object); 87static void ga_service_browser_finalize(GObject * object); 88 89static void ga_service_browser_set_property(GObject * object, 90 guint property_id, 91 const GValue * value, GParamSpec * pspec) { 92 GaServiceBrowser *browser = GA_SERVICE_BROWSER(object); 93 GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(browser); 94 95 g_assert(priv->browser == NULL); 96 switch (property_id) { 97 case PROP_PROTOCOL: 98 priv->protocol = g_value_get_enum(value); 99 break; 100 case PROP_IFINDEX: 101 priv->interface = g_value_get_int(value); 102 break; 103 case PROP_TYPE: 104 priv->type = g_strdup(g_value_get_string(value)); 105 break; 106 case PROP_DOMAIN: 107 priv->domain = g_strdup(g_value_get_string(value)); 108 break; 109 case PROP_FLAGS: 110 priv->flags = g_value_get_enum(value); 111 break; 112 default: 113 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 114 break; 115 } 116} 117 118static void ga_service_browser_get_property(GObject * object, 119 guint property_id, 120 GValue * value, GParamSpec * pspec) { 121 GaServiceBrowser *browser = GA_SERVICE_BROWSER(object); 122 GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(browser); 123 124 switch (property_id) { 125 case PROP_PROTOCOL: 126 g_value_set_int(value, priv->protocol); 127 break; 128 case PROP_IFINDEX: 129 g_value_set_int(value, priv->interface); 130 break; 131 case PROP_TYPE: 132 g_value_set_string(value, priv->type); 133 break; 134 case PROP_DOMAIN: 135 g_value_set_string(value, priv->domain); 136 break; 137 case PROP_FLAGS: 138 g_value_set_enum(value, priv->flags); 139 break; 140 default: 141 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 142 break; 143 } 144} 145 146 147static void ga_service_browser_class_init(GaServiceBrowserClass * 148 ga_service_browser_class) { 149 GObjectClass *object_class = G_OBJECT_CLASS(ga_service_browser_class); 150 GParamSpec *param_spec; 151 152 g_type_class_add_private(ga_service_browser_class, 153 sizeof (GaServiceBrowserPrivate)); 154 155 object_class->dispose = ga_service_browser_dispose; 156 object_class->finalize = ga_service_browser_finalize; 157 158 object_class->set_property = ga_service_browser_set_property; 159 object_class->get_property = ga_service_browser_get_property; 160 161 signals[NEW] = 162 g_signal_new("new-service", 163 G_OBJECT_CLASS_TYPE(ga_service_browser_class), 164 G_SIGNAL_RUN_LAST, 165 0, 166 NULL, NULL, 167 _ga_signals_marshal_VOID__INT_ENUM_STRING_STRING_STRING_UINT, 168 G_TYPE_NONE, 6, 169 G_TYPE_INT, 170 GA_TYPE_PROTOCOL, 171 G_TYPE_STRING, 172 G_TYPE_STRING, 173 G_TYPE_STRING, GA_TYPE_LOOKUP_RESULT_FLAGS); 174 175 signals[REMOVED] = 176 g_signal_new("removed-service", 177 G_OBJECT_CLASS_TYPE(ga_service_browser_class), 178 G_SIGNAL_RUN_LAST, 179 0, 180 NULL, NULL, 181 _ga_signals_marshal_VOID__INT_ENUM_STRING_STRING_STRING_UINT, 182 G_TYPE_NONE, 6, 183 G_TYPE_INT, 184 GA_TYPE_PROTOCOL, 185 G_TYPE_STRING, 186 G_TYPE_STRING, 187 G_TYPE_STRING, GA_TYPE_LOOKUP_RESULT_FLAGS); 188 189 signals[ALL_FOR_NOW] = 190 g_signal_new("all-for-now", 191 G_OBJECT_CLASS_TYPE(ga_service_browser_class), 192 G_SIGNAL_RUN_LAST, 193 0, 194 NULL, NULL, 195 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); 196 197 signals[CACHE_EXHAUSTED] = 198 g_signal_new("cache-exhausted", 199 G_OBJECT_CLASS_TYPE(ga_service_browser_class), 200 G_SIGNAL_RUN_LAST, 201 0, 202 NULL, NULL, 203 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); 204 205 signals[FAILURE] = 206 g_signal_new("failure", 207 G_OBJECT_CLASS_TYPE(ga_service_browser_class), 208 G_SIGNAL_RUN_LAST, 209 0, 210 NULL, NULL, 211 g_cclosure_marshal_VOID__POINTER, 212 G_TYPE_NONE, 1, G_TYPE_POINTER); 213 214 param_spec = g_param_spec_enum("protocol", "Avahi protocol to browse", 215 "Avahi protocol to browse", 216 GA_TYPE_PROTOCOL, 217 GA_PROTOCOL_UNSPEC, 218 G_PARAM_READWRITE | 219 G_PARAM_STATIC_NAME | 220 G_PARAM_STATIC_BLURB); 221 g_object_class_install_property(object_class, PROP_PROTOCOL, param_spec); 222 223 param_spec = g_param_spec_int("interface", "interface index", 224 "Interface use for browser", 225 AVAHI_IF_UNSPEC, 226 G_MAXINT, 227 AVAHI_IF_UNSPEC, 228 G_PARAM_READWRITE | 229 G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB); 230 g_object_class_install_property(object_class, PROP_IFINDEX, param_spec); 231 232 param_spec = g_param_spec_string("type", "service type", 233 "Service type to browse for", 234 NULL, 235 G_PARAM_READWRITE | 236 G_PARAM_STATIC_NAME | 237 G_PARAM_STATIC_BLURB); 238 g_object_class_install_property(object_class, PROP_TYPE, param_spec); 239 240 param_spec = g_param_spec_string("domain", "service domain", 241 "Domain to browse in", 242 NULL, 243 G_PARAM_READWRITE | 244 G_PARAM_STATIC_NAME | 245 G_PARAM_STATIC_BLURB); 246 g_object_class_install_property(object_class, PROP_DOMAIN, param_spec); 247 248 param_spec = g_param_spec_enum("flags", "Lookup flags for the browser", 249 "Browser lookup flags", 250 GA_TYPE_LOOKUP_FLAGS, 251 GA_LOOKUP_NO_FLAGS, 252 G_PARAM_READWRITE | 253 G_PARAM_STATIC_NAME | 254 G_PARAM_STATIC_BLURB); 255 g_object_class_install_property(object_class, PROP_FLAGS, param_spec); 256} 257 258void ga_service_browser_dispose(GObject * object) { 259 GaServiceBrowser *self = GA_SERVICE_BROWSER(object); 260 GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(self); 261 262 if (priv->dispose_has_run) 263 return; 264 265 priv->dispose_has_run = TRUE; 266 267 if (priv->browser) 268 avahi_service_browser_free(priv->browser); 269 priv->browser = NULL; 270 if (priv->client) 271 g_object_unref(priv->client); 272 priv->client = NULL; 273 274 /* release any references held by the object here */ 275 276 if (G_OBJECT_CLASS(ga_service_browser_parent_class)->dispose) 277 G_OBJECT_CLASS(ga_service_browser_parent_class)->dispose(object); 278} 279 280void ga_service_browser_finalize(GObject * object) { 281 GaServiceBrowser *self = GA_SERVICE_BROWSER(object); 282 GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(self); 283 284 /* free any data held directly by the object here */ 285 g_free(priv->type); 286 priv->type = NULL; 287 g_free(priv->domain); 288 priv->domain = NULL; 289 290 G_OBJECT_CLASS(ga_service_browser_parent_class)->finalize(object); 291} 292 293static void _avahi_service_browser_cb(AvahiServiceBrowser * b, AvahiIfIndex interface, 294 AvahiProtocol protocol, AvahiBrowserEvent event, 295 const char *name, const char *type, 296 const char *domain, AvahiLookupResultFlags flags, 297 void *userdata) { 298 GaServiceBrowser *self = GA_SERVICE_BROWSER(userdata); 299 GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(self); 300 if (priv->browser == NULL) { 301 priv->browser = b; 302 } 303 g_assert(priv->browser == b); 304 305 switch (event) { 306 case AVAHI_BROWSER_NEW: 307 case AVAHI_BROWSER_REMOVE:{ 308 guint signalid; 309 signalid = (event == AVAHI_BROWSER_NEW ? NEW : REMOVED); 310 g_signal_emit(self, signals[signalid], 0, 311 interface, protocol, name, type, domain, flags); 312 break; 313 } 314 case AVAHI_BROWSER_CACHE_EXHAUSTED: 315 g_signal_emit(self, signals[CACHE_EXHAUSTED], 0); 316 break; 317 case AVAHI_BROWSER_ALL_FOR_NOW: 318 g_signal_emit(self, signals[ALL_FOR_NOW], 0); 319 break; 320 case AVAHI_BROWSER_FAILURE:{ 321 GError *error; 322 int aerrno = avahi_client_errno(priv->client->avahi_client); 323 error = g_error_new(GA_ERROR, aerrno, 324 "Browsing failed: %s", 325 avahi_strerror(aerrno)); 326 g_signal_emit(self, signals[FAILURE], 0, error); 327 g_error_free(error); 328 break; 329 } 330 } 331} 332 333GaServiceBrowser *ga_service_browser_new(const gchar * type) { 334 return ga_service_browser_new_full(AVAHI_IF_UNSPEC, 335 AVAHI_PROTO_UNSPEC, type, NULL, 0); 336} 337 338GaServiceBrowser *ga_service_browser_new_full(AvahiIfIndex interface, 339 AvahiProtocol protocol, 340 const gchar * type, gchar * domain, 341 GaLookupFlags flags) { 342 return g_object_new(GA_TYPE_SERVICE_BROWSER, 343 "interface", interface, 344 "protocol", protocol, 345 "type", type, "domain", domain, "flags", flags, NULL); 346} 347 348gboolean ga_service_browser_attach(GaServiceBrowser * browser, 349 GaClient * client, GError ** error) { 350 GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(browser); 351 352 g_object_ref(client); 353 priv->client = client; 354 355 priv->browser = avahi_service_browser_new(client->avahi_client, 356 priv->interface, 357 priv->protocol, 358 priv->type, priv->domain, 359 priv->flags, 360 _avahi_service_browser_cb, 361 browser); 362 if (priv->browser == NULL) { 363 if (error != NULL) { 364 int aerrno = avahi_client_errno(client->avahi_client); 365 *error = g_error_new(GA_ERROR, aerrno, 366 "Attaching group failed: %s", 367 avahi_strerror(aerrno)); 368 } 369 return FALSE; 370 } 371 return TRUE; 372} 373