1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
|
/*
Authors:
Pavel Březina <pbrezina@redhat.com>
Copyright (C) 2017 Red Hat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SBUS_PRIVATE_H_
#define _SBUS_PRIVATE_H_
#include <time.h>
#include <dhash.h>
#include <talloc.h>
#include <tevent.h>
#include <dbus/dbus.h>
#include "util/util.h"
#include "sbus/sbus.h"
#include "sbus/sbus_message.h"
#include "sbus/sbus_sync_private.h"
#include "sbus/sbus_interface_declarations.h"
/**
* First, declare all structures, since they are often cross referenced.
*/
struct sbus_connection_destructor;
struct sbus_connection_access;
struct sbus_connection;
struct sbus_reconnect;
struct sbus_server;
struct sbus_router;
struct sbus_watch;
struct sbus_sender;
struct sbus_listener;
struct sbus_interface;
struct sbus_active_requests;
struct sbus_server_on_connection;
enum sbus_connection_type {
/**
* Client connection is owned by sbus and not by D-Bus, therefore it
* needs to be explicitly closed before removing the last reference.
*
* This is used for connections created by sbus server.
*/
SBUS_CONNECTION_CLIENT,
/**
* Address and system bus connections are owned by libdbus thus we can not
* close these connections explicitly. These connections may be recycled
* when we connect to the same address more than once.
*/
SBUS_CONNECTION_ADDRESS,
SBUS_CONNECTION_SYSBUS
};
struct sbus_connection {
struct tevent_context *ev;
DBusConnection *connection;
enum sbus_connection_type type;
const char *address;
/* D-Bus connection well-known name as request by the application. */
const char *wellknown_name;
/* D-Bus connection unique name as assigned by bus. */
const char *unique_name;
/**
* True if the connection is being disconnected or freed. No further
* manipulation with the connection is allowed.
*/
bool disconnecting;
/* Make all the structures pointers so we can have them encapsulated. */
struct sbus_connection_access *access;
struct sbus_connection_destructor *destructor;
struct sbus_active_requests *requests;
struct sbus_reconnect *reconnect;
struct sbus_router *router;
struct sbus_watch *watch;
/**
* Connection private data.
*/
void *data;
/**
* Table of <dbus-sender, sbus-sender> pair. Contains resolved uids
* of remote D-Bus clients.
*/
hash_table_t *senders;
/* Pointer to a caller's last activity variable. The time is updated
* each time the bus is active (when a method arrives). */
time_t *last_activity;
};
struct sbus_server {
struct tevent_context *ev;
DBusServer *server;
const char *symlink;
struct sbus_watch *watch_ctx;
struct sbus_router *router;
dbus_int32_t data_slot;
time_t *last_activity;
hash_table_t *names;
hash_table_t *match_rules;
uint32_t max_connections;
uid_t uid;
gid_t gid;
struct sbus_server_on_connection *on_connection;
bool disconnecting;
/* Last generated unique name information. */
struct {
uint32_t major;
uint32_t minor;
} name;
};
/* Setup server interface implementing org.freedesktop.DBus. */
errno_t
sbus_server_setup_interface(struct sbus_server *server);
/* Add signal match. */
errno_t
sbus_server_add_match(struct sbus_server *server,
struct sbus_connection *conn,
const char *rule);
/* Remove signal match. */
errno_t
sbus_server_remove_match(struct sbus_server *server,
struct sbus_connection *conn,
const char *rule);
/* Send message to all connections whose rule matches the message. */
errno_t
sbus_server_matchmaker(struct sbus_server *server,
struct sbus_connection *conn,
const char *avoid_name,
DBusMessage *message);
/* Send NameAcquired signal to given connection. */
void
sbus_server_name_acquired(struct sbus_server *server,
struct sbus_connection *conn,
const char *name);
/* Send NameLost signal to given connection. */
void
sbus_server_name_lost(struct sbus_server *server,
struct sbus_connection *conn,
const char *name);
/* Initialize new sbus connection. */
struct sbus_connection *
sbus_connection_init(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
DBusConnection *dbus_conn,
const char *address,
const char *dbus_name,
enum sbus_connection_type type,
time_t *last_activity_time);
/* Replace current D-Bus connection context with a new one. */
errno_t sbus_connection_replace(struct sbus_connection *sbus_conn,
DBusConnection *dbus_conn);
/* Integrate an sbus connection with tevent loop. */
errno_t sbus_connection_tevent_enable(struct sbus_connection *conn);
void sbus_connection_tevent_disable(struct sbus_connection *conn);
/* Mark that this connection is currently active (new method call arrived). */
void sbus_connection_mark_active(struct sbus_connection *conn);
/* Set connection well known name. */
errno_t sbus_connection_set_name(struct sbus_connection *conn,
const char *name);
/* Free connection next time the event loop is processed. We do it
* asynchronously to avoid a potential use after free from tevent
* callbacks that may be already scheduled. */
void sbus_connection_free(struct sbus_connection *conn);
/* Try to reconnect to D-Bus if connection was dropped. It will notify
* the user with a result through a reconnection callback. */
void sbus_reconnect(struct sbus_connection *conn);
/* Initialize reconnection structure. */
struct sbus_reconnect *sbus_reconnect_init(TALLOC_CTX *mem_ctx);
/* Disable any further reconnection attempts. */
void sbus_reconnect_disable(struct sbus_connection *conn);
/* Return true if we are already trying to reconnect. */
bool sbus_reconnect_in_progress(struct sbus_connection *conn);
/* Return true if we are allowed to reconnect. */
bool sbus_reconnect_enabled(struct sbus_connection *conn);
/* Call Hello and RequestName methods. */
struct tevent_req *
sbus_connect_init_send(TALLOC_CTX *mem_ctx,
struct sbus_connection *conn,
const char *name);
errno_t sbus_connect_init_recv(struct tevent_req *req);
/* Setup D-Bus event watchers to integrate D-Bus with event loop. */
errno_t sbus_watch_server(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
DBusServer *server,
struct sbus_watch **_watch);
errno_t sbus_watch_connection(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
DBusConnection *conn,
struct sbus_watch **_watch);
/* Perform an access check on the given request using registered
* access check function of connection.*/
errno_t sbus_check_access(struct sbus_connection *conn,
struct sbus_request *sbus_req);
/* Setup D-Bus tevent dispatcher. */
void sbus_dispatcher_setup(struct sbus_connection *conn);
void sbus_dispatcher_disable(struct sbus_connection *conn);
void sbus_dispatch_now(struct sbus_connection *conn);
/* Send a new D-Bus message. */
struct tevent_req *
sbus_message_send(TALLOC_CTX *mem_ctx,
struct sbus_connection *conn,
DBusMessage *msg,
int timeout_ms);
errno_t
sbus_message_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
DBusMessage **_reply);
/* Send reply to a D-Bus message. The @reply is unreferenced when sent. */
void sbus_reply(struct sbus_connection *conn,
DBusMessage *reply);
/* Replz to a D-Bus message with error. */
void sbus_reply_error(struct sbus_connection *conn,
DBusMessage *reply_to,
const char *error_name,
const char *error_message);
/* Emit a new signal. */
void sbus_emit_signal(struct sbus_connection *conn,
DBusMessage *msg);
struct sbus_interface_list {
struct sbus_interface *interface;
struct sbus_interface_list *next;
struct sbus_interface_list *prev;
};
struct sbus_listener_list {
struct sbus_listener *listener;
struct sbus_listener_list *next;
struct sbus_listener_list *prev;
};
struct sbus_router {
struct sbus_connection *conn;
/**
* Table of <object-path, interface> pair. Contains description of
* sbus interfaces that are implemented and supported on given path.
*/
hash_table_t *paths;
/**
* Table of <object-path, node> pair. A node contains factory function
* given for selected object paths. This function is used to create
* list of object paths nodes that are available under requested path
* during introspection.
*/
hash_table_t *nodes;
/**
* Table of <interface.signal, listener> pair. Contains description of
* sbus signal listeners.
*/
hash_table_t *listeners;
};
/* Initialize router structure. */
struct sbus_router *
sbus_router_init(TALLOC_CTX *mem_ctx,
struct sbus_connection *conn);
/* Re-register paths and listeners on dropped connection. */
errno_t
sbus_router_reset(struct sbus_connection *conn);
/* Initialize object paths hash table. */
hash_table_t *
sbus_router_paths_init(TALLOC_CTX *mem_ctx);
/* Register an interface with an object path. */
errno_t
sbus_router_paths_add(hash_table_t *table,
const char *path,
struct sbus_interface *iface);
/* Lookup interface for given object path. */
struct sbus_interface *
sbus_router_paths_lookup(hash_table_t *table,
const char *path,
const char *iface_name);
/* Return list of all interfaces registered with given object path. */
errno_t
sbus_router_paths_supported(TALLOC_CTX *mem_ctx,
hash_table_t *table,
const char *path,
struct sbus_interface_list **_list);
/* Return all registered paths converted to node names. */
const char **
sbus_router_paths_nodes(TALLOC_CTX *mem_ctx,
hash_table_t *table);
/* Check if given object path is registered. */
bool
sbus_router_paths_exist(hash_table_t *table,
const char *object_path);
/* Initialize signal listeners hash table. */
hash_table_t *
sbus_router_listeners_init(TALLOC_CTX *mem_ctx,
struct sbus_connection *conn);
/* Add new signal listener. */
errno_t
sbus_router_listeners_add(hash_table_t *table,
const char *interface,
const char *signal_name,
struct sbus_listener *listener,
bool *_signal_known);
/* Find all listeners for given signal. */
struct sbus_listener_list *
sbus_router_listeners_lookup(hash_table_t *table,
const char *interface,
const char *signal_name);
/* Initialize nodes hash table. */
hash_table_t *
sbus_router_nodes_init(TALLOC_CTX *mem_ctx);
/* Add new node factory. */
errno_t
sbus_router_nodes_add(hash_table_t *table,
struct sbus_node *node);
/* Lookup node factory for given object path. */
struct sbus_node *
sbus_router_nodes_lookup(hash_table_t *table,
const char *path);
/* Register new interface on path with the router. */
errno_t
sbus_router_add_path(struct sbus_router *router,
const char *path,
struct sbus_interface *iface);
/* Register new interface on path with the router from map. */
errno_t
sbus_router_add_path_map(struct sbus_router *router,
struct sbus_path *map);
/* Return D-Bus match rule for given signal. */
char *
sbus_router_signal_rule(TALLOC_CTX *mem_ctx,
const char *interface,
const char *signal_name);
/* Parse interface.signal into interface and signal parts. */
errno_t
sbus_router_signal_parse(TALLOC_CTX *mem_ctx,
const char *qualified_signal,
char **_interface,
char **_signal_name);
/* Process incoming messages. */
DBusHandlerResult
sbus_router_filter(struct sbus_connection *conn,
struct sbus_router *router,
DBusMessage *message);
/* Handler for incoming D-Bus messages that are recieve by connection. */
DBusHandlerResult
sbus_connection_filter(DBusConnection *dbus_conn,
DBusMessage *message,
void *handler_data);
/* Server filter function. Routes messages between connections. */
DBusHandlerResult
sbus_server_filter(DBusConnection *dbus_conn,
DBusMessage *message,
void *handler_data);
/* Spy that ensures that the request list item is invalidated when the
* request or connection is freed. */
struct sbus_request_spy;
struct sbus_request_list {
struct tevent_req *req;
struct sbus_connection *conn;
bool is_invalid;
bool is_dbus;
struct {
struct sbus_request_spy *req;
struct sbus_request_spy *conn;
} spy;
struct sbus_request_list *prev;
struct sbus_request_list *next;
};
struct sbus_active_requests {
hash_table_t *incoming;
hash_table_t *outgoing;
};
/* Initialize active requests structure. */
struct sbus_active_requests *
sbus_active_requests_init(TALLOC_CTX *mem_ctx);
/* Initialize request table. */
hash_table_t *
sbus_requests_init(TALLOC_CTX *mem_ctx);
/* Add new active request into the table. */
errno_t
sbus_requests_add(hash_table_t *table,
const char *key,
struct sbus_connection *conn,
struct tevent_req *req,
bool is_dbus,
bool *_key_exists);
/* Lookup active requests list. */
struct sbus_request_list *
sbus_requests_lookup(hash_table_t *table,
const char *key);
/* Delete active requests list. */
void
sbus_requests_delete(struct sbus_request_list *list);
/* Finish a request. */
void
sbus_requests_finish(struct sbus_request_list *item,
errno_t error);
/* Terminate all requests. */
void
sbus_requests_terminate_all(hash_table_t *table,
errno_t error);
/* Create new sbus request. */
struct sbus_request *
sbus_request_create(TALLOC_CTX *mem_ctx,
struct sbus_connection *conn,
enum sbus_request_type type,
const char *destination,
const char *interface,
const char *member,
const char *path);
/* Run an incoming request handler. */
struct tevent_req *
sbus_incoming_request_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sbus_connection *conn,
struct sbus_request *request,
const struct sbus_invoker *invoker,
const struct sbus_handler *handler,
const char *sender_name,
DBusMessageIter *read_iter,
DBusMessage *msg);
errno_t
sbus_incoming_request_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
DBusMessage **_reply);
/* Issue a new outgoing request. */
struct tevent_req *
sbus_outgoing_request_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sbus_connection *conn,
const char *key,
DBusMessage *msg);
errno_t
sbus_outgoing_request_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
DBusMessage **_reply);
/* Initialize senders hash table. */
hash_table_t *
sbus_senders_init(TALLOC_CTX *mem_ctx);
/* Remove sender from the table. */
void
sbus_senders_delete(hash_table_t *table,
const char *name);
/* Create new sbus sender. */
struct sbus_sender *
sbus_sender_create(TALLOC_CTX *mem_ctx,
const char *name,
int64_t uid);
/* Copy sbus sender structure. */
struct sbus_sender *
sbus_sender_copy(TALLOC_CTX *mem_ctx,
const struct sbus_sender *input);
/* Resolve sender of the incoming message. */
struct tevent_req *
sbus_sender_resolve_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sbus_connection *conn,
enum sbus_request_type type,
const char *destination,
const char *object_path,
const char *interface,
const char *member,
const char *name);
errno_t
sbus_sender_resolve_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
struct sbus_sender **_sender);
/* Generic receiver of sbus invoker. */
errno_t
sbus_invoker_recv(struct tevent_req *req);
/* Build key of given request. */
errno_t
sbus_request_key(TALLOC_CTX *mem_ctx,
sbus_invoker_keygen keygen,
struct sbus_request *sbus_req,
void *input,
const char **_key);
/**
* Create copy of provided interface. It expects that the interface was
* not created manually but through sbus API, therefore many of its fields
* must point to a static memory and same pointers are used for copy.
*/
struct sbus_interface *
sbus_interface_copy(TALLOC_CTX *mem_ctx,
const struct sbus_interface *input);
/* Find given method in interface. */
const struct sbus_method *
sbus_interface_find_method(struct sbus_interface *iface,
const char *method_name);
/* Find given property in interface. */
const struct sbus_property *
sbus_interface_find_property(struct sbus_interface *iface,
enum sbus_property_access access,
const char *property_name);
/**
* Create copy of provided signal listener. It expects that the listener was
* not created manually but through sbus API, therefore many of its fields
* must point to a static memory and same pointers are used for copy.
*/
struct sbus_listener *
sbus_listener_copy(TALLOC_CTX *mem_ctx,
const struct sbus_listener *input);
/**
* Create copy of provided node. It expects that the listener was
* not created manually but through sbus API, therefore many of its fields
* must point to a static memory and same pointers are used for copy.
*/
struct sbus_node *
sbus_node_copy(TALLOC_CTX *mem_ctx,
struct sbus_node *input);
/* Find given annotation. */
const char *
sbus_annotation_find(const struct sbus_annotation *annotations,
const char *name);
/* Find given annotation and return its value as boolean. */
bool
sbus_annotation_find_as_bool(const struct sbus_annotation *annotations,
const char *name);
/* Print a warning if specific annotations exist. */
void
sbus_annotation_warn(const struct sbus_interface *iface,
const struct sbus_method *method);
/* Register D-Bus introspection interface. */
errno_t
sbus_register_introspection(struct sbus_router *router);
/* Register D-Bus properties interface. */
errno_t
sbus_register_properties(struct sbus_router *router);
/* Register listeners for org.freedesktop.DBus signals. */
errno_t
sbus_register_standard_signals(struct sbus_connection *conn);
/* Send a D-Bus method call. Used in generated callers. */
struct tevent_req *
sbus_call_method_send(TALLOC_CTX *mem_ctx,
struct sbus_connection *conn,
DBusMessage *raw_message,
sbus_invoker_keygen keygen,
sbus_invoker_writer_fn writer,
const char *bus,
const char *path,
const char *iface,
const char *method,
void *input);
errno_t
sbus_call_method_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
DBusMessage **_reply);
/* Send a D-Bus signal call. Used in generated callers. */
void
sbus_call_signal_send(struct sbus_connection *conn,
DBusMessage *raw_message,
sbus_invoker_writer_fn writer,
const char *path,
const char *iface,
const char *signal_name,
void *input);
#endif /* _SBUS_PRIVATE_H_ */
|