~oif-team/geis/trunk

« back to all changes in this revision

Viewing changes to libs/geis-dbus/geis_dbus_subscription.c

  • Committer: Stephen M. Webb
  • Date: 2011-10-18 20:30:02 UTC
  • mfrom: (158.1.42 client-arch)
  • Revision ID: stephen.webb@canonical.com-20111018203002-ne8h3n25fbey3fqr
Merged client-arch branch.

Provided a new DBus-client back end and a dbus-server facility.  Included a test driver for the server.  Made the DBus client the default back-end with an automatic fall back to the XCB back end for seamless support of existing client software.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @file geis_dbus_subscription.c
 
3
 * @brief Implementation of the GEIS DBus subscription transport.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright 2011 Canonical Ltd.
 
8
 *
 
9
 * This library is free software; you can redistribute it and/or modify it under
 
10
 * the terms of the GNU Lesser General Public License as published by the Free
 
11
 * Software Foundation; either version 3 of the License, or (at your option) any
 
12
 * later version.
 
13
 *
 
14
 * This library is distributed in the hope that it will be useful, but WITHOUT
 
15
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
16
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 
17
 * details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 */
 
22
#include "geis_config.h"
 
23
#include "geis_dbus_subscription.h"
 
24
 
 
25
#include "geis_dbus.h"
 
26
#include "geis_dbus_attr.h"
 
27
#include "geis_filter_term.h"
 
28
#include "geis_logging.h"
 
29
#include "geis_subscription.h"
 
30
#include <stdint.h>
 
31
 
 
32
 
 
33
/*
 
34
 * A filter term is marshalled as a (facility, operation, value) tuple.
 
35
 * That would be a (ii(sv)) in DBusspeak.
 
36
 */
 
37
#define GEIS_DBUS_TYPE_SIGNATURE_TERM \
 
38
             DBUS_STRUCT_BEGIN_CHAR_AS_STRING \
 
39
             DBUS_TYPE_INT32_AS_STRING \
 
40
             DBUS_TYPE_INT32_AS_STRING \
 
41
             GEIS_DBUS_TYPE_SIGNATURE_ATTR \
 
42
             DBUS_STRUCT_END_CHAR_AS_STRING
 
43
 
 
44
/*
 
45
 * A term list is an array of terms, as in a(ii(sv)).
 
46
 */
 
47
#define GEIS_DBUS_TYPE_SIGNATURE_TERM_LIST \
 
48
             DBUS_TYPE_ARRAY_AS_STRING \
 
49
             GEIS_DBUS_TYPE_SIGNATURE_TERM
 
50
 
 
51
/*
 
52
 * A filter is a named array of filter terms.
 
53
 * That's a {sa(ii(sv))} in the DBus tongue.
 
54
 */
 
55
#define GEIS_DBUS_TYPE_SIGNATURE_FILTER \
 
56
             DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
 
57
             DBUS_TYPE_STRING_AS_STRING \
 
58
             GEIS_DBUS_TYPE_SIGNATURE_TERM_LIST \
 
59
             DBUS_DICT_ENTRY_END_CHAR_AS_STRING
 
60
 
 
61
 
 
62
/**
 
63
 * Adds filter terms to a DBus message.
 
64
 *
 
65
 * @param[in] filter      The filter for which terms will be marshalled.
 
66
 * @param[in] filter_iter A DBus message output iterator.
 
67
 */
 
68
static void
 
69
_geis_dbus_marshall_subscription_filter_terms(GeisFilter       filter,
 
70
                                              DBusMessageIter *filter_iter)
 
