]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/bus.c
networkd: bus: Create a unified function to register an interface
[people/ms/network.git] / src / networkd / bus.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <systemd/sd-bus.h>
25 #include <systemd/sd-event.h>
26
27 #include "bus.h"
28 #include "daemon.h"
29 #include "logging.h"
30
31 static int nw_bus_daemon_reload(sd_bus_message* m, void* data, sd_bus_error* error) {
32 struct nw_daemon* daemon = (struct nw_daemon*)data;
33
34 // Reload the daemon
35 nw_daemon_reload(daemon);
36
37 // Respond with an empty message
38 return sd_bus_reply_method_return(m, NULL);
39 }
40
41 static const sd_bus_vtable daemon_vtable[] = {
42 SD_BUS_VTABLE_START(0),
43 SD_BUS_METHOD("Reload", SD_BUS_NO_ARGS, SD_BUS_NO_RESULT,
44 nw_bus_daemon_reload, SD_BUS_VTABLE_UNPRIVILEGED),
45 SD_BUS_VTABLE_END,
46 };
47
48 const struct nw_bus_implementation daemon_implementation = {
49 .path = "/org/ipfire/network1",
50 .interface = "org.ipfire.network1",
51 .vtables = BUS_VTABLES(daemon_vtable),
52 };
53
54 static int nw_bus_on_connect(sd_bus_message* m, void* data, sd_bus_error* error) {
55 struct nw_daemon* daemon = (struct nw_daemon*)data;
56
57 DEBUG("Connected to D-Bus\n");
58
59 return 0;
60 }
61
62 int nw_bus_connect(sd_bus* bus, sd_event* loop) {
63 int r;
64
65 // Create a bus object
66 r = sd_bus_new(&bus);
67 if (r < 0) {
68 ERROR("Could not allocate a bus object: %s\n", strerror(-r));
69 return 1;
70 }
71
72 // Set description
73 r = sd_bus_set_description(bus, NETWORKD_BUS_DESCRIPTION);
74 if (r < 0) {
75 ERROR("Could not set bus description: %s\n", strerror(-r));
76 return 1;
77 }
78
79 const char* address = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
80 if (!address)
81 address = DEFAULT_SYSTEM_BUS_ADDRESS;
82
83 // Set bus address
84 r = sd_bus_set_address(bus, address);
85 if (r < 0) {
86 ERROR("Could not set bus address: %s\n", strerror(-r));
87 return 1;
88 }
89
90 // Set bus client
91 r = sd_bus_set_bus_client(bus, 1);
92 if (r < 0) {
93 ERROR("Could not set bus client: %s\n", strerror(-r));
94 return 1;
95 }
96
97 // Request some credentials for all messages
98 r = sd_bus_negotiate_creds(bus, 1,
99 SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
100 if (r < 0) {
101 ERROR("Could not negotiate creds: %s\n", strerror(-r));
102 return 1;
103 }
104
105 // Automatically bind when the socket is available
106 r = sd_bus_set_watch_bind(bus, 1);
107 if (r < 0) {
108 ERROR("Could not watch socket: %s\n", strerror(-r));
109 return 1;
110 }
111
112 // Emit a connected signal when we are connected
113 r = sd_bus_set_connected_signal(bus, 1);
114 if (r < 0) {
115 ERROR("Could not enable sending a connect signal: %s\n", strerror(-r));
116 return 1;
117 }
118
119 // Connect to the bus
120 r = sd_bus_start(bus);
121 if (r < 0) {
122 ERROR("Could not connect to bus: %s\n", strerror(-r));
123 return 1;
124 }
125
126 // Register the implementation
127 r = nw_bus_register_implementation(bus, &daemon_implementation, NULL);
128 if (r)
129 return r;
130
131 // Request interface name
132 r = sd_bus_request_name_async(bus, NULL, "org.ipfire.network1", 0, NULL, NULL);
133 if (r < 0) {
134 ERROR("Could not request bus name: %s\n", strerror(-r));
135 return 1;
136 }
137
138 // Attach the event loop
139 r = sd_bus_attach_event(bus, loop, 0);
140 if (r < 0) {
141 ERROR("Could not attach bus to event loop: %s\n", strerror(-r));
142 return 1;
143 }
144
145 // Request receiving a connect signal
146 r = sd_bus_match_signal_async(bus, NULL, "org.freedesktop.DBus.Local",
147 NULL, "org.freedesktop.DBus.Local", "Connected", nw_bus_on_connect, NULL, NULL);
148 if (r < 0) {
149 ERROR("Could not request match on Connected signal: %s\n", strerror(-r));
150 return 1;
151 }
152
153 return 0;
154 }
155
156 int nw_bus_register_implementation(sd_bus* bus,
157 const struct nw_bus_implementation* impl, void* data) {
158 int r;
159
160 DEBUG("Registering bus object implementation for path=%s iface=%s\n",
161 impl->path, impl->interface);
162
163 for (const sd_bus_vtable** vtable = impl->vtables; vtable && *vtable; vtable++) {
164 r = sd_bus_add_object_vtable(bus, NULL, impl->path, impl->interface, *vtable, data);
165 if (r < 0) {
166 ERROR("Could not register bus path %s with interface %s: %m\n",
167 impl->path, impl->interface);
168 return 1;
169 }
170 }
171
172 return 0;
173 }