Home | History | Annotate | Download | only in avahi-gobject
      1 /*
      2  * ga-record-browser.c - Source for GaRecordBrowser
      3  * Copyright (C) 2007 Collabora Ltd.
      4  * @author Sjoerd Simons <sjoerd (at) luon.net>
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2.1 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, write to the Free Software
     18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     19  */
     20 
     21 #ifdef HAVE_CONFIG_H
     22 #include <config.h>
     23 #endif
     24 
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 
     28 #include "ga-record-browser.h"
     29 #include "signals-marshal.h"
     30 #include "ga-error.h"
     31 #include "ga-enums-enumtypes.h"
     32 
     33 G_DEFINE_TYPE(GaRecordBrowser, ga_record_browser, G_TYPE_OBJECT)
     34 
     35 /* signal enum */
     36 enum {
     37     NEW,
     38     REMOVED,
     39     FAILURE,
     40     ALL_FOR_NOW,
     41     CACHE_EXHAUSTED,
     42     LAST_SIGNAL
     43 };
     44 
     45 static guint signals[LAST_SIGNAL] = { 0 };
     46 
     47 /* properties */
     48 enum {
     49     PROP_PROTOCOL = 1,
     50     PROP_IFINDEX,
     51     PROP_NAME,
     52     PROP_CLASS,
     53     PROP_TYPE,
     54     PROP_FLAGS
     55 };
     56 
     57 /* private structure */
     58 typedef struct _GaRecordBrowserPrivate GaRecordBrowserPrivate;
     59 
     60 struct _GaRecordBrowserPrivate {
     61     gboolean dispose_has_run;
     62     GaClient *client;
     63     AvahiRecordBrowser *browser;
     64     AvahiProtocol protocol;
     65     AvahiIfIndex interface;
     66     gchar *name;
     67     guint16 class;
     68     guint16 type;
     69     AvahiLookupFlags flags;
     70 };
     71 
     72 #define GA_RECORD_BROWSER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_RECORD_BROWSER, GaRecordBrowserPrivate))
     73 
     74 static void ga_record_browser_init(AVAHI_GCC_UNUSED GaRecordBrowser * obj) {
     75     /* allocate any data required by the object here */
     76 }
     77 
     78 static void ga_record_browser_dispose(GObject * object);
     79 static void ga_record_browser_finalize(GObject * object);
     80 
     81 static void ga_record_browser_set_property(GObject * object,
     82                                guint property_id,
     83                                const GValue * value, GParamSpec * pspec) {
     84     GaRecordBrowser *browser = GA_RECORD_BROWSER(object);
     85     GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(browser);
     86 
     87     g_assert(priv->browser == NULL);
     88 
     89     switch (property_id) {
     90         case PROP_PROTOCOL:
     91             priv->protocol = g_value_get_enum(value);
     92             break;
     93         case PROP_IFINDEX:
     94             priv->interface = g_value_get_int(value);
     95             break;
     96         case PROP_NAME:
     97             priv->name = g_value_dup_string(value);
     98             break;
     99         case PROP_CLASS:
    100             priv->class = g_value_get_uint(value);
    101             break;
    102         case PROP_TYPE:
    103             priv->type = g_value_get_uint(value);
    104             break;
    105         case PROP_FLAGS:
    106             priv->flags = g_value_get_enum(value);
    107             break;
    108         default:
    109             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
    110             break;
    111     }
    112 }
    113 
    114 static void ga_record_browser_get_property(GObject * object,
    115                                guint property_id,
    116                                GValue * value, GParamSpec * pspec) {
    117     GaRecordBrowser *browser = GA_RECORD_BROWSER(object);
    118     GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(browser);
    119 
    120     switch (property_id) {
    121         case PROP_PROTOCOL:
    122             g_value_set_int(value, priv->protocol);
    123             break;
    124         case PROP_IFINDEX:
    125             g_value_set_int(value, priv->interface);
    126             break;
    127         case PROP_TYPE:
    128             g_value_set_uint(value, priv->type);
    129             break;
    130         case PROP_CLASS:
    131             g_value_set_uint(value, priv->class);
    132             break;
    133         case PROP_NAME:
    134             g_value_set_string(value, priv->name);
    135             break;
    136         case PROP_FLAGS:
    137             g_value_set_enum(value, priv->flags);
    138             break;
    139         default:
    140             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
    141             break;
    142     }
    143 }
    144 
    145 
    146 static void ga_record_browser_class_init(GaRecordBrowserClass * ga_record_browser_class) {
    147     GObjectClass *object_class = G_OBJECT_CLASS(ga_record_browser_class);
    148     GParamSpec *param_spec;
    149 
    150     g_type_class_add_private(ga_record_browser_class,
    151                              sizeof (GaRecordBrowserPrivate));
    152 
    153     object_class->dispose = ga_record_browser_dispose;
    154     object_class->finalize = ga_record_browser_finalize;
    155 
    156     object_class->set_property = ga_record_browser_set_property;
    157     object_class->get_property = ga_record_browser_get_property;
    158 
    159     signals[NEW] =
    160             g_signal_new("new-record",
    161                          G_OBJECT_CLASS_TYPE(ga_record_browser_class),
    162                          G_SIGNAL_RUN_LAST,
    163                          0,
    164                          NULL, NULL,
    165                          _ga_signals_marshal_VOID__INT_ENUM_STRING_UINT_UINT_POINTER_INT_INT,
    166                          G_TYPE_NONE, 8,
    167                          G_TYPE_INT,
    168                          GA_TYPE_PROTOCOL,
    169                          G_TYPE_STRING,
    170                          G_TYPE_UINT,
    171                          G_TYPE_UINT,
    172                          G_TYPE_POINTER,
    173                          G_TYPE_INT, GA_TYPE_LOOKUP_RESULT_FLAGS);
    174 
    175     signals[REMOVED] =
    176             g_signal_new("removed-record",
    177                          G_OBJECT_CLASS_TYPE(ga_record_browser_class),
    178                          G_SIGNAL_RUN_LAST,
    179                          0,
    180                          NULL, NULL,
    181                          _ga_signals_marshal_VOID__INT_ENUM_STRING_UINT_UINT_POINTER_INT_INT,
    182                          G_TYPE_NONE, 8,
    183                          G_TYPE_INT,
    184                          GA_TYPE_PROTOCOL,
    185                          G_TYPE_STRING,
    186                          G_TYPE_UINT,
    187                          G_TYPE_UINT,
    188                          G_TYPE_POINTER,
    189                          G_TYPE_INT, GA_TYPE_LOOKUP_RESULT_FLAGS);
    190 
    191     signals[ALL_FOR_NOW] =
    192             g_signal_new("all-for-now",
    193                          G_OBJECT_CLASS_TYPE(ga_record_browser_class),
    194                          G_SIGNAL_RUN_LAST,
    195                          0,
    196                          NULL, NULL,
    197                          g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    198 
    199     signals[CACHE_EXHAUSTED] =
    200             g_signal_new("cache-exhausted",
    201                          G_OBJECT_CLASS_TYPE(ga_record_browser_class),
    202                          G_SIGNAL_RUN_LAST,
    203                          0,
    204                          NULL, NULL,
    205                          g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
    206 
    207     signals[FAILURE] =
    208             g_signal_new("failure",
    209                          G_OBJECT_CLASS_TYPE(ga_record_browser_class),
    210                          G_SIGNAL_RUN_LAST,
    211                          0,
    212                          NULL, NULL,
    213                          g_cclosure_marshal_VOID__POINTER,
    214                          G_TYPE_NONE, 1, G_TYPE_POINTER);
    215 
    216     param_spec = g_param_spec_enum("protocol", "Avahi protocol to browse",
    217                                    "Avahi protocol to browse",
    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_PROTOCOL, param_spec);
    224 
    225     param_spec = g_param_spec_int("interface", "interface index",
    226                                   "Interface use for browser",
    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", "record name",
    235                                      "Record name to browse for",
    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_uint("type", "record type",
    243                                    "Record type to browse for",
    244                                    0, G_MAXUINT16, 0,
    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_uint("class", "record class",
    251                                    "Record class to browse for",
    252                                    0, G_MAXUINT16, 0,
    253                                    G_PARAM_READWRITE |
    254                                    G_PARAM_STATIC_NAME |
    255                                    G_PARAM_STATIC_BLURB);
    256     g_object_class_install_property(object_class, PROP_CLASS, param_spec);
    257 
    258     param_spec = g_param_spec_enum("flags", "Lookup flags for the browser",
    259                                    "Browser 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 
    268 void ga_record_browser_dispose(GObject * object) {
    269     GaRecordBrowser *self = GA_RECORD_BROWSER(object);
    270     GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(self);
    271 
    272     if (priv->dispose_has_run)
    273         return;
    274 
    275     priv->dispose_has_run = TRUE;
    276 
    277     /* release any references held by the object here */
    278     if (priv->client)
    279         g_object_unref(priv->client);
    280     priv->client = NULL;
    281 
    282     if (priv->browser)
    283         avahi_record_browser_free(priv->browser);
    284     priv->browser = NULL;
    285 
    286     if (G_OBJECT_CLASS(ga_record_browser_parent_class)->dispose)
    287         G_OBJECT_CLASS(ga_record_browser_parent_class)->dispose(object);
    288 }
    289 
    290 void ga_record_browser_finalize(GObject * object) {
    291     GaRecordBrowser *self = GA_RECORD_BROWSER(object);
    292     GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(self);
    293 
    294     /* free any data held directly by the object here */
    295     g_free(priv->name);
    296 
    297     G_OBJECT_CLASS(ga_record_browser_parent_class)->finalize(object);
    298 }
    299 
    300 
    301 GaRecordBrowser *ga_record_browser_new(const gchar * name, guint16 type) {
    302     return ga_record_browser_new_full(AVAHI_IF_UNSPEC,
    303                                       AVAHI_PROTO_UNSPEC, name,
    304                                       AVAHI_DNS_CLASS_IN, type, 0);
    305 }
    306 
    307 GaRecordBrowser *ga_record_browser_new_full(AvahiIfIndex interface,
    308                                             AvahiProtocol protocol,
    309                                             const gchar * name,
    310                                             guint16 clazz,
    311                                             guint16 type,
    312                                             GaLookupFlags flags) {
    313     return g_object_new(GA_TYPE_RECORD_BROWSER,
    314                         "interface", interface,
    315                         "protocol", protocol,
    316                         "name", name,
    317                         "class", clazz, "type", type, "flags", flags, NULL);
    318 
    319 }
    320 
    321 static void _avahi_record_browser_cb(AVAHI_GCC_UNUSED AvahiRecordBrowser * r, AvahiIfIndex interface,
    322                          AvahiProtocol protocol, AvahiBrowserEvent event,
    323                          const char *name, uint16_t clazz, uint16_t type,
    324                          const void *rdata, size_t rdata_size,
    325                          AvahiLookupResultFlags flags, void *userdata) {
    326     GaRecordBrowser *self = GA_RECORD_BROWSER(userdata);
    327     GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(userdata);
    328 
    329     switch (event) {
    330         case AVAHI_BROWSER_NEW:
    331         case AVAHI_BROWSER_REMOVE:{
    332                 guint signalid = (event == AVAHI_BROWSER_NEW ? NEW : REMOVED);
    333                 g_signal_emit(self, signals[signalid], 0,
    334                               interface, protocol, name, clazz, type,
    335                               rdata, rdata_size, flags);
    336                 break;
    337             }
    338         case AVAHI_BROWSER_CACHE_EXHAUSTED:
    339             g_signal_emit(self, signals[CACHE_EXHAUSTED], 0);
    340             break;
    341         case AVAHI_BROWSER_ALL_FOR_NOW:
    342             g_signal_emit(self, signals[ALL_FOR_NOW], 0);
    343             break;
    344         case AVAHI_BROWSER_FAILURE:{
    345                 GError *error;
    346                 int aerrno = avahi_client_errno(priv->client->avahi_client);
    347                 error = g_error_new(GA_ERROR, aerrno,
    348                                     "Browsing failed: %s",
    349                                     avahi_strerror(aerrno));
    350                 g_signal_emit(self, signals[FAILURE], 0, error);
    351                 g_error_free(error);
    352                 break;
    353             }
    354     }
    355 }
    356 
    357 gboolean ga_record_browser_attach(GaRecordBrowser * browser,
    358                          GaClient * client, GError ** error) {
    359     GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(browser);
    360 
    361     priv->client = g_object_ref(client);
    362     priv->browser = avahi_record_browser_new(client->avahi_client,
    363                                              priv->interface,
    364                                              priv->protocol,
    365                                              priv->name,
    366                                              priv->class,
    367                                              priv->type,
    368                                              priv->flags,
    369                                              _avahi_record_browser_cb,
    370                                              browser);
    371     if (priv->browser == NULL) {
    372         if (error != NULL) {
    373             int aerrno = avahi_client_errno(client->avahi_client);
    374             *error = g_error_new(GA_ERROR, aerrno,
    375                                  "Attaching record browser failed: %s",
    376                                  avahi_strerror(aerrno));
    377         }
    378         return FALSE;
    379     }
    380     return TRUE;
    381 }
    382