71
{
 
72
  DBusMessageIter term_list_iter;
 
73
  dbus_message_iter_open_container(filter_iter,
 
74
                                   DBUS_TYPE_ARRAY,
 
75
                                   GEIS_DBUS_TYPE_SIGNATURE_TERM,
 
76
                                   &term_list_iter);
 
77
  for (GeisSize i = 0; i < geis_filter_term_count(filter); ++i)
 
78
  {
 
79
    GeisFilterTerm term = geis_filter_term(filter, i);
 
80
    dbus_int32_t facility = geis_filter_term_facility(term);
 
81
    dbus_int32_t operation = geis_filter_term_operation(term);
 
82
    GeisAttr     attr = geis_filter_term_attr(term);
 
83
 
 
84
    DBusMessageIter term_iter;
 
85
    dbus_message_iter_open_container(&term_list_iter,
 
86
                                     DBUS_TYPE_STRUCT,
 
87
                                     NULL,
 
88
                                     &term_iter);
 
89
    dbus_message_iter_append_basic(&term_iter, DBUS_TYPE_INT32, &facility);
 
90
    dbus_message_iter_append_basic(&term_iter, DBUS_TYPE_INT32, &operation);
 
91
    geis_dbus_attr_marshall(attr, &term_iter);
 
92
    dbus_message_iter_close_container(&term_list_iter, &term_iter);
 
93
  }
 
94
  dbus_message_iter_close_container(filter_iter, &term_list_iter);
 
95
}
 
96
 
 
97
 
 
98
/**
 
99
 * Squeezes the filters on a subscription into the DBus wire protocol.
 
100
 *
 
101
 * @param[in] sub      A %GeisSubscription
 
102
 * @param[in] msg_iter The open output iterator for a DBus message.
 
103
 *
 
104
 * The filters are marshalled as an array of DBus dict entries.
 
105
 */
 
106
static void
 
107
_geis_dbus_marshall_subscription_filters(GeisSubscription  subscription,
 
108
                                         DBusMessageIter  *msg_iter)
 
109
{
 
110
  DBusMessageIter filter_list_iter;
 
111
 
 
112
  dbus_message_iter_open_container(msg_iter,
 
113
                                   DBUS_TYPE_ARRAY,
 
114
                                   GEIS_DBUS_TYPE_SIGNATURE_FILTER,
 
115
                                   &filter_list_iter);
 
116
 
 
117
  for (GeisFilterIterator it = geis_subscription_filter_begin(subscription);
 
118
       it != geis_subscription_filter_end(subscription);
 
119
       it = geis_subscription_filter_next(subscription, it))
 
120
  {
 
121
    const char *filter_name = geis_filter_name(*it);
 
122
 
 
123
    DBusMessageIter filter_iter;
 
124
    dbus_message_iter_open_container(&filter_list_iter,
 
125
                                     DBUS_TYPE_DICT_ENTRY,
 
126
                                     NULL,
 
127
                                     &filter_iter);
 
128
    dbus_message_iter_append_basic(&filter_iter, DBUS_TYPE_STRING, &filter_name);
 
129
    _geis_dbus_marshall_subscription_filter_terms(*it, &filter_iter);
 
130
    dbus_message_iter_close_container(&filter_list_iter, &filter_iter);
 
131
  }
 
132
  dbus_message_iter_close_container(msg_iter, &filter_list_iter);
 
133
}
 
134
 
 
135
 
 
136
static void
 
137
_geis_dbus_unmarshall_filter_terms(GeisFilter       filter,
 
138
                                   DBusMessageIter *filter_iter)
 
