2 * @file dbus_interface.c
4 * @brief Implementation of dbus_interface_t.
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
23 #define DBUS_API_SUBJECT_TO_CHANGE
24 #include <dbus/dbus.h>
25 #include <NetworkManager/NetworkManager.h>
26 #include <NetworkManager/NetworkManagerVPN.h>
29 #include "dbus_interface.h"
33 #include <processing/jobs/callback_job.h>
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"
40 typedef struct private_dbus_interface_t private_dbus_interface_t
;
43 * Private data of an dbus_interface_t object.
45 struct private_dbus_interface_t
{
48 * Public part of dbus_t object.
50 dbus_interface_t
public;
58 * error value used here and there
68 * job accepting stroke messages
73 * name of the currently active connection
79 * set daemon state and send StateChange signal to the bus
81 static void set_state(private_dbus_interface_t
*this, NMVPNState state
)
85 msg
= dbus_message_new_signal(NM_DBUS_PATH_STRONG
, NM_DBUS_INTERFACE_STRONG
, NM_DBUS_VPN_SIGNAL_STATE_CHANGE
);
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
))
91 DBG1(DBG_CFG
, "unable to send DBUS StateChange signal");
93 dbus_connection_flush(this->conn
);
94 dbus_message_unref(msg
);
100 * get the child_cfg with the same name as the peer cfg
102 static child_cfg_t
* get_child_from_peer(peer_cfg_t
*peer_cfg
, char *name
)
104 child_cfg_t
*current
, *found
= NULL
;
105 iterator_t
*iterator
;
107 iterator
= peer_cfg
->create_child_cfg_iterator(peer_cfg
);
108 while (iterator
->iterate(iterator
, (void**)¤t
))
110 if (streq(current
->get_name(current
), name
))
113 found
->get_ref(found
);
117 iterator
->destroy(iterator
);
124 static bool dbus_log(void *param
, signal_t signal
, level_t level
,
125 ike_sa_t
*ike_sa
, char *format
, va_list args
)
132 * process NetworkManagers startConnection method call
134 static bool start_connection(private_dbus_interface_t
*this, DBusMessage
* msg
)
136 DBusMessage
*reply
, *signal
;
137 char *name
, *user
, **data
, **passwords
, **routes
;
138 int data_count
, passwords_count
, routes_count
;
139 u_int32_t me
, other
, p2p
, netmask
, mss
;
140 char *dev
, *domain
, *banner
;
141 const dbus_int32_t array
[] = {};
142 const dbus_int32_t
*varray
= array
;
143 peer_cfg_t
*peer_cfg
;
144 child_cfg_t
*child_cfg
;
145 status_t status
= FAILED
;
147 dbus_error_free(&this->err
);
149 if (!dbus_message_get_args(msg
, &this->err
,
150 DBUS_TYPE_STRING
, &name
, DBUS_TYPE_STRING
, &user
,
151 DBUS_TYPE_ARRAY
, DBUS_TYPE_STRING
, &passwords
, &passwords_count
,
152 DBUS_TYPE_ARRAY
, DBUS_TYPE_STRING
, &data
, &data_count
,
153 DBUS_TYPE_ARRAY
, DBUS_TYPE_STRING
, &routes
, &routes_count
,
158 set_state(this, NM_VPN_STATE_STARTING
);
160 peer_cfg
= charon
->backends
->get_peer_cfg_by_name(charon
->backends
, name
);
164 this->name
= strdup(peer_cfg
->get_name(peer_cfg
));
165 child_cfg
= get_child_from_peer(peer_cfg
, name
);
168 status
= charon
->interfaces
->initiate(charon
->interfaces
, peer_cfg
,
169 child_cfg
, dbus_log
, NULL
);
173 peer_cfg
->destroy(peer_cfg
);
176 reply
= dbus_message_new_method_return(msg
);
177 dbus_connection_send(this->conn
, reply
, NULL
);
178 dbus_message_unref(reply
);
180 if (status
== SUCCESS
)
183 set_state(this, NM_VPN_STATE_STARTED
);
184 signal
= dbus_message_new_signal(NM_DBUS_PATH_STRONG
,
185 NM_DBUS_INTERFACE_STRONG
,
186 NM_DBUS_VPN_SIGNAL_IP4_CONFIG
);
187 me
= other
= p2p
= mss
= netmask
= 0;
188 dev
= domain
= banner
= "";
189 if (dbus_message_append_args(signal
,
190 DBUS_TYPE_UINT32
, &other
,
191 DBUS_TYPE_STRING
, &dev
,
192 DBUS_TYPE_UINT32
, &me
,
193 DBUS_TYPE_UINT32
, &p2p
,
194 DBUS_TYPE_UINT32
, &netmask
,
195 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &varray
, 0,
196 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &varray
, 0,
197 DBUS_TYPE_UINT32
, &mss
,
198 DBUS_TYPE_STRING
, &domain
,
199 DBUS_TYPE_STRING
, &banner
, DBUS_TYPE_INVALID
))
201 dbus_connection_send(this->conn
, signal
, NULL
);
203 dbus_message_unref(signal
);
207 set_state(this, NM_VPN_STATE_STOPPED
);
210 dbus_connection_flush(this->conn
);
215 * process NetworkManagers stopConnection method call
217 static bool stop_connection(private_dbus_interface_t
*this, DBusMessage
* msg
)
220 iterator_t
*iterator
;
223 if (this->name
== NULL
)
228 dbus_error_free(&this->err
);
230 set_state(this, NM_VPN_STATE_STOPPING
);
232 iterator
= charon
->interfaces
->create_ike_sa_iterator(charon
->interfaces
);
233 while (iterator
->iterate(iterator
, (void**)&ike_sa
))
235 child_sa_t
*child_sa
;
236 iterator_t
*children
;
238 if (this->name
&& streq(this->name
, ike_sa
->get_name(ike_sa
)))
240 id
= ike_sa
->get_unique_id(ike_sa
);
241 iterator
->destroy(iterator
);
242 charon
->interfaces
->terminate_ike(charon
->interfaces
, id
, NULL
, NULL
);
243 set_state(this, NM_VPN_STATE_STOPPED
);
246 children
= ike_sa
->create_child_sa_iterator(ike_sa
);
247 while (children
->iterate(children
, (void**)&child_sa
))
249 if (this->name
&& streq(this->name
, child_sa
->get_name(child_sa
)))
251 id
= child_sa
->get_reqid(child_sa
);
252 children
->destroy(children
);
253 iterator
->destroy(iterator
);
254 charon
->interfaces
->terminate_child(charon
->interfaces
, id
, NULL
, NULL
);
255 set_state(this, NM_VPN_STATE_STOPPED
);
259 children
->destroy(children
);
261 iterator
->destroy(iterator
);
262 set_state(this, NM_VPN_STATE_STOPPED
);
267 * process NetworkManagers getState method call
269 static bool get_state(private_dbus_interface_t
*this, DBusMessage
* msg
)
272 reply
= dbus_message_new_method_return(msg
);
273 if (!reply
|| !dbus_message_append_args(reply
,
274 DBUS_TYPE_UINT32
, &this->state
,
279 dbus_connection_send(this->conn
, reply
, NULL
);
284 * Handle incoming messages
286 static DBusHandlerResult
message_handler(DBusConnection
*con
, DBusMessage
*msg
,
287 private_dbus_interface_t
*this)
291 if (dbus_message_is_method_call(msg
, NM_DBUS_INTERFACE_STRONG
,
294 handled
= start_connection(this, msg
);
296 else if (dbus_message_is_method_call(msg
, NM_DBUS_INTERFACE_STRONG
,
299 handled
= stop_connection(this, msg
);
301 else if (dbus_message_is_method_call(msg
, NM_DBUS_INTERFACE_STRONG
,
304 handled
= get_state(this, msg
);
308 DBG1(DBG_CFG
, "ignoring DBUS message %s.%s",
309 dbus_message_get_interface(msg
), dbus_message_get_member(msg
));
315 return DBUS_HANDLER_RESULT_HANDLED
;
317 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
321 * Handle received signals
323 static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg,
324 private_dbus_interface_t *this)
328 if (dbus_message_is_signal(msg, NM_DBUS_INTERFACE, "VPNConnectionStateChange"))
333 if (dbus_message_get_args(msg, &this->err, DBUS_TYPE_STRING, &name,
334 DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID))
336 DBG1(DBG_CFG, "got state %d for %s", state, name);
342 DBG1(DBG_CFG, "ignoring DBUS signal %s.%s",
343 dbus_message_get_interface(msg), dbus_message_get_member(msg));
348 return DBUS_HANDLER_RESULT_HANDLED;
350 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
354 * dispatcher function processed by a seperate thread
356 static job_requeue_t
dispatch(private_dbus_interface_t
*this)
358 if (dbus_connection_read_write_dispatch(this->conn
, -1))
360 return JOB_REQUEUE_DIRECT
;
362 return JOB_REQUEUE_NONE
;
366 * Implementation of interface_t.destroy.
368 static void destroy(private_dbus_interface_t
*this)
370 this->job
->cancel(this->job
);
371 dbus_connection_close(this->conn
);
372 dbus_error_free(&this->err
);
379 * Described in header file
381 interface_t
*interface_create()
384 DBusObjectPathVTable v
= {NULL
, (void*)&message_handler
, NULL
, NULL
, NULL
, NULL
};
385 private_dbus_interface_t
*this = malloc_thing(private_dbus_interface_t
);
387 this->public.interface
.destroy
= (void (*)(interface_t
*))destroy
;
389 dbus_error_init(&this->err
);
390 this->conn
= dbus_bus_get(DBUS_BUS_SYSTEM
, &this->err
);
391 if (dbus_error_is_set(&this->err
))
393 DBG1(DBG_CFG
, "unable to open DBUS connection: %s", this->err
.message
);
394 charon
->kill(charon
, "DBUS initialization failed");
396 dbus_connection_set_exit_on_disconnect(this->conn
, FALSE
);
398 ret
= dbus_bus_request_name(this->conn
, NM_DBUS_SERVICE_STRONG
,
399 DBUS_NAME_FLAG_REPLACE_EXISTING
, &this->err
);
400 if (dbus_error_is_set(&this->err
))
402 DBG1(DBG_CFG
, "unable to set DBUS name: %s", this->err
.message
);
403 charon
->kill(charon
, "unable to set DBUS name");
405 if (ret
!= DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
)
407 charon
->kill(charon
, "DBUS name already owned");
409 if (!dbus_connection_register_object_path(this->conn
, NM_DBUS_PATH_STRONG
, &v
, this))
411 charon
->kill(charon
, "unable to register DBUS message handler");
414 if (!dbus_connection_add_filter(this->conn, (void*)signal_handler, this, NULL))
416 charon->kill(charon, "unable to register DBUS signal handler");
419 dbus_bus_add_match(this->conn, "type='signal', "
420 "interface='" NM_DBUS_INTERFACE_VPN "',"
421 "path='" NM_DBUS_PATH_VPN "'", &this->err);
422 if (dbus_error_is_set (&this->err))
424 charon->kill(charon, "unable to add DBUS signal match");
428 this->state
= NM_VPN_STATE_INIT
;
429 set_state(this, NM_VPN_STATE_STOPPED
);
431 this->job
= callback_job_create((callback_job_cb_t
)dispatch
, this, NULL
, NULL
);
432 charon
->processor
->queue_job(charon
->processor
, (job_t
*)this->job
);
434 return &this->public.interface
;