Home | History | Annotate | Download | only in avahi-gobject
      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 
     36 G_DEFINE_TYPE(GaServiceBrowser, ga_service_browser, G_TYPE_OBJECT)
     37 
     38 /* signal enum */
     39 enum {
     40     NEW,
     41     REMOVED,
     42     CACHE_EXHAUSTED,
     43     ALL_FOR_NOW,
     44     FAILURE,
     45     LAST_SIGNAL
     46 };
     47 
     48 static guint signals[LAST_SIGNAL] = { 0 };
     49 
     50 /* properties */
     51 enum {
     52     PROP_PROTOCOL = 1,
     53     PROP_IFINDEX,
     54     PROP_TYPE,
     55     PROP_DOMAIN,
     56     PROP_FLAGS
     57 };
     58 
     59 /* private structure */
     60 typedef struct _GaServiceBrowserPrivate GaServiceBrowserPrivate;
     61 
     62 struct _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 
     75 static 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 
     86 static void ga_service_browser_dispose(GObject * object);
     87 static void ga_service_browser_finalize(GObject * object);
     88 
     89 static 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 
    118 static 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 
    147 static 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 
    258 void 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 
    280 void 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 
    293 static 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 
    333 GaServiceBrowser *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 
    338 GaServiceBrowser *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 
    348 gboolean 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