139
{
 
140
  DBusMessageIter term_list_iter;
 
141
  dbus_message_iter_recurse(filter_iter, &term_list_iter);
 
142
  for (int dtype = dbus_message_iter_get_arg_type(&term_list_iter);
 
143
       dtype != DBUS_TYPE_INVALID;
 
144
       dbus_message_iter_next(&term_list_iter),
 
145
       dtype = dbus_message_iter_get_arg_type(&term_list_iter))
 
146
  {
 
147
    int ttype = dbus_message_iter_get_arg_type(&term_list_iter);
 
148
    if (ttype != DBUS_TYPE_STRUCT)
 
149
    {
 
150
      geis_error("malformed GeisSubscription term");
 
151
      goto final_exit;
 
152
    }
 
153
 
 
154
    DBusMessageIter term_iter;
 
155
    dbus_message_iter_recurse(&term_list_iter, &term_iter);
 
156
 
 
157
    dbus_int32_t facility;
 
158
    dbus_message_iter_get_basic(&term_iter, &facility);
 
159
    dbus_message_iter_next(&term_iter);
 
160
 
 
161
    dbus_int32_t operation;
 
162
    dbus_message_iter_get_basic(&term_iter, &operation);
 
163
    dbus_message_iter_next(&term_iter);
 
164
 
 
165
    GeisAttr attr = geis_dbus_attr_unmarshall(&term_iter);
 
166
    GeisFilterTerm term = geis_filter_term_new(facility, operation, attr);
 
167
    geis_filter_add_term_internal(filter, term);
 
168
  }
 
169
 
 
170
final_exit:
 
171
  return;
 
172
}
 
173
 
 
174
 
 
175
/**
 
176
 * Unmarshalls a filter from a DBus message.
 
177
 *
 
178
 * @param[in] geis         A GEIS instance.
 
179
 * @param[in] filter_iter  A DBus message iterator pointing to the filter.
 
180
 */
 
181
static GeisFilter
 
182
_geis_dbus_unmarshall_filter(Geis geis, DBusMessageIter *filter_iter)
 
183
{
 
184
  GeisFilter filter = NULL;
 
185
 
 
186
  int ftype = dbus_message_iter_get_arg_type(filter_iter);
 
187
  if (ftype != DBUS_TYPE_DICT_ENTRY)
 
188
  {
 
189
    geis_error("malformed GeisSubscription filter");
 
190
    goto final_exit;
 
191
  }
 
192
 
 
193
  DBusMessageIter dict_iter;
 
194
  dbus_message_iter_recurse(filter_iter, &dict_iter);
 
195
 
 
196
  ftype = dbus_message_iter_get_arg_type(&dict_iter);
 
197
  if (ftype != DBUS_TYPE_STRING)
 
198
  {
 
199
    geis_error("malformed GeisSubscription filter");
 
200
    goto final_exit;
 
201
  }
 
202
  GeisString filter_name;
 
203
  dbus_message_iter_get_basic(&dict_iter, &filter_name);
 
204
  dbus_message_iter_next(&dict_iter);
 
205
 
 
206
  filter = geis_filter_new(geis, filter_name);
 
207
 
 
208
  ftype = dbus_message_iter_get_arg_type(&dict_iter);
 
209
  if (ftype != DBUS_TYPE_ARRAY)
 
210
  {
 
211
    geis_error("malformed GeisSubscription filter");
 
212
    goto final_exit;
 
213
  }
 
214
  _geis_dbus_unmarshall_filter_terms(filter, &dict_iter);
 
215
 
 
216
final_exit:
 
217
  return filter;
 
218
}
 
219
 
 
220
 
 
221
/**
 
222
 * Unmarshalls a list of filters from a DBus message.
 
223
 *
 
224
 * @param[in] geis               A GEIS instance.
 
225
 * @param[in] subscription_iter  A DBus message iterator for the subscription.
 
226
 * @param[in] subscription       A GEIS subsccription.
 
227
 *
 
228
 * This function unmarshalls filters from a GEIS DBus subscription message and
 
229
 * adds them to a existing GEIS subscription.
 
230
 */
 
231
static void
 
232
_geis_dbus_unmarshall_subscription_filters(Geis              geis,
 
233
                                           DBusMessageIter  *subscription_iter,
 
234
                                           GeisSubscription  subscription)
 
