dummy callback added to interface manager
[strongswan.git] / src / charon / control / interfaces / dbus_interface.c
1 /**
2 * @file dbus_interface.c
3 *
4 * @brief Implementation of dbus_interface_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #define DBUS_API_SUBJECT_TO_CHANGE
24 #include <dbus/dbus.h>
25 #include <NetworkManager/NetworkManager.h>
26 #include <NetworkManager/NetworkManagerVPN.h>
27 #include <stdlib.h>
28
29 #include "dbus_interface.h"
30
31 #include <library.h>
32 #include <daemon.h>
33 #include <processing/jobs/callback_job.h>
34
35
36 #define NM_DBUS_SERVICE_STRONG "org.freedesktop.NetworkManager.strongswan"
37 #define NM_DBUS_INTERFACE_STRONG "org.freedesktop.NetworkManager.strongswan"
38 #define NM_DBUS_PATH_STRONG "/org/freedesktop/NetworkManager/strongswan"
39
40 typedef struct private_dbus_interface_t private_dbus_interface_t;
41
42 /**
43 * Private data of an dbus_interface_t object.
44 */
45 struct private_dbus_interface_t {
46
47 /**
48 * Public part of dbus_t object.
49 */
50 dbus_interface_t public;
51
52 /**
53 * DBUS connection
54 */
55 DBusConnection* conn;
56
57 /**
58 * error value used here and there
59 */
60 DBusError err;
61
62 /**
63 * state of the daemon
64 */
65 NMVPNState state;
66
67 /**
68 * job accepting stroke messages
69 */
70 callback_job_t *job;
71
72 /**
73 * name of the currently active connection
74 */
75 char *name;
76 };
77
78 /**
79 * set daemon state and send StateChange signal to the bus
80 */
81 static void set_state(private_dbus_interface_t *this, NMVPNState state)
82 {
83 DBusMessage* msg;
84
85 msg = dbus_message_new_signal(NM_DBUS_PATH_STRONG, NM_DBUS_INTERFACE_STRONG, NM_DBUS_VPN_SIGNAL_STATE_CHANGE);
86
87 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &this->state,
88 DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID) ||
89 !dbus_connection_send(this->conn, msg, NULL))
90 {
91 DBG1(DBG_CFG, "unable to send DBUS StateChange signal");
92 }
93 dbus_connection_flush(this->conn);
94 dbus_message_unref(msg);
95 this->state = state;
96 }
97
98
99 /**
100 * get the child_cfg with the same name as the peer cfg
101 */
102 static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
103 {
104 child_cfg_t *current, *found = NULL;
105 iterator_t *iterator;
106
107 iterator = peer_cfg->create_child_cfg_iterator(peer_cfg);
108 while (iterator->iterate(iterator, (void**)&current))
109 {
110 if (streq(current->get_name(current), name))
111 {
112 found = current;
113 found->get_ref(found);
114 break;
115 }
116 }
117 iterator->destroy(iterator);
118 return found;
119 }
120
121 /**
122 * process NetworkManagers startConnection method call
123 */
124 static bool start_connection(private_dbus_interface_t *this, DBusMessage* msg)
125 {
126 DBusMessage *reply, *signal;
127 char *name, *user, **data, **passwords, **routes;
128 int data_count, passwords_count, routes_count;
129 u_int32_t me, other, p2p, netmask, mss;
130 char *dev, *domain, *banner;
131 const dbus_int32_t array[] = {};
132 const dbus_int32_t *varray = array;
133 peer_cfg_t *peer_cfg;
134 child_cfg_t *child_cfg;
135 status_t status = FAILED;
136
137 dbus_error_free(&this->err);
138
139 if (!dbus_message_get_args(msg, &this->err,
140 DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user,
141 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &passwords_count,
142 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data, &data_count,
143 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &routes, &routes_count,
144 DBUS_TYPE_INVALID))
145 {
146 return FALSE;
147 }
148 set_state(this, NM_VPN_STATE_STARTING);
149
150 peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name);
151 if (peer_cfg)
152 {
153 free(this->name);
154 this->name = strdup(peer_cfg->get_name(peer_cfg));
155 child_cfg = get_child_from_peer(peer_cfg, name);
156 if (child_cfg)
157 {
158 status = charon->interfaces->initiate(charon->interfaces, peer_cfg,
159 child_cfg, NULL, NULL);
160 }
161 else
162 {
163 peer_cfg->destroy(peer_cfg);
164 }
165 }
166 reply = dbus_message_new_method_return(msg);
167 dbus_connection_send(this->conn, reply, NULL);
168 dbus_message_unref(reply);
169
170 if (status == SUCCESS)
171 {
172
173 set_state(this, NM_VPN_STATE_STARTED);
174 signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG,
175 NM_DBUS_INTERFACE_STRONG,
176 NM_DBUS_VPN_SIGNAL_IP4_CONFIG);
177 me = other = p2p = mss = netmask = 0;
178 dev = domain = banner = "";
179 if (dbus_message_append_args(signal,
180 DBUS_TYPE_UINT32, &other,
181 DBUS_TYPE_STRING, &dev,
182 DBUS_TYPE_UINT32, &me,
183 DBUS_TYPE_UINT32, &p2p,
184 DBUS_TYPE_UINT32, &netmask,
185 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
186 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
187 DBUS_TYPE_UINT32, &mss,
188 DBUS_TYPE_STRING, &domain,
189 DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID))
190 {
191 dbus_connection_send(this->conn, signal, NULL);
192 }
193 dbus_message_unref(signal);
194 }
195 else
196 {
197 set_state(this, NM_VPN_STATE_STOPPED);
198 }
199
200 dbus_connection_flush(this->conn);
201 return TRUE;
202 }
203
204 /**
205 * process NetworkManagers stopConnection method call
206 */
207 static bool stop_connection(private_dbus_interface_t *this, DBusMessage* msg)
208 {
209 u_int32_t id;
210 iterator_t *iterator;
211 ike_sa_t *ike_sa;
212
213 if (this->name == NULL)
214 {
215 return FALSE;
216 }
217
218 dbus_error_free(&this->err);
219
220 set_state(this, NM_VPN_STATE_STOPPING);
221
222 iterator = charon->interfaces->create_ike_sa_iterator(charon->interfaces);
223 while (iterator->iterate(iterator, (void**)&ike_sa))
224 {
225 child_sa_t *child_sa;
226 iterator_t *children;
227
228 if (this->name && streq(this->name, ike_sa->get_name(ike_sa)))
229 {
230 id = ike_sa->get_unique_id(ike_sa);
231 iterator->destroy(iterator);
232 charon->interfaces->terminate_ike(charon->interfaces, id, NULL, NULL);
233 set_state(this, NM_VPN_STATE_STOPPED);
234 return TRUE;;
235 }
236 children = ike_sa->create_child_sa_iterator(ike_sa);
237 while (children->iterate(children, (void**)&child_sa))
238 {
239 if (this->name && streq(this->name, child_sa->get_name(child_sa)))
240 {
241 id = child_sa->get_reqid(child_sa);
242 children->destroy(children);
243 iterator->destroy(iterator);
244 charon->interfaces->terminate_child(charon->interfaces, id, NULL, NULL);
245 set_state(this, NM_VPN_STATE_STOPPED);
246 return TRUE;
247 }
248 }
249 children->destroy(children);
250 }
251 iterator->destroy(iterator);
252 set_state(this, NM_VPN_STATE_STOPPED);
253 return TRUE;
254 }
255
256 /**
257 * process NetworkManagers getState method call
258 */
259 static bool get_state(private_dbus_interface_t *this, DBusMessage* msg)
260 {
261 DBusMessage* reply;
262 reply = dbus_message_new_method_return(msg);
263 if (!reply || !dbus_message_append_args(reply,
264 DBUS_TYPE_UINT32, &this->state,
265 DBUS_TYPE_INVALID))
266 {
267 return FALSE;
268 }
269 dbus_connection_send(this->conn, reply, NULL);
270 return TRUE;
271 }
272
273 /**
274 * Handle incoming messages
275 */
276 static DBusHandlerResult message_handler(DBusConnection *con, DBusMessage *msg,
277 private_dbus_interface_t *this)
278 {
279 bool handled;
280
281 if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG,
282 "startConnection"))
283 {
284 handled = start_connection(this, msg);
285 }
286 else if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG,
287 "stopConnection"))
288 {
289 handled = stop_connection(this, msg);
290 }
291 else if (dbus_message_is_method_call(msg, NM_DBUS_INTERFACE_STRONG,
292 "getState"))
293 {
294 handled = get_state(this, msg);
295 }
296 else
297 {
298 DBG1(DBG_CFG, "ignoring DBUS message %s.%s",
299 dbus_message_get_interface(msg), dbus_message_get_member(msg));
300 handled = FALSE;
301 }
302
303 if (handled)
304 {
305 return DBUS_HANDLER_RESULT_HANDLED;
306 }
307 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
308 }
309
310 /**
311 * Handle received signals
312
313 static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg,
314 private_dbus_interface_t *this)
315 {
316 bool handled;
317
318 if (dbus_message_is_signal(msg, NM_DBUS_INTERFACE, "VPNConnectionStateChange"))
319 {
320 NMVPNState state;
321 char *name;
322
323 if (dbus_message_get_args(msg, &this->err, DBUS_TYPE_STRING, &name,
324 DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID))
325 {
326 DBG1(DBG_CFG, "got state %d for %s", state, name);
327 }
328 handled = TRUE;
329 }
330 else
331 {
332 DBG1(DBG_CFG, "ignoring DBUS signal %s.%s",
333 dbus_message_get_interface(msg), dbus_message_get_member(msg));
334 handled = FALSE;
335 }
336 if (handled)
337 {
338 return DBUS_HANDLER_RESULT_HANDLED;
339 }
340 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
341 } */
342
343 /**
344 * dispatcher function processed by a seperate thread
345 */
346 static job_requeue_t dispatch(private_dbus_interface_t *this)
347 {
348 if (dbus_connection_read_write_dispatch(this->conn, -1))
349 {
350 return JOB_REQUEUE_DIRECT;
351 }
352 return JOB_REQUEUE_NONE;
353 }
354
355 /**
356 * Implementation of interface_t.destroy.
357 */
358 static void destroy(private_dbus_interface_t *this)
359 {
360 this->job->cancel(this->job);
361 dbus_connection_close(this->conn);
362 dbus_error_free(&this->err);
363 dbus_shutdown();
364 free(this->name);
365 free(this);
366 }
367
368 /*
369 * Described in header file
370 */
371 interface_t *interface_create()
372 {
373 int ret;
374 DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL};
375 private_dbus_interface_t *this = malloc_thing(private_dbus_interface_t);
376
377 this->public.interface.destroy = (void (*)(interface_t*))destroy;
378
379 dbus_error_init(&this->err);
380 this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err);
381 if (dbus_error_is_set(&this->err))
382 {
383 DBG1(DBG_CFG, "unable to open DBUS connection: %s", this->err.message);
384 charon->kill(charon, "DBUS initialization failed");
385 }
386 dbus_connection_set_exit_on_disconnect(this->conn, FALSE);
387
388 ret = dbus_bus_request_name(this->conn, NM_DBUS_SERVICE_STRONG,
389 DBUS_NAME_FLAG_REPLACE_EXISTING , &this->err);
390 if (dbus_error_is_set(&this->err))
391 {
392 DBG1(DBG_CFG, "unable to set DBUS name: %s", this->err.message);
393 charon->kill(charon, "unable to set DBUS name");
394 }
395 if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
396 {
397 charon->kill(charon, "DBUS name already owned");
398 }
399 if (!dbus_connection_register_object_path(this->conn, NM_DBUS_PATH_STRONG, &v, this))
400 {
401 charon->kill(charon, "unable to register DBUS message handler");
402 }
403 /*
404 if (!dbus_connection_add_filter(this->conn, (void*)signal_handler, this, NULL))
405 {
406 charon->kill(charon, "unable to register DBUS signal handler");
407 }
408
409 dbus_bus_add_match(this->conn, "type='signal', "
410 "interface='" NM_DBUS_INTERFACE_VPN "',"
411 "path='" NM_DBUS_PATH_VPN "'", &this->err);
412 if (dbus_error_is_set (&this->err))
413 {
414 charon->kill(charon, "unable to add DBUS signal match");
415 }*/
416
417 this->name = NULL;
418 this->state = NM_VPN_STATE_INIT;
419 set_state(this, NM_VPN_STATE_STOPPED);
420
421 this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL);
422 charon->processor->queue_job(charon->processor, (job_t*)this->job);
423
424 return &this->public.interface;
425 }
426