1/* 2 * ga-client.c - Source for GaClient 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-client.h" 28 29#include "ga-client-enumtypes.h" 30#include "ga-error.h" 31 32/* FIXME what to do about glib-malloc ? */ 33#include <avahi-glib/glib-watch.h> 34#include <avahi-glib/glib-malloc.h> 35#include <avahi-common/error.h> 36#include <avahi-common/timeval.h> 37 38G_DEFINE_TYPE(GaClient, ga_client, G_TYPE_OBJECT) 39 40/* signal enum */ 41enum { 42 STATE_CHANGED, 43 LAST_SIGNAL 44}; 45 46static guint signals[LAST_SIGNAL] = { 0 }; 47 48/* properties */ 49enum { 50 PROP_STATE = 1, 51 PROP_FLAGS 52}; 53 54/* private structure */ 55typedef struct _GaClientPrivate GaClientPrivate; 56 57struct _GaClientPrivate { 58 AvahiGLibPoll *poll; 59 GaClientFlags flags; 60 GaClientState state; 61 gboolean dispose_has_run; 62}; 63 64#define GA_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_CLIENT, GaClientPrivate)) 65 66static void ga_client_init(GaClient * self) { 67 GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(self); 68 /* allocate any data required by the object here */ 69 self->avahi_client = NULL; 70 priv->state = GA_CLIENT_STATE_NOT_STARTED; 71 priv->flags = GA_CLIENT_FLAG_NO_FLAGS; 72} 73 74static void ga_client_dispose(GObject * object); 75static void ga_client_finalize(GObject * object); 76 77static void ga_client_set_property(GObject * object, 78 guint property_id, 79 const GValue * value, GParamSpec * pspec) { 80 GaClient *client = GA_CLIENT(object); 81 GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(client); 82 83 switch (property_id) { 84 case PROP_FLAGS: 85 g_assert(client->avahi_client == NULL); 86 priv->flags = g_value_get_enum(value); 87 break; 88 default: 89 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 90 break; 91 } 92} 93 94static void ga_client_get_property(GObject * object, 95 guint property_id, 96 GValue * value, GParamSpec * pspec) { 97 GaClient *client = GA_CLIENT(object); 98 GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(client); 99 100 switch (property_id) { 101 case PROP_STATE: 102 g_value_set_enum(value, priv->state); 103 break; 104 case PROP_FLAGS: 105 g_value_set_enum(value, priv->flags); 106 default: 107 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 108 break; 109 } 110} 111 112static void ga_client_class_init(GaClientClass * ga_client_class) { 113 GObjectClass *object_class = G_OBJECT_CLASS(ga_client_class); 114 GParamSpec *param_spec; 115 116 g_type_class_add_private(ga_client_class, sizeof (GaClientPrivate)); 117 118 119 object_class->dispose = ga_client_dispose; 120 object_class->finalize = ga_client_finalize; 121 122 object_class->set_property = ga_client_set_property; 123 object_class->get_property = ga_client_get_property; 124 125 param_spec = g_param_spec_enum("state", "Client state", 126 "The state of the Avahi client", 127 GA_TYPE_CLIENT_STATE, 128 GA_CLIENT_STATE_NOT_STARTED, 129 G_PARAM_READABLE | 130 G_PARAM_STATIC_NAME | 131 G_PARAM_STATIC_BLURB); 132 g_object_class_install_property(object_class, PROP_STATE, param_spec); 133 134 param_spec = g_param_spec_enum("flags", "Client flags", 135 "The flags the Avahi client is started with", 136 GA_TYPE_CLIENT_FLAGS, 137 GA_CLIENT_FLAG_NO_FLAGS, 138 G_PARAM_READWRITE | 139 G_PARAM_CONSTRUCT_ONLY | 140 G_PARAM_STATIC_NAME | 141 G_PARAM_STATIC_BLURB); 142 g_object_class_install_property(object_class, PROP_FLAGS, param_spec); 143 144 signals[STATE_CHANGED] = 145 g_signal_new("state-changed", 146 G_OBJECT_CLASS_TYPE(ga_client_class), 147 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 148 0, 149 NULL, NULL, 150 g_cclosure_marshal_VOID__ENUM, 151 G_TYPE_NONE, 1, GA_TYPE_CLIENT_STATE); 152 153} 154 155void ga_client_dispose(GObject * object) { 156 GaClient *self = GA_CLIENT(object); 157 GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(self); 158 159 if (priv->dispose_has_run) 160 return; 161 162 priv->dispose_has_run = TRUE; 163 164 if (self->avahi_client) { 165 avahi_client_free(self->avahi_client); 166 self->avahi_client = NULL; 167 } 168 if (priv->poll) { 169 avahi_glib_poll_free(priv->poll); 170 priv->poll = NULL; 171 } 172 173 /* release any references held by the object here */ 174 if (G_OBJECT_CLASS(ga_client_parent_class)->dispose) 175 G_OBJECT_CLASS(ga_client_parent_class)->dispose(object); 176} 177 178void ga_client_finalize(GObject * object) { 179 180 /* free any data held directly by the object here */ 181 G_OBJECT_CLASS(ga_client_parent_class)->finalize(object); 182} 183 184GaClient *ga_client_new(GaClientFlags flags) { 185 return g_object_new(GA_TYPE_CLIENT, "flags", flags, NULL); 186} 187 188static GQuark detail_for_state(AvahiClientState state) { 189 static struct { 190 AvahiClientState state; 191 const gchar *name; 192 GQuark quark; 193 } states[] = { 194 { AVAHI_CLIENT_S_REGISTERING, "registering", 0}, 195 { AVAHI_CLIENT_S_RUNNING, "running", 0}, 196 { AVAHI_CLIENT_S_COLLISION, "collistion", 0}, 197 { AVAHI_CLIENT_FAILURE, "failure", 0}, 198 { AVAHI_CLIENT_CONNECTING, "connecting", 0}, 199 { 0, NULL, 0} 200 }; 201 int i; 202 203 for (i = 0; states[i].name != NULL; i++) { 204 if (state != states[i].state) 205 continue; 206 207 if (!states[i].quark) 208 states[i].quark = g_quark_from_static_string(states[i].name); 209/* printf("Detail: %s\n", states[i].name); */ 210 return states[i].quark; 211 } 212 g_assert_not_reached(); 213} 214 215static void _avahi_client_cb(AvahiClient * c, AvahiClientState state, void *data) { 216 GaClient *self = GA_CLIENT(data); 217 GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(self); 218 219/* printf("CLIENT CB: %d\n", state); */ 220 221 /* Avahi can call the callback before return from _client_new */ 222 if (self->avahi_client == NULL) 223 self->avahi_client = c; 224 225 g_assert(c == self->avahi_client); 226 priv->state = state; 227 g_signal_emit(self, signals[STATE_CHANGED], 228 detail_for_state(state), state); 229} 230 231gboolean ga_client_start(GaClient * client, GError ** error) { 232 GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(client); 233 AvahiClient *aclient; 234 int aerror; 235 236 g_assert(client->avahi_client == NULL); 237 g_assert(priv->poll == NULL); 238 239 avahi_set_allocator(avahi_glib_allocator()); 240 241 priv->poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT); 242 243 aclient = avahi_client_new(avahi_glib_poll_get(priv->poll), 244 priv->flags, 245 _avahi_client_cb, client, &aerror); 246 if (aclient == NULL) { 247 if (error != NULL) { 248 *error = g_error_new(GA_ERROR, aerror, 249 "Failed to create avahi client: %s", 250 avahi_strerror(aerror)); 251 } 252 return FALSE; 253 } 254 client->avahi_client = aclient; 255 return TRUE; 256} 257