Branch data Line data Source code
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 : 0 : watch_iter = list;
38 [ # # ]: 0 : while (watch_iter != NULL) {
39 [ # # ]: 0 : if (watch_iter->fd == fd) {
40 : : return watch_iter;
41 : : }
42 : :
43 : 0 : watch_iter = watch_iter->next;
44 : : }
45 : :
46 : : return NULL;
47 : : }
48 : :
49 : 0 : static int watch_destructor(void *mem)
50 : : {
51 : : struct sbus_watch_ctx *watch;
52 : :
53 : 0 : watch = talloc_get_type(mem, struct sbus_watch_ctx);
54 [ # # ][ # # ]: 0 : DLIST_REMOVE(watch->conn->watch_list, watch);
[ # # ][ # # ]
[ # # ]
55 : :
56 : 0 : return 0;
57 : : }
58 : :
59 : : /*
60 : : * watch_handler
61 : : * Callback for D-BUS to handle messages on a file-descriptor
62 : : */
63 : 0 : static void sbus_watch_handler(struct tevent_context *ev,
64 : : struct tevent_fd *fde,
65 : : uint16_t flags, void *data)
66 : : {
67 : 0 : 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 : 0 : type = watch->conn->type;
74 : 0 : dbus_p = watch->conn->dbus;
75 : :
76 : : /* Take a reference while handling watch */
77 [ # # ]: 0 : if (type == SBUS_SERVER) {
78 : 0 : dbus_server_ref(dbus_p.server);
79 : : } else {
80 : 0 : dbus_connection_ref(dbus_p.conn);
81 : : }
82 : :
83 : : /* Fire if readable */
84 [ # # ]: 0 : if (flags & TEVENT_FD_READ) {
85 [ # # ]: 0 : if (watch->dbus_read_watch) {
86 : 0 : dbus_watch_handle(watch->dbus_read_watch, DBUS_WATCH_READABLE);
87 : : }
88 : : }
89 : :
90 : : /* Fire if writeable */
91 [ # # ]: 0 : if (flags & TEVENT_FD_WRITE) {
92 [ # # ]: 0 : if (watch->dbus_write_watch) {
93 : 0 : dbus_watch_handle(watch->dbus_write_watch, DBUS_WATCH_WRITABLE);
94 : : }
95 : : }
96 : :
97 : : /* Release reference once done */
98 [ # # ]: 0 : if (type == SBUS_SERVER) {
99 : 0 : dbus_server_unref(dbus_p.server);
100 : : } else {
101 : 0 : dbus_connection_unref(dbus_p.conn);
102 : : }
103 : 0 : }
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 : 0 : 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 : 0 : conn = talloc_get_type(data, struct sbus_connection);
120 : :
121 : : #ifdef HAVE_DBUS_WATCH_GET_UNIX_FD
122 : 0 : fd = dbus_watch_get_unix_fd(dbus_watch);
123 : : #else
124 : : fd = dbus_watch_get_fd(dbus_watch);
125 : : #endif
126 : :
127 : 0 : watch = fd_to_watch(conn->watch_list, fd);
128 [ # # ]: 0 : if (!watch) {
129 : : /* does not exist, allocate new one */
130 : 0 : watch = talloc_zero(conn, struct sbus_watch_ctx);
131 [ # # ]: 0 : if (!watch) {
132 [ # # ][ # # ]: 0 : DEBUG(0, ("Out of Memory!\n"));
[ # # ][ # # ]
[ # # ]
133 : : return FALSE;
134 : : }
135 : 0 : watch->conn = conn;
136 : 0 : watch->fd = fd;
137 : : }
138 : :
139 : 0 : enabled = dbus_watch_get_enabled(dbus_watch);
140 : 0 : flags = dbus_watch_get_flags(dbus_watch);
141 : :
142 : : /* Save the event to the watch object so it can be found later */
143 [ # # ]: 0 : if (flags & DBUS_WATCH_READABLE) {
144 : 0 : watch->dbus_read_watch = dbus_watch;
145 : : }
146 [ # # ]: 0 : if (flags & DBUS_WATCH_WRITABLE) {
147 : 0 : watch->dbus_write_watch = dbus_watch;
148 : : }
149 : 0 : dbus_watch_set_data(dbus_watch, watch, NULL);
150 : :
151 [ # # ]: 0 : if (watch->fde) {
152 : : /* pre-existing event, just toggle flags */
153 : 0 : sbus_toggle_watch(dbus_watch, data);
154 : 0 : return TRUE;
155 : : }
156 : :
157 : 0 : event_flags = 0;
158 [ # # ]: 0 : if (enabled) {
159 [ # # ]: 0 : if (flags & DBUS_WATCH_READABLE) {
160 : 0 : event_flags |= TEVENT_FD_READ;
161 : : }
162 [ # # ]: 0 : if (flags & DBUS_WATCH_WRITABLE) {
163 : 0 : event_flags |= TEVENT_FD_WRITE;
164 : : }
165 : : }
166 : :
167 : : /* Add the file descriptor to the event loop */
168 : 0 : watch->fde = tevent_add_fd(conn->ev,
169 : : watch, fd, event_flags,
170 : : sbus_watch_handler, watch);
171 [ # # ]: 0 : if (!watch->fde) {
172 [ # # ][ # # ]: 0 : DEBUG(0, ("Failed to set up fd event!\n"));
[ # # ][ # # ]
[ # # ]
173 : 0 : talloc_zfree(watch);
174 : 0 : return FALSE;
175 : : }
176 : :
177 [ # # ]: 0 : DLIST_ADD(conn->watch_list, watch);
178 : 0 : talloc_set_destructor((TALLOC_CTX *)watch, watch_destructor);
179 : :
180 [ # # ][ # # ]: 0 : 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 : 0 : 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 : 0 : int fd = -1;
201 : :
202 : 0 : enabled = dbus_watch_get_enabled(dbus_watch);
203 : 0 : flags = dbus_watch_get_flags(dbus_watch);
204 : :
205 : 0 : watch_data = dbus_watch_get_data(dbus_watch);
206 : 0 : watch = talloc_get_type(watch_data, struct sbus_watch_ctx);
207 [ # # ]: 0 : if (!watch) {
208 [ # # ][ # # ]: 0 : DEBUG(2, ("[%p] does not carry watch context?!\n", dbus_watch));
[ # # ][ # # ]
[ # # ]
209 : : /* abort ? */
210 : 0 : return;
211 : : }
212 : :
213 [ # # ]: 0 : if (enabled) {
214 [ # # ]: 0 : if (flags & DBUS_WATCH_READABLE) {
215 : 0 : TEVENT_FD_READABLE(watch->fde);
216 : : }
217 [ # # ]: 0 : if (flags & DBUS_WATCH_WRITABLE) {
218 : 0 : TEVENT_FD_WRITEABLE(watch->fde);
219 : : }
220 : : } else {
221 [ # # ]: 0 : if (flags & DBUS_WATCH_READABLE) {
222 : 0 : TEVENT_FD_NOT_READABLE(watch->fde);
223 : : }
224 [ # # ]: 0 : if (flags & DBUS_WATCH_WRITABLE) {
225 : 0 : TEVENT_FD_NOT_WRITEABLE(watch->fde);
226 : : }
227 : : }
228 : :
229 [ # # ]: 0 : if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
230 : : #ifdef HAVE_DBUS_WATCH_GET_UNIX_FD
231 : 0 : fd = dbus_watch_get_unix_fd(dbus_watch);
232 : : #else
233 : : fd = dbus_watch_get_fd(dbus_watch);
234 : : #endif
235 : : }
236 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_ALL,
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
237 : : ("%p/%p (%d), %s/%s (%s)\n",
238 : : watch, dbus_watch, fd,
239 : : ((flags & DBUS_WATCH_READABLE)?"R":"-"),
240 : : ((flags & DBUS_WATCH_WRITABLE)?"W":"-"),
241 : : enabled?"enabled":"disabled"));
242 : : }
243 : :
244 : : /*
245 : : * sbus_remove_watch
246 : : * Hook for D-BUS to remove file descriptor-based events
247 : : * from the libevents mainloop
248 : : */
249 : 0 : void sbus_remove_watch(DBusWatch *dbus_watch, void *data)
250 : : {
251 : : struct sbus_watch_ctx *watch;
252 : : void *watch_data;
253 : :
254 : 0 : watch_data = dbus_watch_get_data(dbus_watch);
255 : 0 : watch = talloc_get_type(watch_data, struct sbus_watch_ctx);
256 : :
257 [ # # ][ # # ]: 0 : DEBUG(8, ("%p/%p\n", watch, dbus_watch));
[ # # ][ # # ]
[ # # ]
258 : :
259 [ # # ]: 0 : if (!watch) {
260 [ # # ][ # # ]: 0 : DEBUG(2, ("DBUS trying to remove unknown watch!\n"));
[ # # ][ # # ]
[ # # ]
261 : 0 : return;
262 : : }
263 : :
264 : : /* remove dbus watch data */
265 : 0 : dbus_watch_set_data(dbus_watch, NULL, NULL);
266 : :
267 : : /* check which watch to remove, or free if none left */
268 [ # # ]: 0 : if (watch->dbus_read_watch == dbus_watch) {
269 : 0 : watch->dbus_read_watch = NULL;
270 : : }
271 [ # # ]: 0 : if (watch->dbus_write_watch == dbus_watch) {
272 : 0 : watch->dbus_write_watch = NULL;
273 : : }
274 [ # # ][ # # ]: 0 : if (!watch->dbus_read_watch && !watch->dbus_write_watch) {
275 : 0 : talloc_free(watch);
276 : : }
277 : : }
278 : :
279 : : /* =Timeouts============================================================== */
280 : :
281 : 0 : static struct timeval _get_interval_tv(int interval) {
282 : : struct timeval tv;
283 : : struct timeval rightnow;
284 : :
285 : 0 : gettimeofday(&rightnow,NULL);
286 : :
287 : 0 : tv.tv_sec = interval / 1000 + rightnow.tv_sec;
288 : 0 : tv.tv_usec = (interval % 1000) * 1000 + rightnow.tv_usec;
289 : 0 : return tv;
290 : : }
291 : :
292 : : /*
293 : : * timeout_handler
294 : : * Callback for D-BUS to handle timed events
295 : : */
296 : 0 : static void sbus_timeout_handler(struct tevent_context *ev,
297 : : struct tevent_timer *te,
298 : : struct timeval t, void *data)
299 : : {
300 : : struct sbus_timeout_ctx *timeout;
301 : 0 : timeout = talloc_get_type(data, struct sbus_timeout_ctx);
302 : :
303 : 0 : dbus_timeout_handle(timeout->dbus_timeout);
304 : 0 : }
305 : :
306 : : /*
307 : : * add_timeout
308 : : * Hook for D-BUS to add time-based events to the mainloop
309 : : */
310 : 0 : dbus_bool_t sbus_add_timeout(DBusTimeout *dbus_timeout, void *data)
311 : : {
312 : : struct sbus_connection *conn;
313 : : struct sbus_timeout_ctx *timeout;
314 : : struct timeval tv;
315 : :
316 [ # # ][ # # ]: 0 : DEBUG(8, ("%p\n", dbus_timeout));
[ # # ][ # # ]
[ # # ]
317 : :
318 [ # # ]: 0 : if (!dbus_timeout_get_enabled(dbus_timeout)) {
319 : : return TRUE;
320 : : }
321 : :
322 : 0 : conn = talloc_get_type(data, struct sbus_connection);
323 : :
324 : 0 : timeout = talloc_zero(conn, struct sbus_timeout_ctx);
325 [ # # ]: 0 : if (!timeout) {
326 [ # # ][ # # ]: 0 : DEBUG(0, ("Out of Memory!\n"));
[ # # ][ # # ]
[ # # ]
327 : : return FALSE;
328 : : }
329 : 0 : timeout->dbus_timeout = dbus_timeout;
330 : :
331 : 0 : tv = _get_interval_tv(dbus_timeout_get_interval(dbus_timeout));
332 : 0 : timeout->te = tevent_add_timer(conn->ev, timeout, tv,
333 : : sbus_timeout_handler, timeout);
334 [ # # ]: 0 : if (!timeout->te) {
335 [ # # ][ # # ]: 0 : DEBUG(0, ("Failed to set up timeout event!\n"));
[ # # ][ # # ]
[ # # ]
336 : : return FALSE;
337 : : }
338 : :
339 : : /* Save the event to the watch object so it can be removed later */
340 : 0 : dbus_timeout_set_data(timeout->dbus_timeout, timeout, NULL);
341 : :
342 : : return TRUE;
343 : : }
344 : :
345 : : /*
346 : : * sbus_toggle_timeout
347 : : * Hook for D-BUS to toggle the enabled/disabled state of a mainloop
348 : : * event
349 : : */
350 : 0 : void sbus_toggle_timeout(DBusTimeout *dbus_timeout, void *data)
351 : : {
352 [ # # ][ # # ]: 0 : DEBUG(8, ("%p\n", dbus_timeout));
[ # # ][ # # ]
[ # # ]
353 : :
354 [ # # ]: 0 : if (dbus_timeout_get_enabled(dbus_timeout)) {
355 : 0 : sbus_add_timeout(dbus_timeout, data);
356 : : } else {
357 : 0 : sbus_remove_timeout(dbus_timeout, data);
358 : : }
359 : 0 : }
360 : :
361 : : /*
362 : : * sbus_remove_timeout
363 : : * Hook for D-BUS to remove time-based events from the mainloop
364 : : */
365 : 0 : void sbus_remove_timeout(DBusTimeout *dbus_timeout, void *data)
366 : : {
367 : : void *timeout;
368 : :
369 [ # # ][ # # ]: 0 : DEBUG(8, ("%p\n", dbus_timeout));
[ # # ][ # # ]
[ # # ]
370 : :
371 : 0 : timeout = dbus_timeout_get_data(dbus_timeout);
372 : :
373 : : /* remove dbus timeout data */
374 : 0 : dbus_timeout_set_data(dbus_timeout, NULL, NULL);
375 : :
376 : : /* Freeing the event object will remove it from the event loop */
377 : 0 : talloc_free(timeout);
378 : :
379 : 0 : }
380 : :
381 : : /* =Helpers=============================================================== */
382 : :
383 : 0 : int sbus_is_dbus_fixed_type(int dbus_type)
384 : : {
385 [ # # ]: 0 : switch (dbus_type) {
386 : : case DBUS_TYPE_BYTE:
387 : : case DBUS_TYPE_BOOLEAN:
388 : : case DBUS_TYPE_INT16:
389 : : case DBUS_TYPE_UINT16:
390 : : case DBUS_TYPE_INT32:
391 : : case DBUS_TYPE_UINT32:
392 : : case DBUS_TYPE_INT64:
393 : : case DBUS_TYPE_UINT64:
394 : : case DBUS_TYPE_DOUBLE:
395 : : return true;
396 : : }
397 : 0 : return false;
398 : : }
399 : :
400 : 0 : int sbus_is_dbus_string_type(int dbus_type)
401 : : {
402 [ # # ]: 0 : switch(dbus_type) {
403 : : case DBUS_TYPE_STRING:
404 : : case DBUS_TYPE_OBJECT_PATH:
405 : : case DBUS_TYPE_SIGNATURE:
406 : : return true;
407 : : }
408 : 0 : return false;
409 : : }
410 : :
411 : 0 : size_t sbus_get_dbus_type_size(int dbus_type)
412 : : {
413 : : size_t ret;
414 : :
415 [ # # ]: 0 : switch(dbus_type) {
416 : : /* 1-byte types */
417 : : case DBUS_TYPE_BYTE:
418 : : ret = 1;
419 : : break;
420 : :
421 : : /* 2-byte types */
422 : : case DBUS_TYPE_INT16:
423 : : case DBUS_TYPE_UINT16:
424 : : ret = 2;
425 : : break;
426 : :
427 : : /* 4-byte types */
428 : : case DBUS_TYPE_BOOLEAN:
429 : : case DBUS_TYPE_INT32:
430 : : case DBUS_TYPE_UINT32:
431 : : ret = 4;
432 : : break;
433 : :
434 : : /* 8-byte types */
435 : : case DBUS_TYPE_INT64:
436 : : case DBUS_TYPE_UINT64:
437 : : case DBUS_TYPE_DOUBLE:
438 : : ret = 8;
439 : : break;
440 : :
441 : : default:
442 : : ret = 0;
443 : : }
444 : 0 : return ret;
445 : : }
|