~ubuntu-branches/ubuntu/saucy/sssd/saucy

« back to all changes in this revision

Viewing changes to server/sbus/sssd_dbus_common.c

  • Committer: Stéphane Graber
  • Date: 2011-06-15 16:23:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: stgraber@ubuntu.com-20110615162314-rbhoppnpaxfqo5q7
Merge 1.5.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    Authors:
3
 
        Simo Sorce <ssorce@redhat.com>
4
 
        Stephen Gallagher <sgallagh@redhat.com>
5
 
 
6
 
    Copyright (C) 2009 Red Hat
7
 
 
8
 
    This program is free software; you can redistribute it and/or modify
9
 
    it under the terms of the GNU General Public License as published by
10
 
    the Free Software Foundation; either version 3 of the License, or
11
 
    (at your option) any later version.
12
 
 
13
 
    This program is distributed in the hope that it will be useful,
14
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
    GNU General Public License for more details.
17
 
 
18
 
    You should have received a copy of the GNU General Public License
19
 
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 
*/
21
 
 
22
 
#include <sys/time.h>
23
 
#include "tevent.h"
24
 
#include "dbus/dbus.h"
25
 
#include "util/util.h"
26
 
#include "sbus/sssd_dbus.h"
27
 
#include "sbus/sssd_dbus_private.h"
28
 
 
29
 
/* =Watches=============================================================== */
30
 
 
31
 
/* DBUS may ask us to add a watch to a file descriptor that already had a watch
32
 
 * associated. Need to check if that's the case */
33
 
static struct sbus_watch_ctx *fd_to_watch(struct sbus_watch_ctx *list, int fd)
34
 
{
35
 
    struct sbus_watch_ctx *watch_iter;
36
 
 
37
 
    watch_iter = list;
38
 
    while (watch_iter != NULL) {
39
 
        if (watch_iter->fd == fd) {
40
 
            return watch_iter;
41
 
        }
42
 
 
43
 
        watch_iter = watch_iter->next;
44
 
    }
45
 
 
46
 
    return NULL;
47
 
}
48
 
 
49
 
static int watch_destructor(void *mem)
50
 
{
51
 
    struct sbus_watch_ctx *watch;
52
 
 
53
 
    watch = talloc_get_type(mem, struct sbus_watch_ctx);
54
 
    DLIST_REMOVE(watch->conn->watch_list, watch);
55
 
 
56
 
    return 0;
57
 
}
58
 
 
59
 
/*
60
 
 * watch_handler
61
 
 * Callback for D-BUS to handle messages on a file-descriptor
62
 
 */
63
 
static void sbus_watch_handler(struct tevent_context *ev,
64
 
                               struct tevent_fd *fde,
65
 
                               uint16_t flags, void *data)
66
 
{
67
 
    struct sbus_watch_ctx *watch = talloc_get_type(data,
68
 
                                                   struct sbus_watch_ctx);
69
 
    enum dbus_conn_type type;
70
 
    union dbus_conn_pointer dbus_p;
71
 
 
72
 
    /* conn may get freed inside a handle, save the data we need for later */
73
 
    type = watch->conn->type;
74
 
    dbus_p = watch->conn->dbus;
75
 
 
76
 
    /* Take a reference while handling watch */
77
 
    if (type == SBUS_SERVER) {
78
 
        dbus_server_ref(dbus_p.server);
79
 
    } else {
80
 
        dbus_connection_ref(dbus_p.conn);
81
 
    }
82
 
 
83
 
    /* Fire if readable */
84
 
    if (flags & TEVENT_FD_READ) {
85
 
        if (watch->dbus_read_watch) {
86
 
            dbus_watch_handle(watch->dbus_read_watch, DBUS_WATCH_READABLE);
87
 
        }
88
 
    }
89
 
 
90
 
    /* Fire if writeable */
91
 
    if (flags & TEVENT_FD_WRITE) {
92
 
        if (watch->dbus_write_watch) {
93
 
            dbus_watch_handle(watch->dbus_write_watch, DBUS_WATCH_WRITABLE);
94
 
        }
95
 
    }
96
 
 
97
 
    /* Release reference once done */
98
 
    if (type == SBUS_SERVER) {
99
 
        dbus_server_unref(dbus_p.server);
100
 
    } else {
101
 
        dbus_connection_unref(dbus_p.conn);
102
 
    }
103
 
}
104
 
 
105
 
/*
106
 
 * add_watch
107
 
 * Set up hooks into the libevents mainloop for
108
 
 * D-BUS to add file descriptor-based events
109
 
 */
110
 
dbus_bool_t sbus_add_watch(DBusWatch *dbus_watch, void *data)
111
 