235
{
 
236
  DBusMessageIter filter_list_iter;
 
237
  dbus_message_iter_recurse(subscription_iter, &filter_list_iter);
 
238
  for (int dtype = dbus_message_iter_get_arg_type(&filter_list_iter);
 
239
       dtype != DBUS_TYPE_INVALID;
 
240
       dbus_message_iter_next(&filter_list_iter),
 
241
       dtype = dbus_message_iter_get_arg_type(&filter_list_iter))
 
242
  {
 
243
    GeisFilter filter = _geis_dbus_unmarshall_filter(geis, &filter_list_iter);
 
244
    if (filter)
 
245
    {
 
246
      geis_subscription_add_filter(subscription, filter);
 
247
    }
 
248
  }
 
249
}
 
250
 
 
251
 
 
252
/*
 
253
 * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_CREATE method call.
 
254
 */
 
255
GeisBoolean
 
256
geis_dbus_message_is_subscription_create_call(DBusMessage *message)
 
257
{
 
258
  return dbus_message_is_method_call(message,
 
259
                                     GEIS_DBUS_SERVICE_INTERFACE,
 
260
                                     GEIS_DBUS_SUBSCRIPTION_CREATE);
 
261
}
 
262
 
 
263
 
 
264
/*
 
265
 * Creates a GEIS_DBUS_SUBSCRIPTION_CREATE method call message.
 
266
 */
 
267
DBusMessage *
 
268
geis_dbus_subscription_create_call_message(GeisSubscription subscription)
 
269
{
 
270
  DBusMessage  *message   = NULL;
 
271
  GeisString    sub_name  = "dummy";
 
272
  dbus_int32_t  sub_id    = -1;
 
273
  dbus_uint32_t sub_flags = 0;
 
274
  DBusMessageIter iter;
 
275
 
 
276
  message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
 
277
                                         GEIS_DBUS_SERVICE_PATH,
 
278
                                         GEIS_DBUS_SERVICE_INTERFACE,
 
279
                                         GEIS_DBUS_SUBSCRIPTION_CREATE);
 
280
 
 
281
  if (subscription)
 
282
  {
 
283
    sub_name  = geis_subscription_name(subscription);
 
284
    sub_id    = geis_subscription_id(subscription);
 
285
    sub_flags = geis_subscription_flags(subscription);
 
286
  }
 
287
  dbus_message_iter_init_append(message, &iter);
 
288
 
 
289
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &sub_name);
 
290
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,  &sub_id);
 
291
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,  &sub_flags);
 
292
  _geis_dbus_marshall_subscription_filters(subscription, &iter);
 
293
 
 
294
  return message;
 
295
}
 
296
 
 
297
 
 
298
/*
 
299
 * Creates a %GeisSubscription from a method call message.
 
300
 */
 
301
GeisSubscription
 
302
geis_dbus_subscription_from_create_call_message(Geis geis, DBusMessage *message)
 
303
{
 
304
  DBusMessageIter  message_iter;
 
305
  dbus_message_iter_init(message, &message_iter);
 
306
 
 
307
  GeisString       client_sub_name;
 
308
  dbus_message_iter_get_basic(&message_iter, &client_sub_name);
 
309
  dbus_message_iter_next(&message_iter);
 
310
 
 
311
  dbus_int32_t     client_sub_id;
 
312
  dbus_message_iter_get_basic(&message_iter, &client_sub_id);
 
313
  dbus_message_iter_next(&message_iter);
 
314
 
 
315
  dbus_uint32_t    client_sub_flags;
 
316
  dbus_message_iter_get_basic(&message_iter, &client_sub_flags);
 
317
  dbus_message_iter_next(&message_iter);
 
318
 
 
319
  GeisSubscription subscription = NULL;
 
320
  subscription = geis_subscription_new(geis, client_sub_name, client_sub_flags);
 
321
  if (!subscription)
 
322
  {
 
323
    geis_error("error creating proxy subscription");
 
324
    goto final_exit;
 
325
  }
 
326
  intptr_t fudge = client_sub_id;
 
327
  geis_subscription_set_pdata(subscription, (GeisPointer)fudge);
 
328
 
 
329
  int dtype = dbus_message_iter_get_arg_type(&message_iter);
 
330
  if (dtype != DBUS_TYPE_ARRAY)
 
331
  {
 
332
    geis_error("malformed GeisSubscription message"
 
333
               " (expected type %c, received type %c)",
 
334
               DBUS_TYPE_ARRAY, dtype);
 
335
    goto final_exit;
 
336
  }
 
337
 
 
338
  _geis_dbus_unmarshall_subscription_filters(geis, &message_iter, subscription);
 
339
 
 
340
final_exit:
 
341
  return subscription;
 
342
}
 
