~ubuntu-branches/ubuntu/saucy/dee/saucy-proposed

« back to all changes in this revision

Viewing changes to src/dee-server.c

  • Committer: Package Import Robot
  • Author(s): Didier Roche
  • Date: 2012-02-03 11:38:57 UTC
  • mfrom: (1.1.15)
  • Revision ID: package-import@ubuntu.com-20120203113857-a46h5kyigogedqy2
Tags: 1.0.2-0ubuntu1
* New upstream release.
  - DeeModel support insert_sorted() and find_sorted() (LP: #913128)
* debian/control:
  - requires now libicu-dev
* debian/libdee-1.0-4.symbols:
  - updated

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
#endif
34
34
 
35
35
#include <gio/gio.h>
 
36
#include <gio/gunixsocketaddress.h>
36
37
 
37
38
#include "dee-server.h"
38
39
#include "dee-marshal.h"
43
44
#define GET_PRIVATE(o) \
44
45
      (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEE_TYPE_SERVER, DeeServerPrivate))
45
46
 
 
47
#define ACTIVE_CONNECTIONS_KEY "dee-active-connections-list"
 
48
#define CONNECTION_ACCEPTED_KEY "dee-connection-accepted"
 
49
 
46
50
/**
47
51
 * DeeServerPrivate:
48
52
 *
75
79
};
76
80
 
77
81
//static guint32 _server_signals[LAST_SIGNAL] = { 0 };
 
82
static GHashTable *active_servers = NULL;
78
83
 
79
84
/* Forwards */
80
85
static gboolean on_new_connection               (GDBusServer *server,
134
139
    }
135
140
}
136
141
 
 
142
static void
 
143
remove_connection (GDBusConnection *connection, gboolean remote_peer_vanished,
 
144
                   GError *error, GDBusServer *server)
 
145
{
 
146
  GSList *list;
 
147
 
 
148
  trace_object (server, "Removing [%p] from list of active connections",
 
149
                connection);
 
150
  list = (GSList*) g_object_steal_data (G_OBJECT (server),
 
151
                                        ACTIVE_CONNECTIONS_KEY);
 
152
 
 
153
  list = g_slist_remove (list, connection);
 
154
 
 
155
  g_object_set_data_full (G_OBJECT (server), ACTIVE_CONNECTIONS_KEY,
 
156
                          list, (GDestroyNotify) g_slist_free);
 
157
}
 
158
 
 
159
static void
 
160
connection_finalized (gpointer server, GObject *connection)
 
161
{
 
162
  remove_connection ((GDBusConnection*) connection, FALSE, NULL,
 
163
                     (GDBusServer*) server);
 
164
}
 
165
 
137
166
static gboolean
138
 
initialize_server (DeeServer *self)
139
 