{
112
 
    unsigned int flags;
113
 
    uint16_t event_flags;
114
 
    struct sbus_connection *conn;
115
 
    struct sbus_watch_ctx *watch;
116
 
    dbus_bool_t enabled;
117
 
    int fd;
118
 
 
119
 
    conn = talloc_get_type(data, struct sbus_connection);
120
 
 
121
 
#ifdef HAVE_DBUS_WATCH_GET_UNIX_FD
122
 
    fd = dbus_watch_get_unix_fd(dbus_watch);
123
 
#else
124
 
    fd = dbus_watch_get_fd(dbus_watch);
125
 
#endif
126
 
 
127
 
    watch = fd_to_watch(conn->watch_list, fd);
128
 
    if (!watch) {
129
 
        /* does not exist, allocate new one */
130
 
        watch = talloc_zero(conn, struct sbus_watch_ctx);
131
 
        if (!watch) {
132
 
            DEBUG(0, ("Out of Memory!\n"));
133
 
            return FALSE;
134
 
        }
135
 
        watch->conn = conn;
136
 
        watch->fd = fd;
137
 
    }
138
 
 
139
 
    enabled = dbus_watch_get_enabled(dbus_watch);
140
 
    flags = dbus_watch_get_flags(dbus_watch);
141
 
 
142
 
    /* Save the event to the watch object so it can be found later */
143
 
    if (flags & DBUS_WATCH_READABLE) {
144
 
        watch->dbus_read_watch = dbus_watch;
145
 
    }
146
 
    if (flags & DBUS_WATCH_WRITABLE) {
147
 
        watch->dbus_write_watch = dbus_watch;
148
 
    }
149
 
    dbus_watch_set_data(dbus_watch, watch, NULL);
150
 
 
151
 
    if (watch->fde) {
152
 
        /* pre-existing event, just toggle flags */
153
 
        sbus_toggle_watch(dbus_watch, data);
154
 
        return TRUE;
155
 
    }
156
 
 
157
 
    event_flags = 0;
158
 
    if (enabled) {
159
 
        if (flags & DBUS_WATCH_READABLE) {
160
 
            event_flags |= TEVENT_FD_READ;
161
 
        }
162
 
        if (flags & DBUS_WATCH_WRITABLE) {
163
 
            event_flags |= TEVENT_FD_WRITE;
164
 
        }
165
 
    }
166
 
 
167
 
    /* Add the file descriptor to the event loop */
168
 
    watch->fde = tevent_add_fd(conn->ev,
169
 
                               watch, fd, event_flags,
170
 
                               sbus_watch_handler, watch);
171
 
    if (!watch->fde) {
172
 
        DEBUG(0, ("Failed to set up fd event!\n"));
173
 
        talloc_zfree(watch);
174
 
        return FALSE;
175
 
    }
176
 
 
177
 
    DLIST_ADD(conn->watch_list, watch);
178
 
    talloc_set_destructor((TALLOC_CTX *)watch, watch_destructor);
179
 
 
180
 
    DEBUG(8, ("%p/%p (%d), %s/%s (%s)\n",
181
 
              watch, dbus_watch, fd,
182
 
              ((flags & DBUS_WATCH_READABLE)?"R":"-"),
183
 
              ((flags & DBUS_WATCH_WRITABLE)?"W":"-"),
184
 
              enabled?"enabled":"disabled"));
185
 
 
186
 
    return TRUE;
187
 
}
188
 
 
189
 
/*
190
 
 * toggle_watch
191
 
 * Hook for D-BUS to toggle the enabled/disabled state of
192
 
 * an event in the mainloop
193
 
 */
194
 
void sbus_toggle_watch(DBusWatch *dbus_watch, void *data)
195
 