343
 
 
344
 
 
345
/*
 
346
 * Creates a GEIS_DBUS_SUBSCRIPTION_CREATE method return message.
 
347
 */
 
348
DBusMessage *
 
349
geis_dbus_subscription_create_return_message(DBusMessage      *message,
 
350
                                             GeisSubscription  subscription)
 
351
{
 
352
  DBusMessage *reply = dbus_message_new_method_return(message);
 
353
  intptr_t fudge = (intptr_t)geis_subscription_pdata(subscription);
 
354
  dbus_int32_t client_sub_id = fudge;
 
355
  dbus_int32_t server_sub_id = geis_subscription_id(subscription);
 
356
  dbus_message_append_args(reply,
 
357
                           DBUS_TYPE_INT32, &client_sub_id,
 
358
                           DBUS_TYPE_INT32, &server_sub_id,
 
359
                           DBUS_TYPE_INVALID);
 
360
 
 
361
  return reply;
 
362
}
 
363
 
 
364
 
 
365
/*
 
366
 * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_ACTIVATE message.
 
367
 */
 
368
GeisBoolean
 
369
geis_dbus_message_is_subscription_activate_call(DBusMessage *message)
 
370
{
 
371
  return dbus_message_is_method_call(message,
 
372
                                     GEIS_DBUS_SERVICE_INTERFACE,
 
373
                                     GEIS_DBUS_SUBSCRIPTION_ACTIVATE);
 
374
}
 
375
 
 
376
 
 
377
/*
 
378
 * Creates a GEIS_DBUS_SUBSCRIPTION_ACTIVATE method call message.
 
379
 */
 
380
DBusMessage *
 
381
geis_dbus_subscription_activate_call_message(GeisSubscription subscription)
 
382
{
 
383
  DBusMessage *message   = NULL;
 
384
  DBusMessageIter iter;
 
385
 
 
386
  message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
 
387
                                         GEIS_DBUS_SERVICE_PATH,
 
388
                                         GEIS_DBUS_SERVICE_INTERFACE,
 
389
                                         GEIS_DBUS_SUBSCRIPTION_ACTIVATE);
 
390
  dbus_message_iter_init_append(message, &iter);
 
391
 
 
392
  dbus_int32_t subscription_id = geis_subscription_id(subscription);
 
393
  dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &subscription_id);
 
394
  _geis_dbus_marshall_subscription_filters(subscription, &iter);
 
395
  return message;
 
396
}
 
397
 
 
398
 
 
399
/*
 
400
 * Creates a GEIS_DBUS_SUBSCRIPTION_ACTIVATE method return message.
 
401
 */
 
402
DBusMessage *
 
403
geis_dbus_subscription_activate_return_message(DBusMessage      *message,
 
404
                                               GeisSubscription  subscription)
 
405
{
 
406
  DBusMessage *reply   = NULL;
 
407
  reply = dbus_message_new_method_return(message);
 
408
  dbus_int32_t subscription_id = -1;
 
409
 
 
410
  if (subscription)
 
411
  {
 
412
    subscription_id = geis_subscription_id(subscription);
 
413
  }
 
414
  dbus_message_append_args(reply,
 
415
                           DBUS_TYPE_INT32, &subscription_id,
 
416
                           DBUS_TYPE_INVALID);
 
417
  return reply;
 
418
}
 