{
140
 
  DeeServerPrivate *priv;
 
167
add_new_connection (GDBusServer *server, GDBusConnection *connection,
 
168
                    gpointer user_data)
 
169
{
 
170
  GSList *list;
 
171
  gpointer *data;
 
172
 
 
173
  data = g_object_steal_data (G_OBJECT (connection), CONNECTION_ACCEPTED_KEY);
 
174
 
 
175
  if (data != NULL)
 
176
    {
 
177
      list = (GSList*) g_object_steal_data (G_OBJECT (server),
 
178
                                            ACTIVE_CONNECTIONS_KEY);
 
179
      list = g_slist_prepend (list, connection);
 
180
      g_object_set_data_full (G_OBJECT (server), ACTIVE_CONNECTIONS_KEY,
 
181
                              list, (GDestroyNotify) g_slist_free);
 
182
 
 
183
      g_signal_connect (connection, "closed",
 
184
                        G_CALLBACK (remove_connection), server);
 
185
      /* the connections in our list are weak references, need to make sure
 
186
       * they're not used after they're freed */
 
187
      g_object_weak_ref (G_OBJECT (connection), connection_finalized, server);
 
188
    }
 
189
 
 
190
  /* accept the connection if any of the DeeServers accepted it */
 
191
  return data != NULL;
 
192
}
 
193
 
 
194
static void
 
195
server_toggle_cb (gpointer data, GObject *object, gboolean is_last_ref)
 
196
{
 
197
  GSList *list, *iter;
 
198
  if (!is_last_ref) return;
 
199
 
 
200
  g_hash_table_remove (active_servers, data);
 
201
 
 
202
  g_dbus_server_stop (G_DBUS_SERVER (object));
 
203
 
 
204
  list = (GSList*) g_object_get_data (object, ACTIVE_CONNECTIONS_KEY);
 
205
  for (iter = list; iter != NULL; iter = iter->next)
 
206
    {
 
207
      g_object_weak_unref (iter->data, connection_finalized, object);
 
208
      g_signal_handlers_disconnect_by_func (iter->data,
 
209
                                            remove_connection, object);
 
210
    }
 
211
 
 
212
  /* and this will finalize the object */
 
213
  g_object_remove_toggle_ref (object, server_toggle_cb, data);
 
214
}
 
215
 
 
216
static GDBusServer*
 
217
get_server_for_address (const gchar *bus_address, GError **error)
 
218
{
141
219
  gchar            *guid;
 
220
  gchar            *address;
 
221
  GDBusServer      *server;
142
222
  GDBusServerFlags  server_flags;
 
223
 
 
224
  server = g_hash_table_lookup (active_servers, bus_address);
 
225
  if (server != NULL)
 
226
    {
 
227
      return g_object_ref (server);
 
228
    }
 
229
 
 
230
  /* create new GDBusServer instance */
 
231
  guid = g_dbus_generate_guid ();
 
232
  server_flags = G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
 
233
 
 
234
  server = g_dbus_server_new_sync (bus_address, server_flags, guid,
 
235
                                   NULL, NULL, error);
 
236
 
 
237
  if (error && *error) return NULL;
 
238
 
 
239
  /* need to keep a list of all connections for this GDBusServer */
 
240
  g_signal_connect_after (server, "new-connection",
 
241
                          G_CALLBACK (add_new_connection), NULL);
 
242
 
 
243
  address = g_strdup (bus_address);
 
244
  /* transfer ownership of address to the hash table */
 
245
  g_hash_table_insert (active_servers, address, server);
 
246
  /* we need to stop the server before unreffing it the last time, so we'll
 
247
   * use toggle ref. FIXME: toggle ref is odd, use just weak ref (to remove
 
248
   * it from the active_servers hash table) once it properly stops
 
249
   * the listener on finalize. */
 
250
  g_object_add_toggle_ref (G_OBJECT (server), server_toggle_cb, address);
 
251
 
 
252
  g_free (guid);
 
253
 
 
254
  return server;
 
255
}
 
256
 
 
257
static gboolean
 
258
initialize_server (DeeServer *self)
 
259
{
 
260
  DeeServerPrivate *priv;
 
261
  GSList           *connections;
143
262
  GError           *error = NULL;
144
263
 
145
264
  priv = self->priv;
146
265
 
147
266
  priv->initialize_server_timer_id = 0;
148
267
 
149
 
  guid = g_dbus_generate_guid ();
150
 
  server_flags = G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
151
 
 
152
 
  priv->server = g_dbus_server_new_sync (priv->bus_address,
153
 
                                         server_flags,
154
 
                                         guid,
155
 
                                         NULL,
156
 
                                         NULL,
157
 
                                         &error);
 
268
  /* create new server or get the existing instance for this bus_address */
 
269
  priv->server = get_server_for_address (priv->bus_address, &error);
158
270
 
159
271
  if (error)
160
272
    {
161
273
      g_critical ("Unable to set up DBusServer: %s", error->message);
162
274
 
163
275
      g_error_free (error);
164
 
      g_free (guid);
165
276
 
166
277
      g_object_notify (G_OBJECT (self), "swarm-leader");
167
278
      return FALSE;
174
285
 
175
286
  g_object_notify (G_OBJECT (self), "swarm-leader");
176
287
 
177
 
  g_free (guid);
 
288
  /* were there any connections already? */
 
289
  connections = (GSList*) g_object_get_data (G_OBJECT (priv->server),
 
290
                                             ACTIVE_CONNECTIONS_KEY);
 
291
  for ( ; connections != NULL; connections = connections->next)
 
292
    {
 
293
      on_new_connection (priv->server, (GDBusConnection*) connections->data,
 
294
                         self);
 
295
    }
178
296
 
179
297
  return FALSE;
180
298
}
202
320
 
203
321
  if (!priv->bus_address)
204
322
  {
205
 
    const gchar *username = g_get_user_name ();
206
 
    priv->bus_address = g_strdup_printf ("unix:abstract=%s-%s",
207
 
                                         username, swarm_name);
 
323
    priv->bus_address = dee_server_bus_address_for_name (swarm_name, 
 
324
                                                         priv->same_user_only);
208
325
  }
209
326
 
210
327
  /* Ideally we'd call the async variant of g_dbus_server_new (which doesn't
222
339
                                        user_data);
223
340
 
224
341
  // FIXME: should we use the sync variant? and flush first?
225
 
  g_dbus_connection_close (connection, NULL, NULL, NULL);
 
342
  //g_dbus_connection_close (connection, NULL, NULL, NULL);
226
343
}
227
344
 
228
345
static void
296
413
   * DeeServer::bus-address:
297
414
   *
298
415
   * D-Bus address the server is bound to. If you do not specify this property
299
 
   * DeeServer will try to use abstract unix domain socket where its name is
300
 
   * a concatenation of user name running current process and the swarm name.
301
 
   * You can use dee_server_get_client_address to get address string
302
 
   * that can be used by clients to connect to.
 
416
   * #DeeServer will use dee_server_bus_address_for_name() using current swarm
 
417
   * name to determine the value of this property.
 
418
   * You can use dee_server_get_client_address() to get address string
 
419
   * that can be used by clients to connect to this #DeeServer instance.
303
420
   */
304
421
  pspec = g_param_spec_string ("bus-address", "Bus address",
305
422
                               "Bus address to use for the connection",
320
437
                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
321
438
                                | G_PARAM_STATIC_STRINGS);
322
439
  g_object_class_install_property (object_class, PROP_SAME_USER_ONLY, pspec);
 
440
 
 
441
  /* we'll use this variable to share GDBusServer instances between mutliple
 
442
   * DeeServers - this will enable us to use one connection with multiple
 
443
   * models with different swarm_names */
 
444
  active_servers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
323
445
}
324
446
 
325
447
static void
335
457
 
336
458
/**
337
459
 * dee_server_new:
338
 
 *
339
460
 * @swarm_name: Name of swarm to join.
340
461
 *
341
462
 * Creates a new instance of #DeeServer and tries to bind 
342
463
 * to #DeeServer:bus-address. The #DeePeer:swarm-leader property will be set
343
464
 * when the binding succeeds.
344
465
 *
 
466
 * <note>
 
467
 *   <para>
 
468
 *     Note that this function will automatically determine the value
 
469
 *     of #DeeServer:bus-address property and will generally cause your
 
470
 *     application to use new socket for every #DeeServer with different swarm
 
471
 *     name. See dee_server_new_for_address() if you'd like to share one
 
472
 *     connection between multiple #DeeServer instances.
 
473
 *   </para>
 
474
 * </note>
 
475
 *
345
476
 * Return value: (transfer full): A newly constructed #DeeServer.
346
477
 */
347
478
DeeServer*
355
486
 
356
487
/**
357
488
 * dee_server_new_for_address:
358
 
 *
359
489
 * @swarm_name: Name of swarm to join.
360
490
 * @bus_address: D-Bus address to use for the connection.
361
491
 *
362
492
 * Creates a new instance of #DeeServer and tries to bind to @bus_address.
363
493
 * The #DeePeer:swarm-leader property will be set when the binding succeeds.
364
494
 *
 
495
 * If there is already a #DeeServer instance bound to @bus_address,
 
496
 * the connection will be shared with the newly constructed instance.
 
497
 *
 
498
 * <note>
 
499
 *   <para>
 
500
 *     This function is primarily meant for sharing of one connection (socket)
 
501
 *     between multiple DeeServers, so that you can create #DeeServer instances
 
502
 *     with varying swarm names, but the same bus address, which will cause
 
503
 *     them to share the connection (the sharing is possible only within
 
504
 *     the same process though).
 
505
 *   </para>
 
506
 * </note>
 
507
 *
365
508
 * Return value: (transfer full): A newly constructed #DeeServer.
366
509
 */
367
510
DeeServer*
376
519
 
377
520
/**
378
521
 * dee_server_get_client_address:
379
 
 *
380
 
 * @self: A #DeeServer.
 
522
 * @server: A #DeeServer.
381
523
 *
382
524
 * Gets a D-Bus address string that can be used by clients to connect to server.
383
525
 *
395
537
    g_dbus_server_get_client_address (priv->server) : NULL;
396
538
}
397
539
 
 
540
/**
 
541
 * dee_server_bus_address_for_name:
 
542
 * @name: A name to create bus address for.
 
543
 * @include_username: Include current user name as part of the bus address.
 
544
 *
 
545
 * Helper method which creates bus address string for the given name, which
 
546
 * should have the same format as a DBus unique name.
 
547
 * 
 
548
 * Return value: (transfer full): Newly allocated string with bus address.
 
549
 *                                Use g_free() to free.
 
550
 */
 
551
gchar*
 
552
dee_server_bus_address_for_name (const gchar *name, gboolean include_username)
 
553
{
 
554
  gchar *result;
 
555
 
 
556
  g_return_val_if_fail (name != NULL, NULL);
 
557
 
 
558
  if (g_unix_socket_address_abstract_names_supported ())
 
559
    {
 
560
      result = include_username ? 
 
561
        g_strdup_printf ("unix:abstract=%s-%s", g_get_user_name (), name) :
 
562
        g_strdup_printf ("unix:abstract=%s", name);
 
563
    }
 
564
  else
 
565
    {
 
566
      result = include_username ?
 
567
        g_strdup_printf ("unix:path=%s/%s-%s", g_get_tmp_dir (), 
 
568
                                               g_get_user_name (), name) :
 
569
        g_strdup_printf ("unix:path=%s/%s", g_get_tmp_dir (), name);
 
570
    }
 
571
 
 
572
  return result;
 
573
}
 
574
 
398
575
/* Private Methods */
399
576
static gboolean
400
577
on_new_connection (GDBusServer *server,
433
610
 
434
611
  g_signal_emit_by_name (self, "peer-found", connection_name);
435
612
 
436
 
  return TRUE;
 
613
  g_object_set_data (G_OBJECT (connection), CONNECTION_ACCEPTED_KEY,
 
614
                     GINT_TO_POINTER (1));
 
615
 
 
616
  /* we can't return TRUE, otherwise handlers in other DeeServers wouldn't run,
 
617
   * see add_new_connection callback */
 
618
  return FALSE;
437
619
}
438
620
 
439
621
static void