{
196
 
    struct sbus_watch_ctx *watch;
197
 
    unsigned int flags;
198
 
    dbus_bool_t enabled;
199
 
    void *watch_data;
200
 
    int fd;
201
 
 
202
 
    enabled = dbus_watch_get_enabled(dbus_watch);
203
 
    flags = dbus_watch_get_flags(dbus_watch);
204
 
 
205
 
    watch_data = dbus_watch_get_data(dbus_watch);
206
 
    watch = talloc_get_type(watch_data, struct sbus_watch_ctx);
207
 
    if (!watch) {
208
 
        DEBUG(2, ("[%p] does not carry watch context?!\n", dbus_watch));
209
 
        /* abort ? */
210
 
        return;
211
 
    }
212
 
 
213
 
    if (enabled) {
214
 
        if (flags & DBUS_WATCH_READABLE) {
215
 
            TEVENT_FD_READABLE(watch->fde);
216
 
        }
217
 
        if (flags & DBUS_WATCH_WRITABLE) {
218
 
            TEVENT_FD_WRITEABLE(watch->fde);
219
 
        }
220
 
    } else {
221
 
        if (flags & DBUS_WATCH_READABLE) {
222
 
            TEVENT_FD_NOT_READABLE(watch->fde);
223
 
        }
224
 
        if (flags & DBUS_WATCH_WRITABLE) {
225
 
            TEVENT_FD_NOT_WRITEABLE(watch->fde);
226
 
        }
227
 
    }
228
 
 
229
 
    if (debug_level >= 8) {
230
 
#ifdef HAVE_DBUS_WATCH_GET_UNIX_FD
231
 
        fd = dbus_watch_get_unix_fd(dbus_watch);
232
 
#else
233
 
        fd = dbus_watch_get_fd(dbus_watch);
234
 
#endif
235
 
    }
236
 
    DEBUG(8, ("%p/%p (%d), %s/%s (%s)\n",
237
 
              watch, dbus_watch, fd,
238
 
              ((flags & DBUS_WATCH_READABLE)?"R":"-"),
239
 
              ((flags & DBUS_WATCH_WRITABLE)?"W":"-"),
240
 
              enabled?"enabled":"disabled"));
241
 
}
242
 
 
243
 
/*
244
 
 * sbus_remove_watch
245
 
 * Hook for D-BUS to remove file descriptor-based events
246
 
 * from the libevents mainloop
247
 
 */
248
 
void sbus_remove_watch(DBusWatch *dbus_watch, void *data)
249
 
{
250
 
    struct sbus_watch_ctx *watch;
251
 
    void *watch_data;
252
 
 
253
 
    watch_data = dbus_watch_get_data(dbus_watch);
254
 
    watch = talloc_get_type(watch_data, struct sbus_watch_ctx);
255
 
 
256
 
    DEBUG(8, ("%p/%p\n", watch, dbus_watch));
257
 
 
258
 
    if (!watch) {
259
 
        DEBUG(2, ("DBUS trying to remove unknown watch!\n"));
260
 
        return;
261
 
    }
262
 
 
263
 
    /* remove dbus watch data */
264
 
    dbus_watch_set_data(dbus_watch, NULL, NULL);
265
 
 
266
 
    /* check which watch to remove, or free if none left */
267
 
    if (watch->dbus_read_watch == dbus_watch) {
268
 
        watch->dbus_read_watch = NULL;
269
 
    }
270
 
    if (watch->dbus_write_watch == dbus_watch) {
271
 
        watch->dbus_write_watch = NULL;
272
 
    }
273
 
    if (!watch->dbus_read_watch && !watch->dbus_write_watch) {
274
 
        talloc_free(watch);
275
 
    }
276
 
}
277
 
 
278
 
/* =Timeouts============================================================== */
279
 
 
280
 
static struct timeval _get_interval_tv(int interval) {
281
 
    struct timeval tv;
282
 
    struct timeval rightnow;
283
 
 
284
 
    gettimeofday(&rightnow,NULL);
285
 
 
286
 
    tv.tv_sec = interval / 1000 + rightnow.tv_sec;
287
 
    tv.tv_usec = (interval % 1000) * 1000 + rightnow.tv_usec;
288
 
    return tv;
289
 
}
290
 
 
291
 
/*
292
 
 * timeout_handler
293
 
 * Callback for D-BUS to handle timed events
294
 
 */
295
 
static void sbus_timeout_handler(struct tevent_context *ev,
296
 
                                 struct tevent_timer *te,
297
 
                                 struct timeval t, void *data)
298
 
{
299
 
    struct sbus_timeout_ctx *timeout;
300
 
    timeout = talloc_get_type(data, struct sbus_timeout_ctx);
301
 
 
302
 
    dbus_timeout_handle(timeout->dbus_timeout);
303
 
}
304
 
 
305
 
/*
306
 
 * add_timeout
307
 
 * Hook for D-BUS to add time-based events to the mainloop
308
 
 */
309
 
dbus_bool_t sbus_add_timeout(DBusTimeout *dbus_timeout, void *data)
310
 
