2
* Copyright (C) 2011 Canonical, Ltd.
4
* This library is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License
6
* version 3.0 as published by the Free Software Foundation.
8
* This library is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License version 3.0 for more details.
13
* You should have received a copy of the GNU Lesser General Public
14
* License along with this library. If not, see
15
* <http://www.gnu.org/licenses/>.
17
* Authored by: Michal Hruby <michal.hruby@canonical.com>
22
* @short_description: Creates a client object you can use to connect
26
* #DeeClient is the endpoint for connecting to #DeeServer.
35
#include "dee-client.h"
36
#include "dee-marshal.h"
37
#include "trace-log.h"
39
G_DEFINE_TYPE (DeeClient, dee_client, DEE_TYPE_PEER)
41
#define GET_PRIVATE(o) \
42
(G_TYPE_INSTANCE_GET_PRIVATE ((o), DEE_TYPE_CLIENT, DeeClientPrivate))
47
* Ignore this structure.
49
struct _DeeClientPrivate
51
GDBusConnection *connection;
52
GCancellable *cancellable;
55
guint peer_found_timer_id;
56
gulong closed_signal_handler_id;
71
//static guint32 _server_signals[LAST_SIGNAL] = { 0 };
74
static gboolean dee_client_is_swarm_leader (DeePeer *peer);
76
static const gchar* dee_client_get_swarm_leader (DeePeer *peer);
78
static GSList* dee_client_get_connections (DeePeer *peer);
80
static gchar** dee_client_list_peers (DeePeer *peer);
82
static void connecting_finished (GObject *object,
86
static void connection_closed (GDBusConnection *connection,
87
gboolean remote_peer_vanished,
93
dee_client_get_property (GObject *object, guint property_id,
94
GValue *value, GParamSpec *pspec)
96
DeeClientPrivate *priv;
98
priv = DEE_CLIENT (object)->priv;
102
case PROP_BUS_ADDRESS:
103
g_value_set_string (value, priv->bus_address);
106
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
111
dee_client_set_property (GObject *object, guint property_id,
112
const GValue *value, GParamSpec *pspec)
114
DeeClientPrivate *priv;
116
priv = DEE_CLIENT (object)->priv;
120
case PROP_BUS_ADDRESS:
121
if (priv->bus_address) g_free (priv->bus_address);
122
priv->bus_address = g_value_dup_string (value);
125
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
130
dee_client_constructed (GObject *self)
132
DeeClientPrivate *priv;
133
const gchar *swarm_name;
134
GDBusConnectionFlags flags;
136
priv = DEE_CLIENT (self)->priv;
138
/* we should chain up the constructed method here, but peer does things we
139
* don't want to, so not chaining up... */
141
swarm_name = dee_peer_get_swarm_name (DEE_PEER (self));
142
if (swarm_name == NULL)
144
g_critical ("DeeClient created without a swarm name. You must specify "
145
"a non-NULL swarm name");
149
if (!priv->bus_address)
151
const gchar *username = g_get_user_name ();
152
priv->bus_address = g_strdup_printf ("unix:abstract=%s-%s",
153
username, swarm_name);
156
flags = G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT;
157
priv->cancellable = g_cancellable_new ();
158
g_dbus_connection_new_for_address (priv->bus_address,
160
NULL, // AuthObserver
167
dee_client_finalize (GObject *object)
169
DeeClientPrivate *priv;
171
priv = DEE_CLIENT (object)->priv;
173
if (priv->cancellable)
175
g_cancellable_cancel (priv->cancellable);
176
g_object_unref (priv->cancellable);
179
if (priv->closed_signal_handler_id)
181
g_signal_handler_disconnect (priv->connection,
182
priv->closed_signal_handler_id);
183
priv->closed_signal_handler_id = 0;
186
if (priv->connection)
188
// FIXME: close the connection?
189
g_object_unref (priv->connection);
192
if (priv->peer_found_timer_id)
194
g_source_remove (priv->peer_found_timer_id);
195
priv->peer_found_timer_id = 0;
198
if (priv->bus_address)
200
g_free (priv->bus_address);
203
G_OBJECT_CLASS (dee_client_parent_class)->finalize (object);
207
dee_client_class_init (DeeClientClass *klass)
210
GObjectClass *object_class = G_OBJECT_CLASS (klass);
211
DeePeerClass *peer_class = DEE_PEER_CLASS (klass);
213
g_type_class_add_private (klass, sizeof (DeeClientPrivate));
215
object_class->constructed = dee_client_constructed;
216
object_class->get_property = dee_client_get_property;
217
object_class->set_property = dee_client_set_property;
218
object_class->finalize = dee_client_finalize;
220
peer_class->is_swarm_leader = dee_client_is_swarm_leader;
221
peer_class->get_swarm_leader = dee_client_get_swarm_leader;
222
peer_class->get_connections = dee_client_get_connections;
223
peer_class->list_peers = dee_client_list_peers;
226
* DeeClient::bus-address:
228
* D-Bus address the client will connect to. If you do not specify this
229
* property DeeClient will try to use abstract unix domain socket where
230
* its name is a concatenation of user name running current process and
233
pspec = g_param_spec_string ("bus-address", "Bus address",
234
"Bus address to use for the connection",
236
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
237
| G_PARAM_STATIC_STRINGS);
238
g_object_class_install_property (object_class, PROP_BUS_ADDRESS, pspec);
242
dee_client_init (DeeClient *self)
244
self->priv = GET_PRIVATE (self);
250
* @swarm_name: Name of swarm to join.
252
* Creates a new instance of #DeeClient and tries to connect to #DeeServer
253
* created using dee_server_new(). The #DeePeer:swarm-leader property will
254
* be set once the client connects.
256
* Return value: (transfer full): A newly constructed #DeeClient.
259
dee_client_new (const gchar* swarm_name)
261
g_return_val_if_fail (swarm_name != NULL, NULL);
263
return DEE_CLIENT (g_object_new (DEE_TYPE_CLIENT,
264
"swarm-name", swarm_name, NULL));
268
* dee_client_new_for_address:
270
* @swarm_name: Name of swarm to join.
271
* @bus_address: D-Bus address to use when connecting to the server.
273
* Creates a new instance of #DeeClient and tries to connect to @bus_address.
274
* The #DeePeer:swarm-leader property will be set once the client connects.
276
* Return value: (transfer full): A newly constructed #DeeClient.
279
dee_client_new_for_address (const gchar* swarm_name,
280
const gchar* bus_address)
282
g_return_val_if_fail (swarm_name != NULL, NULL);
284
return DEE_CLIENT (g_object_new (DEE_TYPE_CLIENT,
285
"swarm-name", swarm_name,
286
"bus-address", bus_address, NULL));
289
/* Private Methods */
292
dee_client_is_swarm_leader (DeePeer *peer)
298
dee_client_get_swarm_leader (DeePeer *peer)
300
DeeClientPrivate *priv;
302
priv = DEE_CLIENT (peer)->priv;
303
return priv->connection ? g_dbus_connection_get_guid (priv->connection) : NULL;
307
dee_client_get_connections (DeePeer *peer)
309
DeeClientPrivate *priv;
312
priv = DEE_CLIENT (peer)->priv;
314
if (priv->connection)
316
list = g_slist_append (list, priv->connection);
323
dee_client_list_peers (DeePeer *peer)
325
DeeClientPrivate *priv;
329
priv = DEE_CLIENT (peer)->priv;
331
result = g_new (gchar*, priv->connection ? 2 : 1);
333
if (priv->connection)
335
result[i++] = g_strdup (g_dbus_connection_get_guid (priv->connection));
343
emit_peer_found (gpointer user_data)
345
g_return_val_if_fail (DEE_IS_CLIENT (user_data), FALSE);
347
DeeClientPrivate *priv = DEE_CLIENT (user_data)->priv;
349
g_signal_emit_by_name (user_data, "peer-found",
350
g_dbus_connection_get_guid (priv->connection));
352
priv->peer_found_timer_id = 0;
358
connecting_finished (GObject *object, GAsyncResult *res, gpointer user_data)
360
GDBusConnection *connection;
362
DeeClientPrivate *priv;
363
GError *error = NULL;
365
connection = g_dbus_connection_new_for_address_finish (res, &error);
369
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
371
g_warning ("Unable to connect to server: %s", error->message);
372
// swarm-leader will be set to NULL for unsuccessful connections
373
g_object_notify (G_OBJECT (user_data), "swarm-leader");
375
/* Don't touch the object in case we were cancelled, it's most likely
378
g_error_free (error);
382
self = DEE_CLIENT (user_data);
384
priv->connection = connection;
386
g_object_unref (priv->cancellable);
387
priv->cancellable = NULL;
389
priv->closed_signal_handler_id = g_signal_connect (connection, "closed",
390
G_CALLBACK (connection_closed), self);
392
g_object_notify (G_OBJECT (user_data), "swarm-leader");
394
g_signal_emit_by_name (user_data, "connection-acquired", connection);
396
// FIXME: we might want to call some List method (same as DeePeer), so far
397
// we'll just simulate an async method (tests expect this anyway)
398
priv->peer_found_timer_id = g_idle_add_full (G_PRIORITY_DEFAULT,
399
emit_peer_found, user_data,
404
connection_closed (GDBusConnection *connection, gboolean remote_peer_vanished,
405
GError *error, DeeClient *client)
407
DeeClientPrivate *priv;
409
g_return_if_fail (DEE_IS_CLIENT (client));
412
priv->connection = NULL;
414
g_signal_handler_disconnect (connection, priv->closed_signal_handler_id);
415
priv->closed_signal_handler_id = 0;
417
/* Let's do reverse order of connecting_finished */
418
g_signal_emit_by_name (client, "peer-lost",
419
g_dbus_connection_get_guid (priv->connection));
420
g_signal_emit_by_name (client, "connection-closed", connection);
422
g_object_notify (G_OBJECT (client), "swarm-leader");
424
g_object_unref (connection);