419
 
 
420
 
 
421
/*
 
422
 * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_DEACTIVATE message.
 
423
 */
 
424
GeisBoolean
 
425
geis_dbus_message_is_subscription_deactivate_call(DBusMessage *message)
 
426
{
 
427
  return dbus_message_is_method_call(message,
 
428
                                     GEIS_DBUS_SERVICE_INTERFACE,
 
429
                                     GEIS_DBUS_SUBSCRIPTION_DEACTIVATE);
 
430
}
 
431
 
 
432
 
 
433
/*
 
434
 * Creates a GEIS_DBUS_SUBSCRIPTION_DEACTIVATE method call message.
 
435
 */
 
436
DBusMessage *
 
437
geis_dbus_subscription_deactivate_call_message(GeisSubscription subscription GEIS_UNUSED)
 
438
{
 
439
  DBusMessage *message   = NULL;
 
440
  message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
 
441
                                         GEIS_DBUS_SERVICE_PATH,
 
442
                                         GEIS_DBUS_SERVICE_INTERFACE,
 
443
                                         GEIS_DBUS_SUBSCRIPTION_DEACTIVATE);
 
444
  return message;
 
445
}
 
446
 
 
447
 
 
448
/**
 
449
 */
 
450
DBusMessage *
 
451
geis_dbus_subscription_deactivate_return_message(DBusMessage      *message,
 
452
                                                 GeisSubscription  subscription)
 
453
{
 
454
  DBusMessage *reply   = NULL;
 
455
  reply = dbus_message_new_method_return(message);
 
456
  dbus_int32_t subscription_id = geis_subscription_id(subscription);
 
457
  dbus_message_append_args(reply,
 
458
                           DBUS_TYPE_INT32, &subscription_id,
 
459
                           DBUS_TYPE_INVALID);
 
460
  return reply;
 
461
}
 
462
 
 
463
 
 
464
/*
 
465
 * Indicates if a DBus message is a GEIS_DBUS_SUBSCRIPTION_DESTROY message.
 
466
 */
 
467
GeisBoolean
 
468
geis_dbus_message_is_subscription_destroy_call(DBusMessage *message)
 
469
{
 
470
  return dbus_message_is_method_call(message,
 
471
                                     GEIS_DBUS_SERVICE_INTERFACE,
 
472
                                     GEIS_DBUS_SUBSCRIPTION_DESTROY);
 
473
}
 
474
 
 
475
 
 
476
/*
 
477
 * Creates a GEIS_DBUS_SUBSCRIPTION_DESTROY method call message.
 
478
 */
 
479
DBusMessage *
 
480
geis_dbus_subscription_destroy_call_message(GeisSubscription subscription)
 
481
{
 
482
  DBusMessage  *message   = NULL;
 
483
  message = dbus_message_new_method_call(GEIS_DBUS_SERVICE_INTERFACE,
 
484
                                         GEIS_DBUS_SERVICE_PATH,
 
485
                                         GEIS_DBUS_SERVICE_INTERFACE,
 
486
                                         GEIS_DBUS_SUBSCRIPTION_DESTROY);
 
487
 
 
488
  dbus_int32_t server_sub_id = (intptr_t)geis_subscription_pdata(subscription);
 
489
  dbus_message_append_args(message,
 
490
                           DBUS_TYPE_INT32, &server_sub_id,
 
491
                           DBUS_TYPE_INVALID);
 
492
 
 
493
  return message;
 
494
}
 
495
 
 
496
 
 
497
/*
 
498
 * Creates a GEIS_DBUS_SUBSCRIPTION_DESTROY method return message.
 
499
 */
 
500
DBusMessage *
 
501
geis_dbus_subscription_destroy_return_message(DBusMessage *message)
 
502
{
 
503
 return dbus_message_new_method_return(message);
 
504
}
 
505
 
 
506