{
311
 
    struct sbus_connection *conn;
312
 
    struct sbus_timeout_ctx *timeout;
313
 
    struct timeval tv;
314
 
 
315
 
    DEBUG(8, ("%p\n", dbus_timeout));
316
 
 
317
 
    if (!dbus_timeout_get_enabled(dbus_timeout)) {
318
 
        return TRUE;
319
 
    }
320
 
 
321
 
    conn = talloc_get_type(data, struct sbus_connection);
322
 
 
323
 
    timeout = talloc_zero(conn, struct sbus_timeout_ctx);
324
 
    if (!timeout) {
325
 
        DEBUG(0, ("Out of Memory!\n"));
326
 
        return FALSE;
327
 
    }
328
 
    timeout->dbus_timeout = dbus_timeout;
329
 
 
330
 
    tv = _get_interval_tv(dbus_timeout_get_interval(dbus_timeout));
331
 
    timeout->te = tevent_add_timer(conn->ev, timeout, tv,
332
 
                                   sbus_timeout_handler, timeout);
333
 
    if (!timeout->te) {
334
 
        DEBUG(0, ("Failed to set up timeout event!\n"));
335
 
        return FALSE;
336
 
    }
337
 
 
338
 
    /* Save the event to the watch object so it can be removed later */
339
 
    dbus_timeout_set_data(timeout->dbus_timeout, timeout, NULL);
340
 
 
341
 
    return TRUE;
342
 
}
343
 
 
344
 
/*
345
 
 * sbus_toggle_timeout
346
 
 * Hook for D-BUS to toggle the enabled/disabled state of a mainloop
347
 
 * event
348
 
 */
349
 
void sbus_toggle_timeout(DBusTimeout *dbus_timeout, void *data)
350
 
{
351
 
    DEBUG(8, ("%p\n", dbus_timeout));
352
 
 
353
 
    if (dbus_timeout_get_enabled(dbus_timeout)) {
354
 
        sbus_add_timeout(dbus_timeout, data);
355
 
    } else {
356
 
        sbus_remove_timeout(dbus_timeout, data);
357
 
    }
358
 
}
359
 
 
360
 
/*
361
 
 * sbus_remove_timeout
362
 
 * Hook for D-BUS to remove time-based events from the mainloop
363
 
 */
364
 
void sbus_remove_timeout(DBusTimeout *dbus_timeout, void *data)
365
 
{
366
 
    void *timeout;
367
 
 
368
 
    DEBUG(8, ("%p\n", dbus_timeout));
369
 
 
370
 
    timeout = dbus_timeout_get_data(dbus_timeout);
371
 
 
372
 
    /* remove dbus timeout data */
373
 
    dbus_timeout_set_data(dbus_timeout, NULL, NULL);
374
 
 
375
 
    /* Freeing the event object will remove it from the event loop */
376
 
    talloc_free(timeout);
377
 
 
378
 
}
379
 
 
380
 
/* =Helpers=============================================================== */
381
 
 
382
 
int sbus_is_dbus_fixed_type(int dbus_type)
383
 
{
384
 
    switch (dbus_type) {
385
 
    case DBUS_TYPE_BYTE:
386
 
    case DBUS_TYPE_BOOLEAN:
387
 
    case DBUS_TYPE_INT16:
388
 
    case DBUS_TYPE_UINT16:
389
 
    case DBUS_TYPE_INT32:
390
 
    case DBUS_TYPE_UINT32:
391
 
    case DBUS_TYPE_INT64:
392
 
    case DBUS_TYPE_UINT64:
393
 
    case DBUS_TYPE_DOUBLE:
394
 
        return true;
395
 
    }
396
 
    return false;
397
 
}
398
 
 
399
 
int sbus_is_dbus_string_type(int dbus_type)
400
 
{
401
 
    switch(dbus_type) {
402
 
    case DBUS_TYPE_STRING:
403
 
    case DBUS_TYPE_OBJECT_PATH:
404
 
    case DBUS_TYPE_SIGNATURE:
405
 
        return true;
406
 
    }
407
 
    return false;
408
 
}
409
 
 
410
 
size_t sbus_get_dbus_type_size(int dbus_type)
411
 
{
412
 
    size_t ret;
413
 
 
414
 
    switch(dbus_type) {
415
 
    /* 1-byte types */
416
 
    case DBUS_TYPE_BYTE:
417
 
        ret = 1;
418
 
        break;
419
 
 
420
 
     /* 2-byte types */
421
 
    case DBUS_TYPE_INT16:
422
 
    case DBUS_TYPE_UINT16:
423
 
        ret = 2;
424
 
        break;
425
 
 
426
 
    /* 4-byte types */
427
 
    case DBUS_TYPE_BOOLEAN:
428
 
    case DBUS_TYPE_INT32:
429
 
    case DBUS_TYPE_UINT32:
430
 
        ret = 4;
431
 
        break;
432
 
 
433
 
    /* 8-byte types */
434
 
    case DBUS_TYPE_INT64:
435
 
    case DBUS_TYPE_UINT64:
436
 
    case DBUS_TYPE_DOUBLE:
437
 
        ret = 8;
438
 
        break;
439
 
 
440
 
    default:
441
 
        ret = 0;
442
 
    }
443
 
    return ret;
444
 
}