diff --git a/ChangeLog b/ChangeLog index 6e68779b86..31788edfcf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2005-09-07 Dan Williams + + * The great VPN Manager rewrite of 2005 + 2005-09-07 Christopher Aillon * gnome/applet/menu-items.c: diff --git a/NetworkManager.h b/NetworkManager.h index f54c7a4a3d..b3d849716b 100644 --- a/NetworkManager.h +++ b/NetworkManager.h @@ -192,6 +192,22 @@ typedef enum NMVPNState } NMVPNState; +/* + * VPN connection activation stages + */ +typedef enum NMVPNActStage +{ + NM_VPN_ACT_STAGE_UNKNOWN = 0, + NM_VPN_ACT_STAGE_DISCONNECTED, + NM_VPN_ACT_STAGE_PREPARE, + NM_VPN_ACT_STAGE_CONNECT, + NM_VPN_ACT_STAGE_IP_CONFIG_GET, + NM_VPN_ACT_STAGE_ACTIVATED, + NM_VPN_ACT_STAGE_FAILED, + NM_VPN_ACT_STAGE_CANCELED +} NMVPNActStage; + + /* * Device activation stages */ diff --git a/gnome/applet/applet-dbus-vpn.c b/gnome/applet/applet-dbus-vpn.c index e6f1195c83..672c4c15f5 100644 --- a/gnome/applet/applet-dbus-vpn.c +++ b/gnome/applet/applet-dbus-vpn.c @@ -36,43 +36,19 @@ static void nmwa_free_vpn_connections (NMWirelessApplet *applet); -/* - * nmwa_dbus_vpn_get_active_vpn_connection - * - * Get the active VPN connection from the dbus side of the applet - * - */ -VPNConnection *nmwa_dbus_vpn_get_active_vpn_connection (NMWirelessApplet *applet) -{ - GSList *elt; - - g_return_val_if_fail (applet != NULL, NULL); - - for (elt = applet->vpn_connections; elt; elt = g_slist_next (elt)) - { - VPNConnection *vpn = (VPNConnection*) elt->data; - NMVPNState vpn_state = nmwa_vpn_connection_get_state (vpn); - - if (vpn_state == NM_VPN_STATE_STARTED) - return vpn; - } - - return NULL; -} /* * nmwa_dbus_vpn_update_vpn_connection_state * * Sets the state for a dbus vpn connection and schedules a copy to the applet gui. */ -void nmwa_dbus_vpn_update_vpn_connection_state (NMWirelessApplet *applet, const char *vpn_name, NMVPNState vpn_state) +void nmwa_dbus_vpn_update_vpn_connection_state (NMWirelessApplet *applet, const char *vpn_name, NMVPNActStage vpn_state) { VPNConnection *vpn; g_return_if_fail (applet != NULL); - vpn = nmwa_vpn_connection_find_by_name (applet->vpn_connections, vpn_name); - if (vpn != NULL) + if ((vpn = nmwa_vpn_connection_find_by_name (applet->vpn_connections, vpn_name))) nmwa_vpn_connection_set_state (vpn, vpn_state); } @@ -106,7 +82,7 @@ static void nmwa_dbus_vpn_properties_cb (DBusPendingCall *pcall, void *user_data const char * name; const char * user_name; const char * service; - NMVPNState state; + NMVPNActStage state; dbus_uint32_t state_int; g_return_if_fail (pcall != NULL); @@ -130,7 +106,7 @@ static void nmwa_dbus_vpn_properties_cb (DBusPendingCall *pcall, void *user_data { VPNConnection * vpn; - state = (NMVPNState) state_int; + state = (NMVPNActStage) state_int; /* If its already there, update the service, otherwise add it to the list */ if ((vpn = nmwa_vpn_connection_find_by_name (applet->vpn_connections, name))) @@ -167,7 +143,7 @@ void nmwa_dbus_vpn_update_one_vpn_connection (NMWirelessApplet *applet, const ch g_return_if_fail (applet != NULL); g_return_if_fail (vpn_name != NULL); - nmwa_dbus_vpn_get_active_vpn_connection (applet); + nmwa_get_first_active_vpn_connection (applet); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "getVPNConnectionProperties"))) { @@ -241,7 +217,7 @@ void nmwa_dbus_vpn_update_vpn_connections (NMWirelessApplet *applet) nmwa_free_vpn_connections (applet); - nmwa_dbus_vpn_get_active_vpn_connection (applet); + nmwa_get_first_active_vpn_connection (applet); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "getVPNConnections"))) { diff --git a/gnome/applet/applet-dbus-vpn.h b/gnome/applet/applet-dbus-vpn.h index 1e0294db4f..31684feef1 100644 --- a/gnome/applet/applet-dbus-vpn.h +++ b/gnome/applet/applet-dbus-vpn.h @@ -33,6 +33,6 @@ void nmwa_dbus_vpn_remove_one_vpn_connection (NMWirelessApplet *applet, const void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, GSList *passwords); void nmwa_dbus_vpn_deactivate_connection (DBusConnection *connection); -void nmwa_dbus_vpn_update_vpn_connection_state (NMWirelessApplet *applet, const char *vpn_name, NMVPNState vpn_state); +void nmwa_dbus_vpn_update_vpn_connection_state (NMWirelessApplet *applet, const char *vpn_name, NMVPNActStage vpn_state); #endif diff --git a/gnome/applet/applet-dbus.c b/gnome/applet/applet-dbus.c index 65f1004fcc..c9aa9b3327 100644 --- a/gnome/applet/applet-dbus.c +++ b/gnome/applet/applet-dbus.c @@ -224,12 +224,13 @@ static DBusHandlerResult nmwa_dbus_filter (DBusConnection *connection, DBusMessa } else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNConnectionStateChange")) /* Active VPN connection changed */ { - char *name = NULL; - NMVPNState vpn_state; - dbus_uint32_t vpn_state_int; + char * name = NULL; + NMVPNActStage vpn_state; + dbus_uint32_t vpn_state_int; + if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &vpn_state_int, DBUS_TYPE_INVALID)) { - vpn_state = (NMVPNState) vpn_state_int; + vpn_state = (NMVPNActStage) vpn_state_int; nmwa_dbus_vpn_update_vpn_connection_state (applet, name, vpn_state); } } diff --git a/gnome/applet/applet.c b/gnome/applet/applet.c index bded3f0b33..79c0337de0 100644 --- a/gnome/applet/applet.c +++ b/gnome/applet/applet.c @@ -869,19 +869,23 @@ out: } -VPNConnection* nmwa_get_active_vpn_connection (NMWirelessApplet *applet) +/* + * nmwa_get_first_active_vpn_connection + * + * Return the first active VPN connection, if any. + * + */ +VPNConnection *nmwa_get_first_active_vpn_connection (NMWirelessApplet *applet) { - VPNConnection *vpn; - NMVPNState vpn_state; - GSList *elt; + VPNConnection * vpn; + NMVPNActStage vpn_state; + GSList * elt; - elt = applet->vpn_connections; - - for (; elt; elt = g_slist_next (elt)) + for (elt = applet->vpn_connections; elt; elt = g_slist_next (elt)) { vpn = (VPNConnection*) elt->data; vpn_state = nmwa_vpn_connection_get_state (vpn); - if (vpn_state == NM_VPN_STATE_STARTED) + if (vpn_state == NM_VPN_ACT_STAGE_ACTIVATED) return vpn; } @@ -899,7 +903,7 @@ static void nmwa_set_icon (NMWirelessApplet *applet, GdkPixbuf *new_icon) composite = gdk_pixbuf_copy (new_icon); - vpn = nmwa_get_active_vpn_connection (applet); + vpn = nmwa_get_first_active_vpn_connection (applet); if (vpn) { @@ -1132,8 +1136,9 @@ done: if (!applet->tooltips) applet->tooltips = gtk_tooltips_new (); - vpn = nmwa_get_active_vpn_connection (applet); - if (vpn != NULL) { + vpn = nmwa_get_first_active_vpn_connection (applet); + if (vpn != NULL) + { char *newtip; char *vpntip; @@ -1313,8 +1318,8 @@ static void nmwa_menu_vpn_item_activate (GtkMenuItem *item, gpointer user_data) VPNConnection *vpn = (VPNConnection *)tag; const char *name = nmwa_vpn_connection_get_name (vpn); GSList *passwords; + VPNConnection *active_vpn = nmwa_get_first_active_vpn_connection (applet); - VPNConnection *active_vpn = nmwa_get_active_vpn_connection (applet); if (vpn != active_vpn) { char *gconf_key; @@ -1687,7 +1692,7 @@ static void nmwa_menu_add_vpn_menu (GtkWidget *menu, NMWirelessApplet *applet) item = GTK_MENU_ITEM (gtk_menu_item_new_with_mnemonic (_("_VPN Connections"))); vpn_menu = GTK_MENU (gtk_menu_new ()); - active_vpn = nmwa_get_active_vpn_connection (applet); + active_vpn = nmwa_get_first_active_vpn_connection (applet); for (elt = applet->vpn_connections; elt; elt = g_slist_next (elt)) { diff --git a/gnome/applet/applet.h b/gnome/applet/applet.h index ab3ac0d407..b98b18f52b 100644 --- a/gnome/applet/applet.h +++ b/gnome/applet/applet.h @@ -146,6 +146,7 @@ void nmwa_schedule_vpn_failure_dialog (NMWirelessApplet *applet, const char void nmwa_schedule_vpn_login_banner_dialog (NMWirelessApplet *applet, const char *vpn_name, const char *banner); NetworkDevice * nmwa_get_first_active_device (GSList *dev_list); +VPNConnection * nmwa_get_first_active_vpn_connection (NMWirelessApplet *applet); NMWirelessScanMethod nmwa_gconf_get_wireless_scan_method (NMWirelessApplet *applet); diff --git a/gnome/applet/vpn-connection.c b/gnome/applet/vpn-connection.c index 54e97226af..d06b5c7a62 100644 --- a/gnome/applet/vpn-connection.c +++ b/gnome/applet/vpn-connection.c @@ -25,10 +25,10 @@ struct VPNConnection { - int refcount; - char *name; - char *service; - NMVPNState state; + int refcount; + char * name; + char * service; + NMVPNActStage state; }; @@ -136,14 +136,14 @@ VPNConnection *nmwa_vpn_connection_find_by_name (GSList *list, const char *name) return vpn; } -NMVPNState nmwa_vpn_connection_get_state (VPNConnection *vpn) +NMVPNActStage nmwa_vpn_connection_get_state (VPNConnection *vpn) { - g_return_val_if_fail (vpn != NULL, NM_VPN_STATE_UNKNOWN); + g_return_val_if_fail (vpn != NULL, NM_VPN_ACT_STAGE_UNKNOWN); return vpn->state; } -void nmwa_vpn_connection_set_state (VPNConnection *vpn, NMVPNState state) +void nmwa_vpn_connection_set_state (VPNConnection *vpn, NMVPNActStage state) { g_return_if_fail (vpn != NULL); diff --git a/gnome/applet/vpn-connection.h b/gnome/applet/vpn-connection.h index f67b9cff28..8b45a9dbd2 100644 --- a/gnome/applet/vpn-connection.h +++ b/gnome/applet/vpn-connection.h @@ -34,8 +34,8 @@ const char * nmwa_vpn_connection_get_name (VPNConnection *vpn); const char * nmwa_vpn_connection_get_service (VPNConnection *vpn); void nmwa_vpn_connection_set_service (VPNConnection *vpn, const char *service); -NMVPNState nmwa_vpn_connection_get_state (VPNConnection *vpn); -void nmwa_vpn_connection_set_state (VPNConnection *vpn, NMVPNState state); +NMVPNActStage nmwa_vpn_connection_get_state (VPNConnection *vpn); +void nmwa_vpn_connection_set_state (VPNConnection *vpn, NMVPNActStage state); VPNConnection * nmwa_vpn_connection_find_by_name (GSList *list, const char *name); diff --git a/gnome/applet/vpn-password-dialog.c b/gnome/applet/vpn-password-dialog.c index feb0b253d3..5284094320 100644 --- a/gnome/applet/vpn-password-dialog.c +++ b/gnome/applet/vpn-password-dialog.c @@ -166,8 +166,6 @@ nmwa_vpn_request_password (NMWirelessApplet *applet, const char *name, const cha if (!retry) argv[5] = NULL; - nm_debug ("retry = %d", retry); - child_status = -1; if (!g_spawn_async_with_pipes (NULL, /* working_directory */ diff --git a/src/NetworkManager.c b/src/NetworkManager.c index 2403d5b040..7e5db21762 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -459,7 +459,7 @@ static void nm_data_free (NMData *data) g_return_if_fail (data != NULL); /* Kill any active VPN connection */ - if (nm_vpn_manager_get_active_vpn_connection (data->vpn_manager)) + if (nm_vpn_manager_get_vpn_act_request (data->vpn_manager)) nm_vpn_manager_deactivate_vpn_connection (data->vpn_manager); /* Stop and destroy all devices */ diff --git a/src/NetworkManagerMain.h b/src/NetworkManagerMain.h index b1d5db2368..b2bb9790c4 100644 --- a/src/NetworkManagerMain.h +++ b/src/NetworkManagerMain.h @@ -46,6 +46,7 @@ typedef enum NMIntState typedef struct NMDbusMethodList NMDbusMethodList; typedef struct NMActRequest NMActRequest; +typedef struct NMVPNActRequest NMVPNActRequest; typedef struct NMVPNManager NMVPNManager; typedef struct NMDHCPManager NMDHCPManager; diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 7f847d4668..17d149fe7e 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -413,10 +413,12 @@ static gboolean nm_policy_device_change_check (NMData *data) /* Schedule new activation if the currently associated access point is not the "best" one * or we've lost the link to the old access point. */ - if ((strcmp (old_essid, new_essid) != 0) || !nm_device_has_active_link (old_dev)) + gboolean es = (strcmp (old_essid, new_essid) != 0); + gboolean link = nm_device_has_active_link (old_dev); + if (es || !link) { - nm_info ("SWITCH: found better connection '%s/%s' than current connection '%s/%s'.", nm_device_get_iface (new_dev), - new_essid, nm_device_get_iface (old_dev), old_essid); + nm_info ("SWITCH: found better connection '%s/%s' than current connection '%s/%s'. essid=%d, link=%d", nm_device_get_iface (new_dev), + new_essid, nm_device_get_iface (old_dev), old_essid, es, link); do_switch = TRUE; } } diff --git a/src/vpn-manager/Makefile.am b/src/vpn-manager/Makefile.am index 12f6f760bc..51dc6d9959 100644 --- a/src/vpn-manager/Makefile.am +++ b/src/vpn-manager/Makefile.am @@ -9,7 +9,9 @@ libvpn_manager_la_SOURCES = nm-dbus-vpn.c \ nm-vpn-manager.c \ nm-vpn-manager.h \ nm-vpn-service.c \ - nm-vpn-service.h + nm-vpn-service.h \ + nm-vpn-act-request.c \ + nm-vpn-act-request.h libvpn_manager_la_CPPFLAGS = $(DBUS_CFLAGS) \ $(GTHREAD_CFLAGS) \ diff --git a/src/vpn-manager/nm-dbus-vpn.c b/src/vpn-manager/nm-dbus-vpn.c index 5f8755778c..9ac153d49d 100644 --- a/src/vpn-manager/nm-dbus-vpn.c +++ b/src/vpn-manager/nm-dbus-vpn.c @@ -28,6 +28,8 @@ #include "nm-dbus-vpn.h" #include "nm-vpn-manager.h" #include "nm-vpn-connection.h" +#include "nm-vpn-service.h" +#include "nm-vpn-act-request.h" #include "nm-utils.h" @@ -64,12 +66,11 @@ void nm_dbus_vpn_signal_vpn_connection_update (DBusConnection *con, NMVPNConnect * * Notifies the bus that a VPN connection's state has changed. */ -void nm_dbus_vpn_signal_vpn_connection_state_change (DBusConnection *con, NMVPNConnection *vpn) +void nm_dbus_vpn_signal_vpn_connection_state_change (DBusConnection *con, NMVPNConnection *vpn, NMVPNActStage new_stage) { - DBusMessage *message; - const char *vpn_name; - NMVPNService *service; - NMVPNState vpn_state; + DBusMessage * message; + const char * vpn_name; + dbus_uint32_t int_stage = (dbus_uint32_t) new_stage; g_return_if_fail (con != NULL); g_return_if_fail (vpn != NULL); @@ -81,10 +82,7 @@ void nm_dbus_vpn_signal_vpn_connection_state_change (DBusConnection *con, NMVPNC } vpn_name = nm_vpn_connection_get_name (vpn); - service = nm_vpn_connection_get_service (vpn); - vpn_state = nm_vpn_service_get_state (service); - - dbus_message_append_args (message, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_UINT32, &vpn_state, DBUS_TYPE_INVALID); + dbus_message_append_args (message, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_UINT32, &int_stage, DBUS_TYPE_INVALID); if (!dbus_connection_send (con, message, NULL)) nm_warning ("Could not raise the VPNConnectionStateChange signal!"); @@ -358,12 +356,16 @@ static void nm_dbus_vpn_update_one_connection_cb (DBusPendingCall *pcall, void * if (dbus_message_is_error (reply, "BadVPNConnectionData")) { - NMVPNConnection *vpn = nm_vpn_manager_find_connection_by_name (cb_data->data->vpn_manager, cb_data->vpn); + NMVPNConnection *vpn; - nm_vpn_connection_ref (vpn); - nm_vpn_manager_remove_connection (cb_data->data->vpn_manager, vpn); - nm_dbus_vpn_signal_vpn_connection_update (cb_data->data->dbus_connection, vpn, "VPNConnectionRemoved"); - nm_vpn_connection_unref (vpn); + /* Bad VPN, remove it from our VPN connection list */ + if ((vpn = nm_vpn_manager_find_connection_by_name (cb_data->data->vpn_manager, cb_data->vpn))) + { + nm_vpn_connection_ref (vpn); + nm_vpn_manager_remove_connection (cb_data->data->vpn_manager, vpn); + nm_dbus_vpn_signal_vpn_connection_update (cb_data->data->dbus_connection, vpn, "VPNConnectionRemoved"); + nm_vpn_connection_unref (vpn); + } goto out; } @@ -375,11 +377,19 @@ static void nm_dbus_vpn_update_one_connection_cb (DBusPendingCall *pcall, void * if ((vpn = nm_vpn_manager_find_connection_by_name (cb_data->data->vpn_manager, con_name))) { - nm_vpn_manager_remove_connection (cb_data->data->vpn_manager, vpn); - new = FALSE; + const char *vpn_service_name = nm_vpn_connection_get_service_name (vpn); + + /* If all attributes of the existing connection are the same as the one we get from NMI, + * don't do anything. + */ + if (strcmp (vpn_service_name, service_name) || strcmp (nm_vpn_connection_get_user_name (vpn), user_name)) + nm_vpn_manager_remove_connection (cb_data->data->vpn_manager, vpn); + else + new = FALSE; } - vpn = nm_vpn_manager_add_connection (cb_data->data->vpn_manager, con_name, service_name, user_name); + if (new) + vpn = nm_vpn_manager_add_connection (cb_data->data->vpn_manager, con_name, service_name, user_name); nm_dbus_vpn_signal_vpn_connection_update (cb_data->data->dbus_connection, vpn, new ? "VPNConnectionAdded" : "VPNConnectionUpdate"); } dbus_message_unref (reply); @@ -389,6 +399,9 @@ out: } +/* Should only be used by nm_dbus_vpn_connections_update_cb() */ +GSList *nm_vpn_manager_vpn_connection_list_copy (NMVPNManager *manager); + /* * nm_dbus_vpn_connections_update_cb * @@ -400,6 +413,8 @@ static void nm_dbus_vpn_connections_update_cb (DBusPendingCall *pcall, void *use NMData * data = (NMData *) user_data; DBusMessage * reply; DBusMessageIter iter, array_iter; + GSList * remove_list = NULL; + GSList * elt; g_return_if_fail (pcall); g_return_if_fail (data != NULL); @@ -417,20 +432,27 @@ static void nm_dbus_vpn_connections_update_cb (DBusPendingCall *pcall, void *use nm_info ("Updating VPN Connections..."); + remove_list = nm_vpn_manager_vpn_connection_list_copy (data->vpn_manager); + dbus_message_iter_init (reply, &iter); dbus_message_iter_recurse (&iter, &array_iter); while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING) { - DBusMessage * message; - const char * value; + DBusMessage * message; + const char * con_name; + NMVPNConnection * vpn; - dbus_message_iter_get_basic (&array_iter, &value); + dbus_message_iter_get_basic (&array_iter, &con_name); + + /* If the connection already exists, remove it from the remove list */ + if ((vpn = nm_vpn_manager_find_connection_by_name (data->vpn_manager, con_name))) + remove_list = g_slist_remove (remove_list, vpn); if ((message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getVPNConnectionProperties"))) { DBusPendingCall * vpn_pcall = NULL; - dbus_message_append_args (message, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID); + dbus_message_append_args (message, DBUS_TYPE_STRING, &con_name, DBUS_TYPE_INVALID); dbus_connection_send_with_reply (data->dbus_connection, message, &vpn_pcall, -1); dbus_message_unref (message); if (vpn_pcall) @@ -438,7 +460,7 @@ static void nm_dbus_vpn_connections_update_cb (DBusPendingCall *pcall, void *use UpdateOneVPNCBData * vpn_cb_data = g_malloc0 (sizeof (UpdateOneVPNCBData)); vpn_cb_data->data = data; - vpn_cb_data->vpn = g_strdup (value); + vpn_cb_data->vpn = g_strdup (con_name); dbus_pending_call_set_notify (vpn_pcall, nm_dbus_vpn_update_one_connection_cb, vpn_cb_data, (DBusFreeFunction) free_update_one_vpn_cb_data); } } @@ -446,6 +468,15 @@ static void nm_dbus_vpn_connections_update_cb (DBusPendingCall *pcall, void *use } dbus_message_unref (reply); + /* VPN connections left in the remove list aren't known by NMI, therefore we delete them */ + for (elt = remove_list; elt; elt = g_slist_next (elt)) + { + nm_vpn_manager_remove_connection (data->vpn_manager, elt->data); + nm_vpn_connection_unref (elt->data); + } + + g_slist_free (remove_list); + out: dbus_pending_call_unref (pcall); } @@ -501,9 +532,6 @@ static gboolean nm_dbus_vpn_connections_update_from_nmi (NMData *data) g_return_val_if_fail (data->dbus_connection != NULL, FALSE); g_return_val_if_fail (data->vpn_manager != NULL, FALSE); - /* Clear all existing connections in preparation for new ones */ - nm_vpn_manager_clear_connections (data->vpn_manager); - if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getVPNConnections"))) { nm_warning ("nm_dbus_vpn_connections_update (): Couldn't allocate the dbus message"); @@ -596,19 +624,19 @@ out: */ static DBusMessage *nm_dbus_vpn_get_vpn_connection_properties (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { - DBusMessage *reply = NULL; - DBusError error; - const char *name; - gboolean good = FALSE; - NMVPNConnection *vpn_con; + DBusMessage * reply = NULL; + DBusError error; + const char * name; + gboolean good = FALSE; + NMVPNManager * manager; + NMVPNConnection * vpn; g_return_val_if_fail (data != NULL, NULL); - g_return_val_if_fail (data->data != NULL, NULL); - g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (data->data != NULL, NULL); g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (message != NULL, NULL); /* Check for no VPN Manager */ - if (!data->data->vpn_manager) + if (!(manager = data->data->vpn_manager)) return nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_VPN, "NoVPNConnections", "There are no available VPN connections."); if (!(reply = dbus_message_new_method_return (message))) @@ -617,20 +645,26 @@ static DBusMessage *nm_dbus_vpn_get_vpn_connection_properties (DBusConnection *c dbus_error_init (&error); if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { - if ((vpn_con = nm_vpn_manager_find_connection_by_name (data->data->vpn_manager, name))) + if ((vpn = nm_vpn_manager_find_connection_by_name (manager, name))) { - const char *user_name; - const char *service_name; - NMVPNService *service; - NMVPNState state; + const char * user_name; + const char * service_name; + NMVPNService * service; - user_name = nm_vpn_connection_get_user_name (vpn_con); - service = nm_vpn_connection_get_service (vpn_con); - service_name = nm_vpn_service_get_service_name (service); - state = nm_vpn_service_get_state (service); + user_name = nm_vpn_connection_get_user_name (vpn); + service_name = nm_vpn_connection_get_service_name (vpn); + if ((service = nm_vpn_manager_find_service_by_name (data->data->vpn_manager, service_name))) + { + NMVPNActRequest * req = nm_vpn_manager_get_vpn_act_request (manager); + dbus_uint32_t stage = (dbus_uint32_t) NM_VPN_ACT_STAGE_DISCONNECTED; - dbus_message_append_args (reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user_name, DBUS_TYPE_STRING, &service_name, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID); - good = TRUE; + if (req && (nm_vpn_act_request_get_connection (req) == vpn)) + stage = nm_vpn_act_request_get_stage (req); + + dbus_message_append_args (reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user_name, + DBUS_TYPE_STRING, &service_name, DBUS_TYPE_UINT32, &stage, DBUS_TYPE_INVALID); + good = TRUE; + } } } @@ -649,22 +683,21 @@ static DBusMessage *nm_dbus_vpn_get_vpn_connection_properties (DBusConnection *c */ static DBusMessage *nm_dbus_vpn_activate_connection (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { - DBusError error; - const char *name; - char **passwords; - int num_passwords; - NMVPNConnection *vpn; + DBusError error; + const char * name; + char ** passwords; + int num_passwords; + NMVPNConnection * vpn; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (data->data != NULL, NULL); g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (message != NULL, NULL); - nm_info ("Entering"); - dbus_error_init (&error); - if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &num_passwords, DBUS_TYPE_INVALID)) { + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &num_passwords, DBUS_TYPE_INVALID)) + { if ((vpn = nm_vpn_manager_find_connection_by_name (data->data->vpn_manager, name))) { int item_count = -1; @@ -672,21 +705,20 @@ static DBusMessage *nm_dbus_vpn_activate_connection (DBusConnection *connection, if ((items = nm_dbus_vpn_get_vpn_data (connection, vpn, &item_count))) { - char *joined_string = g_strjoinv (" / ", items); - NMVPNService *service = nm_vpn_connection_get_service (vpn);; + char * joined_string = g_strjoinv (" / ", items); nm_info ("Will activate VPN connection '%s', service '%s', user_name '%s', vpn_data '%s'.", - name, nm_vpn_service_get_service_name (service), nm_vpn_connection_get_user_name (vpn), joined_string); + name, nm_vpn_connection_get_service_name (vpn), nm_vpn_connection_get_user_name (vpn), joined_string); nm_vpn_manager_activate_vpn_connection (data->data->vpn_manager, vpn, passwords, num_passwords, items, item_count); g_free (joined_string); g_strfreev (items); } } else { - nm_warning ("Cannot find name '%s'", name); + nm_warning ("nm_dbus_vpn_activate_connection(): cannot find VPN connection '%s'", name); } } else { - nm_warning ("Syntax error receiving nm_dbus_vpn_activate_connection"); + nm_warning ("nm_dbus_vpn_activate_connection(): syntax error in method arguments"); } return NULL; @@ -701,12 +733,22 @@ static DBusMessage *nm_dbus_vpn_activate_connection (DBusConnection *connection, */ static DBusMessage *nm_dbus_vpn_deactivate_connection (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) { + NMVPNActRequest *req; + NMVPNConnection *vpn; + g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (data->data != NULL, NULL); g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (message != NULL, NULL); - nm_info ("Will deactivate the current VPN connection."); + if (!(req = nm_vpn_manager_get_vpn_act_request (data->data->vpn_manager))) + return NULL; + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_info ("Will deactivate the VPN connection '%s', service '%s'.", nm_vpn_connection_get_name (vpn), + nm_vpn_connection_get_service_name (vpn)); nm_vpn_manager_deactivate_vpn_connection (data->data->vpn_manager); return NULL; diff --git a/src/vpn-manager/nm-dbus-vpn.h b/src/vpn-manager/nm-dbus-vpn.h index 2e2c256485..6eab8e6159 100644 --- a/src/vpn-manager/nm-dbus-vpn.h +++ b/src/vpn-manager/nm-dbus-vpn.h @@ -32,7 +32,7 @@ void nm_dbus_vpn_update_one_vpn_connection (DBusConnection *connection, cons void nm_dbus_vpn_signal_vpn_connection_update (DBusConnection *con, NMVPNConnection *vpn, const char *signal); void nm_dbus_vpn_signal_vpn_failed (DBusConnection *con, const char *signal, NMVPNConnection *vpn, const char *error_msg); void nm_dbus_vpn_signal_vpn_login_banner (DBusConnection *con, NMVPNConnection *vpn, const char *banner); -void nm_dbus_vpn_signal_vpn_connection_state_change (DBusConnection *con, NMVPNConnection *vpn); +void nm_dbus_vpn_signal_vpn_connection_state_change (DBusConnection *con, NMVPNConnection *vpn, NMVPNActStage new_stage); char ** nm_dbus_vpn_get_routes (DBusConnection *connection, NMVPNConnection *vpn, int *num_items); diff --git a/src/vpn-manager/nm-vpn-act-request.c b/src/vpn-manager/nm-vpn-act-request.c new file mode 100644 index 0000000000..c79a6ec001 --- /dev/null +++ b/src/vpn-manager/nm-vpn-act-request.c @@ -0,0 +1,265 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + + +#include +#include +#include "nm-vpn-act-request.h" +#include "nm-dbus-vpn.h" + + +struct NMVPNActRequest +{ + guint refcount; + NMVPNActStage stage; + + NMDevice * parent_dev; + NMVPNManager * manager; + NMVPNService * service; + NMVPNConnection * vpn; + + char ** password_items; + int password_count; + char ** data_items; + int data_count; + + guint daemon_wait_count; + guint callback_id; + gboolean canceled; +}; + + +/* Ugly, I know. But we need it for now */ +DBusConnection *nm_vpn_service_get_dbus_connection (NMVPNService *service); + + +NMVPNActRequest *nm_vpn_act_request_new (NMVPNManager *manager, NMVPNService *service, NMVPNConnection *vpn, + NMDevice *parent_dev, char **password_items, int password_count, char **data_items, int data_count) +{ + NMVPNActRequest *req; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (service != NULL, NULL); + g_return_val_if_fail (vpn != NULL, NULL); + g_return_val_if_fail (parent_dev != NULL, NULL); + g_return_val_if_fail (password_items != NULL, NULL); + g_return_val_if_fail (data_items != NULL, NULL); + + req = g_malloc0 (sizeof (NMVPNActRequest)); + req->refcount = 1; + req->stage = NM_VPN_ACT_STAGE_PREPARE; + + req->manager = manager; + nm_device_ref (parent_dev); + req->parent_dev = parent_dev; + nm_vpn_service_ref (service); + req->service = service; + nm_vpn_connection_ref (vpn); + req->vpn = vpn; + + req->password_items = g_strdupv (password_items); + req->password_count = password_count; + req->data_items = g_strdupv (data_items); + req->data_count = data_count; + + return req; +} + + +void nm_vpn_act_request_ref (NMVPNActRequest *req) +{ + g_return_if_fail (req != NULL); + + req->refcount++; +} + + +void nm_vpn_act_request_unref (NMVPNActRequest *req) +{ + g_return_if_fail (req != NULL); + + req->refcount--; + if (req->refcount == 0) + { + nm_device_unref (req->parent_dev); + nm_vpn_service_unref (req->service); + nm_vpn_connection_unref (req->vpn); + + g_strfreev (req->password_items); + g_strfreev (req->data_items); + + memset (req, 0, sizeof (NMVPNActRequest)); + g_free (req); + } +} + +gboolean nm_vpn_act_request_is_activating (NMVPNActRequest *req) +{ + gboolean activating = FALSE; + + g_return_val_if_fail (req != NULL, FALSE); + + switch (req->stage) + { + case NM_VPN_ACT_STAGE_PREPARE: + case NM_VPN_ACT_STAGE_CONNECT: + case NM_VPN_ACT_STAGE_IP_CONFIG_GET: + activating = TRUE; + break; + + default: + break; + } + + return activating; +} + +gboolean nm_vpn_act_request_is_activated (NMVPNActRequest *req) +{ + gboolean activated = FALSE; + + g_return_val_if_fail (req != NULL, FALSE); + + switch (req->stage) + { + case NM_VPN_ACT_STAGE_ACTIVATED: + activated = TRUE; + break; + + default: + break; + } + + return activated; +} + +NMVPNManager *nm_vpn_act_request_get_manager (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + + return req->manager; +} + +NMVPNService * nm_vpn_act_request_get_service (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + + return req->service; +} + + +NMVPNConnection * nm_vpn_act_request_get_connection (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + + return req->vpn; +} + +NMDevice *nm_vpn_act_request_get_parent_dev (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + + return req->parent_dev; +} + +const char ** nm_vpn_act_request_get_password_items (NMVPNActRequest *req, guint *count) +{ + g_return_val_if_fail (req != NULL, NULL); + g_return_val_if_fail (count != NULL, NULL); + + *count = req->password_count; + return (const char **) (req->password_items); +} + +const char ** nm_vpn_act_request_get_data_items (NMVPNActRequest *req, guint *count) +{ + g_return_val_if_fail (req != NULL, NULL); + g_return_val_if_fail (count != NULL, NULL); + + *count = req->data_count; + return (const char **) (req->data_items); +} + +void nm_vpn_act_request_cancel (NMVPNActRequest *req) +{ + g_return_if_fail (req != NULL); + + req->canceled = TRUE; +} + +gboolean nm_vpn_act_request_should_cancel (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, FALSE); + + return req->canceled; +} + +NMVPNActStage nm_vpn_act_request_get_stage (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, NM_VPN_ACT_STAGE_UNKNOWN); + + return req->stage; +} + +void nm_vpn_act_request_set_stage (NMVPNActRequest *req, NMVPNActStage stage) +{ + NMVPNActStage old_stage; + + g_return_if_fail (req != NULL); + + old_stage = req->stage; + if (old_stage != stage) + { + DBusConnection *dbus_connection = nm_vpn_service_get_dbus_connection (req->service); + + req->stage = stage; + nm_dbus_vpn_signal_vpn_connection_state_change (dbus_connection, req->vpn, req->stage); + } +} + +guint nm_vpn_act_request_get_daemon_wait_count (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, 0); + + return req->daemon_wait_count; +} + +void nm_vpn_act_request_set_daemon_wait_count (NMVPNActRequest *req, guint count) +{ + g_return_if_fail (req != NULL); + + req->daemon_wait_count = count; +} + +guint nm_vpn_act_request_get_callback_id (NMVPNActRequest *req) +{ + g_return_val_if_fail (req != NULL, 0); + + return req->callback_id; +} + +void nm_vpn_act_request_set_callback_id (NMVPNActRequest *req, guint id) +{ + g_return_if_fail (req != NULL); + + req->callback_id = id; +} + diff --git a/src/vpn-manager/nm-vpn-act-request.h b/src/vpn-manager/nm-vpn-act-request.h new file mode 100644 index 0000000000..302c850d32 --- /dev/null +++ b/src/vpn-manager/nm-vpn-act-request.h @@ -0,0 +1,59 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + */ + +#ifndef NM_VPN_ACT_REQUEST_H +#define NM_VPN_ACT_REQUEST_H + +#include +#include "NetworkManager.h" +#include "nm-vpn-service.h" +#include "nm-vpn-connection.h" + + +NMVPNActRequest * nm_vpn_act_request_new (NMVPNManager *manager, NMVPNService *service, NMVPNConnection *vpn, + NMDevice *parent_dev, char **password_items, int password_count, char **data_items, int data_count); +void nm_vpn_act_request_ref (NMVPNActRequest *req); +void nm_vpn_act_request_unref (NMVPNActRequest *req); + +gboolean nm_vpn_act_request_is_activating (NMVPNActRequest *req); +gboolean nm_vpn_act_request_is_activated (NMVPNActRequest *req); + +NMVPNManager * nm_vpn_act_request_get_manager (NMVPNActRequest *req); +NMVPNService * nm_vpn_act_request_get_service (NMVPNActRequest *req); +NMVPNConnection * nm_vpn_act_request_get_connection (NMVPNActRequest *req); +NMDevice * nm_vpn_act_request_get_parent_dev (NMVPNActRequest *req); + +const char ** nm_vpn_act_request_get_password_items (NMVPNActRequest *req, guint *count); +const char ** nm_vpn_act_request_get_data_items (NMVPNActRequest *req, guint *count); + +void nm_vpn_act_request_cancel (NMVPNActRequest *req); +gboolean nm_vpn_act_request_should_cancel (NMVPNActRequest *req); + +NMVPNActStage nm_vpn_act_request_get_stage (NMVPNActRequest *req); +void nm_vpn_act_request_set_stage (NMVPNActRequest *req, NMVPNActStage stage); + +guint nm_vpn_act_request_get_daemon_wait_count (NMVPNActRequest *req); +void nm_vpn_act_request_set_daemon_wait_count (NMVPNActRequest *req, guint count); + +guint nm_vpn_act_request_get_callback_id (NMVPNActRequest *req); +void nm_vpn_act_request_set_callback_id (NMVPNActRequest *req, guint timeout); + +#endif diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 223fd3c3c3..f6cee76df2 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -22,34 +22,56 @@ #include #include #include "nm-vpn-connection.h" +#include "nm-dbus-vpn.h" +#include "NetworkManagerSystem.h" struct NMVPNConnection { - int refcount; - char *name; - char *user_name; - NMVPNService *service; + int refcount; + + /* Won't change over life of object */ + char * name; + char * user_name; + char * service_name; + + NMNamedManager *named_manager; + DBusConnection *dbus_connection; + + /* Change when connection is activated/deactivated */ + NMDevice * parent_dev; + NMIP4Config * ip4_config; + char * vpn_iface; }; -NMVPNConnection *nm_vpn_connection_new (const char *name, const char *user_name, NMVPNService *service) +static void nm_vpn_connection_set_vpn_iface (NMVPNConnection *con, const char *vpn_iface); +static void nm_vpn_connection_set_ip4_config (NMVPNConnection *con, NMIP4Config *ip4_config); +static void nm_vpn_connection_set_parent_device(NMVPNConnection *con, NMDevice *parent_dev); + + +NMVPNConnection *nm_vpn_connection_new (const char *name, const char *user_name, const char *service_name, + NMNamedManager *named_manager, DBusConnection *dbus_connection) { NMVPNConnection *connection; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (user_name != NULL, NULL); - g_return_val_if_fail (service != NULL, NULL); - + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (named_manager != NULL, NULL); + g_return_val_if_fail (dbus_connection != NULL, NULL); connection = g_malloc0 (sizeof (NMVPNConnection)); connection->refcount = 1; connection->name = g_strdup (name); connection->user_name = g_strdup (user_name); + connection->service_name = g_strdup (service_name); - nm_vpn_service_ref (service); - connection->service = service; + g_object_ref (named_manager); + connection->named_manager = named_manager; + + connection->dbus_connection = dbus_connection; return connection; } @@ -71,13 +93,84 @@ void nm_vpn_connection_unref (NMVPNConnection *connection) { g_free (connection->name); g_free (connection->user_name); - nm_vpn_service_unref (connection->service); + g_free (connection->service_name); + + if (connection->parent_dev) + nm_device_unref (connection->parent_dev); + if (connection->ip4_config) + nm_ip4_config_unref (connection->ip4_config); + g_free (connection->vpn_iface); + + g_object_unref (connection->named_manager); memset (connection, 0, sizeof (NMVPNConnection)); g_free (connection); } } + +void nm_vpn_connection_activate (NMVPNConnection *connection) +{ + g_return_if_fail (connection != NULL); + + /* Nothing done here yet */ +} + + +gboolean nm_vpn_connection_set_config (NMVPNConnection *connection, const char *vpn_iface, NMDevice *dev, NMIP4Config *ip4_config) +{ + gboolean success = FALSE; + int num_routes = -1; + char ** routes; + + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (vpn_iface != NULL, FALSE); + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (ip4_config != NULL, FALSE); + + nm_vpn_connection_set_vpn_iface (connection, vpn_iface); + nm_vpn_connection_set_parent_device (connection, dev); + nm_vpn_connection_set_ip4_config (connection, ip4_config); + + routes = nm_dbus_vpn_get_routes (connection->dbus_connection, connection, &num_routes); + nm_system_vpn_device_set_from_ip4_config (connection->named_manager, connection->parent_dev, + connection->vpn_iface, connection->ip4_config, routes, num_routes); + g_strfreev(routes); + success = TRUE; + + return success; +} + + +void nm_vpn_connection_deactivate (NMVPNConnection *connection) +{ + g_return_if_fail (connection != NULL); + + if (connection->ip4_config) + { + nm_system_remove_ip4_config_nameservers (connection->named_manager, connection->ip4_config); + nm_system_remove_ip4_config_search_domains (connection->named_manager, connection->ip4_config); + } + + if (connection->vpn_iface) + { + nm_system_device_set_up_down_with_iface (NULL, connection->vpn_iface, FALSE); + nm_system_device_flush_routes_with_iface (connection->vpn_iface); + nm_system_device_flush_addresses_with_iface (connection->vpn_iface); + } + + if (connection->ip4_config) + { + /* Reset routes, nameservers, and domains of the currently active device */ + nm_system_device_set_from_ip4_config (connection->parent_dev); + } + + nm_vpn_connection_set_ip4_config (connection, NULL); + nm_vpn_connection_set_vpn_iface (connection, NULL); + nm_vpn_connection_set_parent_device (connection, NULL); +} + + const char *nm_vpn_connection_get_name (NMVPNConnection *connection) { g_return_val_if_fail (connection != NULL, NULL); @@ -92,10 +185,58 @@ const char *nm_vpn_connection_get_user_name (NMVPNConnection *connection) return connection->user_name; } -NMVPNService *nm_vpn_connection_get_service (NMVPNConnection *connection) +const char *nm_vpn_connection_get_service_name (NMVPNConnection *connection) { g_return_val_if_fail (connection != NULL, NULL); - return connection->service; + return connection->service_name; } + +static void nm_vpn_connection_set_vpn_iface (NMVPNConnection *con, const char *vpn_iface) +{ + g_return_if_fail (con != NULL); + + if (con->vpn_iface) + { + g_free (con->vpn_iface); + con->vpn_iface = NULL; + } + + if (vpn_iface) + con->vpn_iface = g_strdup (vpn_iface); +} + +static void nm_vpn_connection_set_ip4_config (NMVPNConnection *con, NMIP4Config *ip4_config) +{ + g_return_if_fail (con != NULL); + + if (con->ip4_config) + { + nm_ip4_config_unref (con->ip4_config); + con->ip4_config = NULL; + } + + if (ip4_config) + { + nm_ip4_config_ref (ip4_config); + con->ip4_config = ip4_config; + } +} + +static void nm_vpn_connection_set_parent_device (NMVPNConnection *con, NMDevice *parent_dev) +{ + g_return_if_fail (con != NULL); + + if (con->parent_dev) + { + nm_device_unref (con->parent_dev); + con->parent_dev = NULL; + } + + if (parent_dev) + { + nm_device_ref (parent_dev); + con->parent_dev = parent_dev; + } +} diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index 7109c15595..bc9b36854d 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -20,17 +20,23 @@ #ifndef NM_VPN_CONNECTION_H #define NM_VPN_CONNECTION_H -#include "nm-vpn-service.h" +#include "NetworkManagerDevice.h" typedef struct NMVPNConnection NMVPNConnection; -NMVPNConnection *nm_vpn_connection_new (const char *name, const char *user_name, NMVPNService *service); -void nm_vpn_connection_ref (NMVPNConnection *connection); -void nm_vpn_connection_unref (NMVPNConnection *connection); +NMVPNConnection * nm_vpn_connection_new (const char *name, const char *user_name, const char *service_name, + NMNamedManager *named_manager, DBusConnection *dbus_connection); +void nm_vpn_connection_ref (NMVPNConnection *con); +void nm_vpn_connection_unref (NMVPNConnection *con); -const char * nm_vpn_connection_get_name (NMVPNConnection *connection); -const char * nm_vpn_connection_get_user_name (NMVPNConnection *connection); -NMVPNService * nm_vpn_connection_get_service (NMVPNConnection *connection); +const char * nm_vpn_connection_get_name (NMVPNConnection *con); +const char * nm_vpn_connection_get_user_name (NMVPNConnection *con); +const char * nm_vpn_connection_get_service_name (NMVPNConnection *con); + +void nm_vpn_connection_activate (NMVPNConnection *con); +void nm_vpn_connection_deactivate (NMVPNConnection *con); + +gboolean nm_vpn_connection_set_config (NMVPNConnection *con, const char *vpn_iface, NMDevice *dev, NMIP4Config *ip4_config); #endif /* NM_VPN_MANAGER_H */ diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index c93222ba0c..7866c530bf 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -20,20 +20,16 @@ #include #include -#include -#include -#include -#include #include #include "nm-vpn-manager.h" #include "NetworkManager.h" #include "NetworkManagerMain.h" #include "NetworkManagerDbus.h" #include "NetworkManagerSystem.h" +#include "nm-vpn-act-request.h" #include "nm-vpn-connection.h" #include "nm-vpn-service.h" #include "nm-dbus-vpn.h" -#include "nm-activation-request.h" #include "nm-utils.h" #define VPN_SERVICE_FILE_PATH SYSCONFDIR"/NetworkManager/VPN" @@ -41,15 +37,13 @@ struct NMVPNManager { NMData * app_data; - GSList * services; + GHashTable * service_table; GSList * connections; - NMVPNConnection * active; - char * active_device; - NMIP4Config * active_config; + + NMVPNActRequest * act_req; }; -static GSList * nm_vpn_manager_load_services (void); -static void nm_vpn_manager_set_active_vpn_connection (NMVPNManager *manager, NMVPNConnection *con); +static void nm_vpn_manager_load_services (NMVPNManager *manager, GHashTable *table); /* * nm_vpn_manager_new @@ -59,14 +53,16 @@ static void nm_vpn_manager_set_active_vpn_connection (NMVPNManager *manager, NM */ NMVPNManager *nm_vpn_manager_new (NMData *app_data) { - NMVPNManager *manager; + NMVPNManager * manager; g_return_val_if_fail (app_data != NULL, NULL); manager = g_malloc0 (sizeof (NMVPNManager)); - manager->services = nm_vpn_manager_load_services (); manager->app_data = app_data; + manager->service_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) nm_vpn_service_unref); + nm_vpn_manager_load_services (manager, manager->service_table); + return manager; } @@ -81,73 +77,19 @@ void nm_vpn_manager_dispose (NMVPNManager *manager) { g_return_if_fail (manager != NULL); - nm_vpn_manager_set_active_vpn_connection (manager, NULL); - if (manager->active_device) - g_free (manager->active_device); - - if (manager->active_config) - { - nm_system_remove_ip4_config_nameservers (manager->app_data->named_manager, manager->active_config); - nm_system_remove_ip4_config_search_domains (manager->app_data->named_manager, manager->active_config); - nm_ip4_config_unref (manager->active_config); - } + if (manager->act_req) + nm_vpn_manager_deactivate_vpn_connection (manager); g_slist_foreach (manager->connections, (GFunc) nm_vpn_connection_unref, NULL); g_slist_free (manager->connections); - g_slist_foreach (manager->services, (GFunc) nm_vpn_service_unref, NULL); - g_slist_free (manager->services); + g_hash_table_destroy (manager->service_table); memset (manager, 0, sizeof (NMVPNManager)); g_free (manager); } -/* - * nm_vpn_manager_clear_connections - * - * Dispose of all the VPN connections the manager knows about. - * - */ -void nm_vpn_manager_clear_connections (NMVPNManager *manager) -{ - g_return_if_fail (manager != NULL); - - g_slist_foreach (manager->connections, (GFunc) nm_vpn_connection_unref, NULL); - g_slist_free (manager->connections); - manager->connections = NULL; -} - - -/* - * find_vpn_service - * - * Return the VPN Service for a given vpn service name. - * - */ -static NMVPNService *find_service_by_name (NMVPNManager *manager, const char *service_name) -{ - NMVPNService *service = NULL; - GSList *elt; - - g_return_val_if_fail (manager != NULL, NULL); - g_return_val_if_fail (service_name != NULL, NULL); - - for (elt = manager->services; elt; elt = g_slist_next (elt)) - { - if ((service = (NMVPNService *)(elt->data))) - { - const char *search_name = nm_vpn_service_get_service_name (service); - if (search_name && (strcmp (service_name, search_name) == 0)) - break; - } - service = NULL; - } - - return service; -} - - /* * nm_vpn_manager_find_connection_by_name * @@ -177,77 +119,34 @@ NMVPNConnection *nm_vpn_manager_find_connection_by_name (NMVPNManager *manager, } +NMVPNService *nm_vpn_manager_find_service_by_name (NMVPNManager *manager, const char *service_name) +{ + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (service_name != NULL, NULL); + + return (NMVPNService *) g_hash_table_lookup (manager->service_table, service_name); +} + + /* - * nm_vpn_manager_set_active_vpn_connection + * nm_vpn_manager_vpn_connection_list_copy * - * Sets the active connection and adds a dbus signal filter for that - * connection's service name. + * Make a shallow copy of the VPN connection list, should + * only be used by nm-dbus-vpn.c * */ -static void nm_vpn_manager_set_active_vpn_connection (NMVPNManager *manager, NMVPNConnection *con) +GSList *nm_vpn_manager_vpn_connection_list_copy (NMVPNManager *manager) { - char *match_string = NULL; - const char *service_name = NULL; - NMVPNConnection *active; - NMVPNService *service; + GSList * list; + GSList * elt; - g_return_if_fail (manager != NULL); + g_return_val_if_fail (manager != NULL, NULL); - if ((active = nm_vpn_manager_get_active_vpn_connection (manager))) - { - service = nm_vpn_connection_get_service (active); - if (service && (service_name = nm_vpn_service_get_service_name (service))) - { - /* Remove any previous watch on this VPN connection's service name */ - match_string = g_strdup_printf ("type='signal'," - "interface='%s'," - "sender='%s'", service_name, service_name); - dbus_bus_remove_match (manager->app_data->dbus_connection, match_string, NULL); - g_free (match_string); - } - nm_vpn_connection_unref (active); - } - manager->active = NULL; + list = g_slist_copy (manager->connections); + for (elt = list; elt; elt = g_slist_next (elt)) + nm_vpn_connection_ref (elt->data); - if (manager->active_config) - { - nm_system_remove_ip4_config_nameservers (manager->app_data->named_manager, manager->active_config); - nm_system_remove_ip4_config_search_domains (manager->app_data->named_manager, manager->active_config); - nm_ip4_config_unref (manager->active_config); - manager->active_config = NULL; - } - - if (manager->active_device) - { - nm_system_device_set_up_down_with_iface (NULL, manager->active_device, FALSE); - nm_system_device_flush_routes_with_iface (manager->active_device); - nm_system_device_flush_addresses_with_iface (manager->active_device); - g_free (manager->active_device); - manager->active_device = NULL; - } - - /* If passed NULL (clear active connection) there's nothing more to do */ - if (!con) - return; - - service = nm_vpn_connection_get_service (con); - if (!service || !(service_name = nm_vpn_service_get_service_name (service))) - { - nm_warning ("VPN connection could not be set active because it didn't have a VPN service."); - return; - } - - nm_vpn_connection_ref (con); - manager->active = con; - - /* Add a dbus filter for this connection's service name so its signals - * get delivered to us. - */ - match_string = g_strdup_printf ("type='signal'," - "interface='%s'," - "sender='%s'", service_name, service_name); - dbus_bus_add_match (manager->app_data->dbus_connection, match_string, NULL); - g_free (match_string); + return list; } @@ -259,8 +158,8 @@ static void nm_vpn_manager_set_active_vpn_connection (NMVPNManager *manager, NMV */ NMVPNConnection *nm_vpn_manager_add_connection (NMVPNManager *manager, const char *name, const char *service_name, const char *user_name) { - NMVPNConnection *connection = NULL; - NMVPNService *service; + NMVPNConnection * connection = NULL; + NMVPNService * service; g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); @@ -268,8 +167,11 @@ NMVPNConnection *nm_vpn_manager_add_connection (NMVPNManager *manager, const cha g_return_val_if_fail (user_name != NULL, NULL); /* Verify that the service name we are adding is in our allowed list */ - service = find_service_by_name (manager, service_name); - if (service && (connection = nm_vpn_connection_new (name, user_name, service))) + if (!(service = nm_vpn_manager_find_service_by_name (manager, service_name))) + return NULL; + + if ((connection = nm_vpn_connection_new (name, user_name, service_name, manager->app_data->named_manager, + manager->app_data->dbus_connection))) { GSList *elt; @@ -305,143 +207,24 @@ void nm_vpn_manager_remove_connection (NMVPNManager *manager, NMVPNConnection *v g_return_if_fail (manager != NULL); g_return_if_fail (vpn != NULL); + /* If this VPN is currently active, kill it */ + if (manager->act_req && (nm_vpn_act_request_get_connection (manager->act_req) == vpn)) + { + NMVPNService * service = nm_vpn_act_request_get_service (manager->act_req); + NMVPNConnection * vpn = nm_vpn_act_request_get_connection (manager->act_req); + + nm_vpn_connection_deactivate (vpn); + nm_vpn_service_stop_connection (service, manager->act_req); + + nm_vpn_act_request_unref (manager->act_req); + manager->act_req = NULL; + } + manager->connections = g_slist_remove (manager->connections, vpn); nm_vpn_connection_unref (vpn); } -/* - * Prints config returned from vpnc-helper - */ -static void print_vpn_config (guint32 ip4_vpn_gateway, - const char *tundev, - guint32 ip4_internal_address, - gint32 ip4_internal_netmask, - guint32 *ip4_internal_dns, - guint32 ip4_internal_dns_len, - guint32 *ip4_internal_nbns, - guint32 ip4_internal_nbns_len, - const char *dns_domain, - const char *login_banner) -{ - struct in_addr temp_addr; - guint32 i; - - temp_addr.s_addr = ip4_vpn_gateway; - nm_info ("VPN Gateway: %s", inet_ntoa (temp_addr)); - nm_info ("Tunnel Device: %s", tundev); - temp_addr.s_addr = ip4_internal_address; - nm_info ("Internal IP4 Address: %s", inet_ntoa (temp_addr)); - temp_addr.s_addr = ip4_internal_netmask; - nm_info ("Internal IP4 Netmask: %s", inet_ntoa (temp_addr)); - - for (i = 0; i < ip4_internal_dns_len; i++) - { - if (ip4_internal_dns[i] != 0) - { - temp_addr.s_addr = ip4_internal_dns[i]; - nm_info ("Internal IP4 DNS: %s", inet_ntoa (temp_addr)); - } - } - - for (i = 0; i < ip4_internal_nbns_len; i++) - { - if (ip4_internal_nbns[i] != 0) - { - temp_addr.s_addr = ip4_internal_nbns[i]; - nm_info ("Internal IP4 NBNS: %s", inet_ntoa (temp_addr)); - } - } - - nm_info ("DNS Domain: '%s'", dns_domain); - nm_info ("Login Banner:"); - nm_info ("-----------------------------------------"); - nm_info ("%s", login_banner); - nm_info ("-----------------------------------------"); -} - -/* - * nm_vpn_manager_handle_ip4_config_signal - * - * Configure a device with IPv4 config info in response the the VPN daemon. - * - */ -void nm_vpn_manager_handle_ip4_config_signal (NMVPNManager *manager, DBusMessage *message, NMVPNService *service, NMVPNConnection *con) -{ - guint32 ip4_vpn_gateway; - char * tundev; - guint32 ip4_internal_address; - guint32 ip4_internal_netmask; - guint32 * ip4_internal_dns; - guint32 ip4_internal_dns_len; - guint32 * ip4_internal_nbns; - guint32 ip4_internal_nbns_len; - char * dns_domain; - char * login_banner; - - g_return_if_fail (manager != NULL); - g_return_if_fail (message != NULL); - g_return_if_fail (service != NULL); - g_return_if_fail (con != NULL); - - if (dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ip4_vpn_gateway, - DBUS_TYPE_STRING, &tundev, - DBUS_TYPE_UINT32, &ip4_internal_address, - DBUS_TYPE_UINT32, &ip4_internal_netmask, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_dns, &ip4_internal_dns_len, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_nbns, &ip4_internal_nbns_len, - DBUS_TYPE_STRING, &dns_domain, - DBUS_TYPE_STRING, &login_banner, DBUS_TYPE_INVALID)) - { - NMIP4Config * config; - NMDevice * vpn_dev; - guint32 i; - -#if 0 - print_vpn_config (ip4_vpn_gateway, tundev, ip4_internal_address, ip4_internal_netmask, - ip4_internal_dns, ip4_internal_dns_len, ip4_internal_nbns, ip4_internal_nbns_len, - dns_domain, login_banner); -#endif - - config = nm_ip4_config_new (); - - nm_ip4_config_set_address (config, ip4_internal_address); - - if (ip4_internal_netmask) - nm_ip4_config_set_netmask (config, ip4_internal_netmask); - else - nm_ip4_config_set_netmask (config, 0x00FF); /* Class C */ - - nm_ip4_config_set_gateway (config, ip4_vpn_gateway); - - if (strlen (dns_domain)) - nm_ip4_config_add_domain (config, dns_domain); - - for (i = 0; i < ip4_internal_dns_len; i++) - { - if (ip4_internal_dns[i] != 0) - nm_ip4_config_add_nameserver (config, ip4_internal_dns[i]); - } - - manager->active_device = g_strdup (tundev); - manager->active_config = config; - vpn_dev = nm_get_active_device (manager->app_data); - if (vpn_dev) - { - int num_routes = -1; - char **routes = nm_dbus_vpn_get_routes (manager->app_data->dbus_connection, con, &num_routes); - - nm_system_vpn_device_set_from_ip4_config (manager->app_data->named_manager, vpn_dev, - manager->active_device, manager->active_config, - routes, num_routes); - if (login_banner && strlen (login_banner)) - nm_dbus_vpn_signal_vpn_login_banner (manager->app_data->dbus_connection, con, login_banner); - g_strfreev(routes); - } - } -} - - /* * nm_vpn_manager_get_connection_names * @@ -470,50 +253,25 @@ char **nm_vpn_manager_get_connection_names (NMVPNManager *manager) /* - * nm_vpn_manager_get_active_vpn_connection + * nm_vpn_manager_get_vpn_act_request * - * Return the active VPN connection, if any. + * Return the VPN activation request, if any. * */ -NMVPNConnection *nm_vpn_manager_get_active_vpn_connection (NMVPNManager *manager) +NMVPNActRequest *nm_vpn_manager_get_vpn_act_request (NMVPNManager *manager) { g_return_val_if_fail (manager != NULL, NULL); - return manager->active; + return manager->act_req; } -/* - * construct_op_from_service_name - * - * Construct an object path from a dbus service name by replacing - * all "." in the service with "/" and prepending a "/" to the - * object path. - * - */ -static char *construct_op_from_service_name (const char *service_name) +static inline gboolean same_service_name (NMVPNService *service, NMVPNConnection *vpn) { - char **split = NULL; - char *temp1; - char *temp2; + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (vpn != NULL, FALSE); - g_return_val_if_fail (service_name != NULL, NULL); - - if (!(split = g_strsplit (service_name, ".", 0))) - return NULL; - - temp1 = g_strjoinv ("/", split); - g_strfreev (split); - temp2 = g_strdup_printf ("/%s", temp1); - g_free (temp1); - - if (!temp2 || !strlen (temp2)) - { - g_free (temp2); - temp2 = NULL; - } - - return temp2; + return (!strcmp (nm_vpn_service_get_service_name (service), nm_vpn_connection_get_service_name (vpn))); } @@ -526,72 +284,21 @@ static char *construct_op_from_service_name (const char *service_name) */ gboolean nm_vpn_manager_process_signal (NMVPNManager *manager, DBusMessage *message) { - const char * object_path; - const char * member; - const char * temp_op; - NMVPNConnection * active; - NMVPNService * service; const char * service_name; + NMVPNService * service; + gboolean handled = FALSE; g_return_val_if_fail (manager != NULL, FALSE); g_return_val_if_fail (message != NULL, FALSE); - if (!(object_path = dbus_message_get_path (message))) - return FALSE; - - if (!(member = dbus_message_get_member (message))) - return FALSE; - - if (!(active = nm_vpn_manager_get_active_vpn_connection (manager))) - return FALSE; - - service = nm_vpn_connection_get_service (active); - if (!service || !(service_name = nm_vpn_service_get_service_name (service))) - return FALSE; - - temp_op = construct_op_from_service_name (service_name); - if (!temp_op || (strcmp (object_path, temp_op) != 0)) - return FALSE; - - if ( dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_LOGIN_FAILED) - || dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_LAUNCH_FAILED) - || dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_CONNECT_FAILED) - || dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_VPN_CONFIG_BAD) - || dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_IP_CONFIG_BAD)) + service_name = dbus_message_get_interface (message); + if ((service = nm_vpn_manager_find_service_by_name (manager, service_name))) { - char *error_msg; - - if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) - error_msg = (char *) ""; - nm_warning ("VPN failed for service '%s', signal '%s', with message '%s'.", service_name, member, error_msg); - nm_dbus_vpn_signal_vpn_failed (manager->app_data->dbus_connection, member, active, error_msg); + nm_vpn_service_process_signal (service, manager->act_req, message); + handled = TRUE; } - else if (dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_STATE_CHANGE)) - { - dbus_uint32_t old_state_int; - dbus_uint32_t new_state_int; - if (dbus_message_get_args (message, NULL, DBUS_TYPE_UINT32, &old_state_int, DBUS_TYPE_UINT32, &new_state_int, DBUS_TYPE_INVALID)) - { - NMVPNState old_state = (NMVPNState) old_state_int; - NMVPNState new_state = (NMVPNState) new_state_int; - - nm_info ("VPN service '%s' signaled new state %d, old state %d.", service_name, new_state, old_state); - nm_vpn_service_set_state (service, new_state); - nm_dbus_vpn_signal_vpn_connection_state_change (manager->app_data->dbus_connection, active); - - /* If the VPN daemon state is now stopped and it was starting, clear the active connection */ - if (((new_state == NM_VPN_STATE_STOPPED) || (new_state == NM_VPN_STATE_SHUTDOWN) || (new_state == NM_VPN_STATE_STOPPING)) - && ((old_state == NM_VPN_STATE_STARTED) || (old_state == NM_VPN_STATE_STARTING))) - { - nm_vpn_manager_set_active_vpn_connection (manager, NULL); - } - } - } - else if (dbus_message_is_signal (message, service_name, NM_DBUS_VPN_SIGNAL_IP4_CONFIG)) - nm_vpn_manager_handle_ip4_config_signal (manager, message, service, active); - - return TRUE; + return handled; } @@ -603,44 +310,20 @@ gboolean nm_vpn_manager_process_signal (NMVPNManager *manager, DBusMessage *mess */ gboolean nm_vpn_manager_process_name_owner_changed (NMVPNManager *manager, const char *changed_service_name, const char *old_owner, const char *new_owner) { - NMVPNService *service; - NMVPNConnection *active; - gboolean old_owner_good = (old_owner && strlen (old_owner)); - gboolean new_owner_good = (new_owner && strlen (new_owner)); + NMVPNConnection * active; + NMVPNService * service; + gboolean handled = FALSE; g_return_val_if_fail (manager != NULL, FALSE); g_return_val_if_fail (changed_service_name != NULL, FALSE); - if (!(active = nm_vpn_manager_get_active_vpn_connection (manager))) - return FALSE; - nm_vpn_connection_ref (active); - - if (!(service = nm_vpn_connection_get_service (active))) + if ((service = nm_vpn_manager_find_service_by_name (manager, changed_service_name))) { - nm_vpn_connection_unref (active); - return FALSE; + nm_vpn_service_name_owner_changed (service, manager->act_req, old_owner, new_owner); + handled = TRUE; } - /* Can't handle the signal if its not from our active VPN service */ - if (strcmp (nm_vpn_service_get_service_name (service), changed_service_name) != 0) - { - nm_vpn_connection_unref (active); - return FALSE; - } - - if (!old_owner_good && new_owner_good) - { - /* VPN service got created. */ - } - else if (old_owner_good && !new_owner_good) - { - /* VPN service went away. */ - nm_vpn_service_set_state (service, NM_VPN_STATE_SHUTDOWN); - nm_dbus_vpn_signal_vpn_connection_state_change (manager->app_data->dbus_connection, active); - } - - nm_vpn_connection_unref (active); - return TRUE; + return handled; } @@ -651,76 +334,36 @@ gboolean nm_vpn_manager_process_name_owner_changed (NMVPNManager *manager, const * launching that daemon if necessary. * */ -void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, char **password_items, int password_count, char **data_items, int count) +void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, + char **password_items, int password_count, char **data_items, int data_count) { - DBusMessage *message; - DBusMessage *reply; - char *op; - NMVPNService *service; - const char *service_name; - const char *name; - const char *user_name; - DBusError error; + NMDevice * parent_dev; + NMVPNActRequest * req; + NMVPNService * service; + const char * service_name; g_return_if_fail (manager != NULL); - g_return_if_fail (manager->app_data != NULL); - g_return_if_fail (manager->app_data->dbus_connection != NULL); g_return_if_fail (vpn != NULL); g_return_if_fail (password_items != NULL); g_return_if_fail (data_items != NULL); - nm_vpn_manager_set_active_vpn_connection (manager, NULL); + if (manager->act_req) + nm_vpn_manager_deactivate_vpn_connection (manager); - /* Construct a new method call with the correct service and object path */ - if (!(service = nm_vpn_connection_get_service (vpn)) || !(service_name = nm_vpn_service_get_service_name (service))) + service_name = nm_vpn_connection_get_service_name (vpn); + if (!(service = nm_vpn_manager_find_service_by_name (manager, service_name))) return; - nm_vpn_manager_set_active_vpn_connection (manager, vpn); - - /* Start the daemon if its not already running */ - if (!dbus_bus_name_has_owner (manager->app_data->dbus_connection, service_name, NULL)) + if (!(parent_dev = nm_get_active_device (manager->app_data))) { - if (!nm_vpn_service_exec_daemon (service)) - { - nm_vpn_manager_set_active_vpn_connection (manager, NULL); - return; - } - } - - /* Send the activate request to the daemon */ - op = construct_op_from_service_name (service_name); - message = dbus_message_new_method_call (service_name, op, service_name, "startConnection"); - g_free (op); - if (!message) - { - nm_warning ("Couldn't allocate dbus message."); - nm_vpn_manager_set_active_vpn_connection (manager, NULL); + nm_warning ("nm_vpn_manager_activate_vpn_connection(): no currently active network device, won't activate VPN."); return; } - name = nm_vpn_connection_get_name (vpn); - user_name = nm_vpn_connection_get_user_name (vpn); + req = nm_vpn_act_request_new (manager, service, vpn, parent_dev, password_items, password_count, data_items, data_count); + manager->act_req = req; - dbus_message_append_args (message, DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &user_name, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &password_items, password_count, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data_items, count, - DBUS_TYPE_INVALID); - - /* Send the message to the daemon again, now that its running. */ - dbus_error_init (&error); - reply = dbus_connection_send_with_reply_and_block (manager->app_data->dbus_connection, message, -1, &error); - dbus_message_unref (message); - if (dbus_error_is_set (&error)) - { - nm_warning ("Could not activate the VPN service. dbus says: '%s' '%s'.", error.name, error.message); - dbus_error_free (&error); - nm_vpn_manager_set_active_vpn_connection (manager, NULL); - return; - } - - if (reply) - dbus_message_unref (reply); + nm_vpn_service_start_connection (service, req); } @@ -732,50 +375,105 @@ void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnect */ void nm_vpn_manager_deactivate_vpn_connection (NMVPNManager *manager) { - DBusMessage * message; - char * op; NMVPNService * service; - const char * service_name; - NMVPNConnection * active; - NMDevice * dev; + NMVPNConnection * vpn; g_return_if_fail (manager != NULL); - if (!(active = nm_vpn_manager_get_active_vpn_connection (manager))) + if (!manager->act_req) return; - nm_vpn_connection_ref (active); - /* Construct a new method call with the correct service and object path */ - service = nm_vpn_connection_get_service (active); - service_name = nm_vpn_service_get_service_name (service); - op = construct_op_from_service_name (service_name); - message = dbus_message_new_method_call (service_name, op, service_name, "stopConnection"); - g_free (op); - if (!message) + if (nm_vpn_act_request_is_activating (manager->act_req) || nm_vpn_act_request_is_activated (manager->act_req)) { - nm_warning ("Couldn't allocate dbus message."); - goto out; + if (nm_vpn_act_request_is_activated (manager->act_req)) + { + vpn = nm_vpn_act_request_get_connection (manager->act_req); + g_assert (vpn); + nm_vpn_connection_deactivate (vpn); + } + + service = nm_vpn_act_request_get_service (manager->act_req); + g_assert (service); + nm_vpn_service_stop_connection (service, manager->act_req); } - /* Call the specific VPN service, let dbus activate it if needed */ - dbus_connection_send (manager->app_data->dbus_connection, message, NULL); - dbus_message_unref (message); + nm_vpn_act_request_unref (manager->act_req); + manager->act_req = NULL; +} -out: - nm_vpn_connection_unref (active); - if ((dev = nm_get_active_device (manager->app_data))) - nm_system_device_set_from_ip4_config (dev); +static gboolean nm_vpn_manager_vpn_activation_failed (gpointer user_data) +{ + NMVPNActRequest * req = (NMVPNActRequest *) user_data; + NMVPNManager * manager; + + g_assert (req); + + manager = nm_vpn_act_request_get_manager (req); + g_assert (manager); + + if (manager->act_req == req) + nm_vpn_manager_deactivate_vpn_connection (manager); + + return FALSE; +} + + +void nm_vpn_manager_schedule_vpn_activation_failed (NMVPNManager *manager, NMVPNActRequest *req) +{ + GSource * source = NULL; + + g_return_if_fail (manager != NULL); + g_return_if_fail (req != NULL); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_vpn_manager_vpn_activation_failed, req, NULL); + g_source_attach (source, manager->app_data->main_context); + g_source_unref (source); +} + + +static gboolean nm_vpn_manager_vpn_connection_died (gpointer user_data) +{ + NMVPNActRequest * req = (NMVPNActRequest *) user_data; + NMVPNManager * manager; + + g_assert (req); + + manager = nm_vpn_act_request_get_manager (req); + g_assert (manager); + + if (manager->act_req == req) + nm_vpn_manager_deactivate_vpn_connection (manager); + + return FALSE; +} + + +void nm_vpn_manager_schedule_vpn_connection_died (NMVPNManager *manager, NMVPNActRequest *req) +{ + GSource * source = NULL; + + g_return_if_fail (manager != NULL); + g_return_if_fail (req != NULL); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_vpn_manager_vpn_connection_died, req, NULL); + g_source_attach (source, manager->app_data->main_context); + g_source_unref (source); } /*********************************************************************/ -static GSList *nm_vpn_manager_load_services (void) +static void nm_vpn_manager_load_services (NMVPNManager *manager, GHashTable *table) { GSList *list = NULL; GDir *vpn_dir; + g_return_if_fail (manager != NULL); + g_return_if_fail (table != NULL); + /* Load allowed service names */ if ((vpn_dir = g_dir_open (VPN_SERVICE_FILE_PATH, 0, NULL))) { @@ -793,7 +491,7 @@ static GSList *nm_vpn_manager_load_services (void) if (split_contents) { int i, len; - NMVPNService * service = nm_vpn_service_new (); + NMVPNService * service = nm_vpn_service_new (manager, manager->app_data); gboolean have_name = FALSE; gboolean have_service = FALSE; gboolean have_program = FALSE; @@ -867,7 +565,7 @@ static GSList *nm_vpn_manager_load_services (void) { nm_info ("Adding VPN service '%s' with name '%s' and program '%s'", nm_vpn_service_get_service_name (service), nm_vpn_service_get_name (service), nm_vpn_service_get_program (service)); - list = g_slist_append (list, service); + g_hash_table_insert (table, (char *) nm_vpn_service_get_service_name (service), service); } else nm_vpn_service_unref (service); @@ -879,7 +577,5 @@ static GSList *nm_vpn_manager_load_services (void) g_dir_close (vpn_dir); } - - return list; } diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h index 64fac40bb8..bed3129ffa 100644 --- a/src/vpn-manager/nm-vpn-manager.h +++ b/src/vpn-manager/nm-vpn-manager.h @@ -23,23 +23,28 @@ #include #include "NetworkManagerMain.h" #include "nm-vpn-connection.h" +#include "nm-vpn-service.h" NMVPNManager * nm_vpn_manager_new (NMData *app_data); -void nm_vpn_manager_clear_connections (NMVPNManager *manager); NMVPNConnection * nm_vpn_manager_add_connection (NMVPNManager *manager, const char *name, const char *service_name, const char *user_name); void nm_vpn_manager_remove_connection (NMVPNManager *manager, NMVPNConnection *vpn); char ** nm_vpn_manager_get_connection_names (NMVPNManager *manager); void nm_vpn_manager_dispose (NMVPNManager *manager); -NMVPNConnection * nm_vpn_manager_get_active_vpn_connection (NMVPNManager *manager); +NMVPNActRequest * nm_vpn_manager_get_vpn_act_request (NMVPNManager *manager); -void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, char **password_items, int password_count, char **data_items, int count); +void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, char **password_items, + int password_count, char **data_items, int data_count); void nm_vpn_manager_deactivate_vpn_connection (NMVPNManager *manager); NMVPNConnection * nm_vpn_manager_find_connection_by_name (NMVPNManager *manager, const char *con_name); +NMVPNService * nm_vpn_manager_find_service_by_name (NMVPNManager *manager, const char *service_name); gboolean nm_vpn_manager_process_signal (NMVPNManager *manager, DBusMessage *signal); gboolean nm_vpn_manager_process_name_owner_changed (NMVPNManager *manager, const char *service, const char *old_owner, const char *new_owner); +void nm_vpn_manager_schedule_vpn_activation_failed(NMVPNManager *manager, NMVPNActRequest *req); +void nm_vpn_manager_schedule_vpn_connection_died (NMVPNManager *manager, NMVPNActRequest *req); + #endif /* NM_VPN_MANAGER_H */ diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c index b746ada4d6..172b6a872d 100644 --- a/src/vpn-manager/nm-vpn-service.c +++ b/src/vpn-manager/nm-vpn-service.c @@ -20,28 +20,67 @@ */ #include +#include +#include +#include +#include #include +#include "NetworkManagerDbus.h" #include "nm-dbus-vpn.h" #include "nm-vpn-service.h" +#include "nm-vpn-act-request.h" #include "nm-utils.h" struct NMVPNService { - int refcount; - char *name; - char *service; - char *program; - NMVPNState state; + int refcount; + NMVPNManager * manager; + NMData * app_data; + gboolean watch_active; + + char * name; + char * service; + char * program; + NMVPNState state; }; -NMVPNService *nm_vpn_service_new (void) +static void nm_vpn_service_add_watch (NMVPNService *service); +static void nm_vpn_service_remove_watch (NMVPNService *service); +static void nm_vpn_service_stop_connection_internal (NMVPNService *service); +static void print_vpn_config (guint32 ip4_vpn_gateway, + const char *tundev, + guint32 ip4_internal_address, + gint32 ip4_internal_netmask, + guint32 *ip4_internal_dns, + guint32 ip4_internal_dns_len, + guint32 *ip4_internal_nbns, + guint32 ip4_internal_nbns_len, + const char *dns_domain, + const char *login_banner); + +static void nm_vpn_service_schedule_stage1_daemon_exec (NMVPNService *service, NMVPNActRequest *req); +static void nm_vpn_service_schedule_stage3_connect (NMVPNService *service, NMVPNActRequest *req); +static void nm_vpn_service_schedule_stage2_daemon_wait (NMVPNService *service, NMVPNActRequest *req); +static void nm_vpn_service_schedule_stage4_ip_config_get_timeout (NMVPNService *service, NMVPNActRequest *req); +static void nm_vpn_service_cancel_callback (NMVPNService *service, NMVPNActRequest *req); + + +/* + * nm_vpn_service_new + * + * Create a new VPNService object + * + */ +NMVPNService *nm_vpn_service_new (NMVPNManager *manager, NMData *app_data) { NMVPNService *service = g_malloc0 (sizeof (NMVPNService)); service->refcount = 1; service->state = NM_VPN_STATE_SHUTDOWN; + service->app_data = app_data; + service->manager = manager; return service; } @@ -103,6 +142,10 @@ void nm_vpn_service_set_service_name (NMVPNService *service, const char *name) if (service->service) g_free (service->service); service->service = g_strdup (name); + + /* If the VPN daemon is currently running, tell it to stop */ + if (!dbus_bus_name_has_owner (service->app_data->dbus_connection, service->service, NULL)) + nm_vpn_service_stop_connection_internal (service); } @@ -132,7 +175,7 @@ NMVPNState nm_vpn_service_get_state (NMVPNService *service) } -void nm_vpn_service_set_state (NMVPNService *service, const NMVPNState state) +static void nm_vpn_service_set_state (NMVPNService *service, const NMVPNState state) { g_return_if_fail (service != NULL); @@ -140,35 +183,768 @@ void nm_vpn_service_set_state (NMVPNService *service, const NMVPNState state) } -gboolean nm_vpn_service_exec_daemon (NMVPNService *service) +DBusConnection *nm_vpn_service_get_dbus_connection (NMVPNService *service) { - GPtrArray *vpn_argv; - GError *error = NULL; - GPid pid; + g_return_val_if_fail (service != NULL, NULL); - g_return_val_if_fail (service != NULL, FALSE); + return service->app_data->dbus_connection; +} - if (!nm_vpn_service_get_program (service)) - return FALSE; + +/* + * construct_op_from_service_name + * + * Construct an object path from a dbus service name by replacing + * all "." in the service with "/" and prepending a "/" to the + * object path. + * + */ +static char *construct_op_from_service_name (const char *service_name) +{ + char **split = NULL; + char *temp1; + char *temp2; + + g_return_val_if_fail (service_name != NULL, NULL); + + if (!(split = g_strsplit (service_name, ".", 0))) + return NULL; + + temp1 = g_strjoinv ("/", split); + g_strfreev (split); + temp2 = g_strdup_printf ("/%s", temp1); + g_free (temp1); + + return temp2; +} + + +/* + * nm_vpn_service_act_request_failed + * + * Clean up after an activation request and tell the VPN manager that it + * has failed. + * + */ +void nm_vpn_service_act_request_failed (NMVPNService *service, NMVPNActRequest *req) +{ + NMVPNConnection *vpn; + + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + /* Sanity checks */ + if (nm_vpn_act_request_get_service (req) != service) + return; + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_vpn_service_cancel_callback (service, req); + + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_FAILED); + nm_info ("VPN Activation (%s) failed.", nm_vpn_connection_get_name (vpn)); + + nm_vpn_act_request_unref (req); + nm_vpn_manager_schedule_vpn_activation_failed (service->manager, req); +} + + +static void nm_vpn_service_activation_success (NMVPNService *service, NMVPNActRequest *req) +{ + GSource * source = NULL; + NMVPNConnection * vpn = NULL; + + g_assert (service != NULL); + g_assert (req != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_vpn_service_cancel_callback (service, req); + + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_ACTIVATED); + nm_info ("VPN Activation (%s) successful.", nm_vpn_connection_get_name (vpn)); +} + + +/* + * nm_vpn_service_start_connection + * + * Kick off the VPN connection process. + * + */ +void nm_vpn_service_start_connection (NMVPNService *service, NMVPNActRequest *req) +{ + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_PREPARE); + nm_vpn_service_add_watch (service); + + /* Start the daemon if it's not already running */ + nm_vpn_act_request_ref (req); + if (!dbus_bus_name_has_owner (service->app_data->dbus_connection, service->service, NULL)) + nm_vpn_service_schedule_stage1_daemon_exec (service, req); + else + nm_vpn_service_schedule_stage3_connect (service, req); +} + + +/* + * nm_vpn_service_stage_1_daemon_exec + * + * Execute the VPN service daemon. + * + */ +static gboolean nm_vpn_service_stage1_daemon_exec (gpointer user_data) +{ + NMVPNActRequest * req = (NMVPNActRequest *) user_data; + NMVPNService * service; + GPtrArray * vpn_argv; + GError * error = NULL; + GPid pid; + + g_assert (req != NULL); + + service = nm_vpn_act_request_get_service (req); + g_assert (service != NULL); + g_assert (service->program != NULL); + + nm_vpn_act_request_set_callback_id (req, 0); vpn_argv = g_ptr_array_new (); - g_ptr_array_add (vpn_argv, (char *) nm_vpn_service_get_program (service)); + g_ptr_array_add (vpn_argv, service->program); g_ptr_array_add (vpn_argv, NULL); if (!g_spawn_async (NULL, (char **) vpn_argv->pdata, NULL, 0, NULL, NULL, &pid, &error)) { g_ptr_array_free (vpn_argv, TRUE); - nm_warning ("Could not activate the VPN service '%s'. error: '%s'.", nm_vpn_service_get_service_name (service), error->message); + nm_warning ("nm_vpn_service_stage1_daemon_exec(%s): could not launch the VPN service. error: '%s'.", service->service, error->message); g_error_free (error); - return FALSE; + nm_vpn_service_act_request_failed (service, req); + goto out; } g_ptr_array_free (vpn_argv, TRUE); - nm_info ("Activated the VPN service '%s' with PID %d.", nm_vpn_service_get_service_name (service), pid); + nm_info ("nm_vpn_service_stage1_daemon_exec(%s): execed the VPN service, PID is %d.", service->service, pid); - /* Wait a bit for the daemon to start up */ - /* FIXME: don't sleep, keep retrying dbus message or something */ - sleep (1); + nm_vpn_service_schedule_stage2_daemon_wait (service, req); + +out: + return FALSE; +} + + +static void nm_vpn_service_schedule_stage1_daemon_exec (NMVPNService *service, NMVPNActRequest *req) +{ + GSource * source = NULL; + NMVPNConnection * vpn = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_PREPARE); + nm_vpn_service_set_state (service, NM_VPN_STATE_SHUTDOWN); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_vpn_service_stage1_daemon_exec, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_vpn_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("VPN Activation (%s) Stage 1 (Connection Prepare) scheduled...", nm_vpn_connection_get_name (vpn)); +} + + +/* + * nm_vpn_service_stage2_daemon_wait + * + * Wait until the VPN daemon has become active. + * + */ +gboolean nm_vpn_service_stage2_daemon_wait (gpointer user_data) +{ + NMVPNActRequest * req = (NMVPNActRequest *) user_data; + NMVPNService * service; + + g_assert (req != NULL); + + service = nm_vpn_act_request_get_service (req); + g_assert (service != NULL); + + nm_vpn_act_request_set_callback_id (req, 0); + + if (service->state == NM_VPN_STATE_STOPPED) + nm_vpn_service_schedule_stage3_connect (service, req); + else if (nm_vpn_act_request_get_daemon_wait_count (req) >= 4) + { + /* We only wait 2s (4 * 500 milliseconds) for the service to start up */ + nm_vpn_service_act_request_failed (service, req); + } + else + nm_vpn_service_schedule_stage2_daemon_wait (service, req); + + return FALSE; +} + + +static void nm_vpn_service_schedule_stage2_daemon_wait (NMVPNService *service, NMVPNActRequest *req) +{ + GSource * source = NULL; + NMVPNConnection * vpn = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_PREPARE); + + nm_vpn_act_request_set_daemon_wait_count (req, nm_vpn_act_request_get_daemon_wait_count (req) + 1); + + source = g_timeout_source_new (500); + g_source_set_callback (source, (GSourceFunc) nm_vpn_service_stage2_daemon_wait, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_vpn_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("VPN Activation (%s) Stage 2 (Connection Prepare Wait) scheduled...", nm_vpn_connection_get_name (vpn)); +} + + +static void nm_vpn_service_stage3_connect_cb (DBusPendingCall *pcall, void *user_data) +{ + DBusMessage * reply; + NMVPNActRequest * req = (NMVPNActRequest *) user_data; + NMVPNService * service; + NMVPNConnection * vpn; + + g_assert (pcall != NULL); + g_assert (req != NULL); + + service = nm_vpn_act_request_get_service (req); + g_assert (service != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_info ("VPN Activation (%s) Stage 3 (Connect) reply received.", nm_vpn_connection_get_name (vpn)); + + if (!(reply = dbus_pending_call_steal_reply (pcall))) + { + nm_warning ("nm_vpn_service_stage3_connect_cb(%s): could not obtain VPN service's reply.", service->service); + nm_vpn_service_act_request_failed (service, req); + goto out; + } + + if (message_is_error (reply)) + { + const char *member = dbus_message_get_member (reply); + char *message; + + if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &message, NULL)) + message = (char *) ""; + + nm_warning ("nm_vpn_service_stage3_connect_cb(%s): could not start the VPN '%s'. dbus says: '%s' '%s'.", + service->service, nm_vpn_connection_get_name (vpn), member, message); + nm_vpn_service_act_request_failed (service, req); + } + else + { + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_IP_CONFIG_GET); + nm_vpn_service_schedule_stage4_ip_config_get_timeout (service, req); + nm_info ("VPN Activation (%s) Stage 4 (IP Config Get) reply expected soon...", nm_vpn_connection_get_name (vpn)); + } + + dbus_message_unref (reply); + +out: + dbus_pending_call_unref (pcall); +} + + +static gboolean nm_vpn_service_stage3_connect (gpointer user_data) +{ + NMVPNActRequest * req = (NMVPNActRequest *) user_data; + NMVPNService * service; + NMVPNConnection * vpn; + char * op; + const char * name; + const char * user_name; + char ** password_items; + dbus_uint32_t password_count; + char ** data_items; + dbus_uint32_t data_count; + DBusError error; + DBusMessage * message; + DBusPendingCall * pcall = NULL; + + g_assert (req != NULL); + + service = nm_vpn_act_request_get_service (req); + g_assert (service != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn != NULL); + + nm_vpn_act_request_set_callback_id (req, 0); + + /* Send the start vpn request to the daemon */ + op = construct_op_from_service_name (service->service); + message = dbus_message_new_method_call (service->service, op, service->service, "startConnection"); + g_free (op); + if (!message) + { + nm_warning ("nm_vpn_service_stage3_connect(%s): couldn't allocate dbus message.", service->service); + nm_vpn_service_act_request_failed (service, req); + return FALSE; + } + + name = nm_vpn_connection_get_name (vpn); + user_name = nm_vpn_connection_get_user_name (vpn); + password_items = (char **) nm_vpn_act_request_get_password_items (req, &password_count); + data_items = (char **) nm_vpn_act_request_get_data_items (req, &data_count); + dbus_message_append_args (message, DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &user_name, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &password_items, password_count, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data_items, data_count, + DBUS_TYPE_INVALID); + + dbus_connection_send_with_reply (service->app_data->dbus_connection, message, &pcall, -1); + if (pcall) + { + dbus_pending_call_set_notify (pcall, nm_vpn_service_stage3_connect_cb, req, NULL); + nm_info ("VPN Activation (%s) Stage 3 (Connect) reply expected soon...", nm_vpn_connection_get_name (vpn)); + } + else + nm_vpn_service_act_request_failed (service, req); + dbus_message_unref (message); + + return FALSE; +} + + +static void nm_vpn_service_schedule_stage3_connect (NMVPNService *service, NMVPNActRequest *req) +{ + GSource * source = NULL; + NMVPNConnection * vpn = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_CONNECT); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_vpn_service_stage3_connect, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_vpn_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("VPN Activation (%s) Stage 3 (Connect) scheduled...", nm_vpn_connection_get_name (vpn)); +} + + +static gboolean nm_vpn_service_stage4_ip_config_get_timeout (gpointer *user_data) +{ + NMVPNActRequest * req = (NMVPNActRequest *) user_data; + NMVPNService * service; + NMVPNConnection * vpn; + + g_assert (req != NULL); + + service = nm_vpn_act_request_get_service (req); + g_assert (service != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn != NULL); + + nm_vpn_act_request_set_callback_id (req, 0); + + /* If the activation request's state is still IP_CONFIG_GET and we're + * in this timeout, cancel activation because it's taken too long. + */ + if (nm_vpn_act_request_get_stage (req) == NM_VPN_ACT_STAGE_IP_CONFIG_GET) + { + nm_info ("VPN Activation (%s) Stage 4 (IP Config Get) timeout exceeded.", nm_vpn_connection_get_name (vpn)); + nm_vpn_service_act_request_failed (service, req); + } + + return FALSE; +} + + +static void nm_vpn_service_schedule_stage4_ip_config_get_timeout (NMVPNService *service, NMVPNActRequest *req) +{ + GSource * source = NULL; + NMVPNConnection * vpn = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_IP_CONFIG_GET); + + /* 20 second timeout waiting for IP config signal from VPN service */ + source = g_timeout_source_new (20000); + g_source_set_callback (source, (GSourceFunc) nm_vpn_service_stage4_ip_config_get_timeout, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_vpn_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("VPN Activation (%s) Stage 4 (IP Config Get) timeout scheduled...", nm_vpn_connection_get_name (vpn)); +} + + +static void nm_vpn_service_cancel_callback (NMVPNService *service, NMVPNActRequest *req) +{ + guint id; + + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + if ((id = nm_vpn_act_request_get_callback_id (req)) != 0) + { + g_source_destroy (g_main_context_find_source_by_id (service->app_data->main_context, id)); + nm_vpn_act_request_set_callback_id (req, 0); + } +} + + +/* + * nm_vpn_service_stage4_ip_config_get + * + * Configure a device with IPv4 config info in response the the VPN daemon. + * + */ +static void nm_vpn_service_stage4_ip_config_get (NMVPNService *service, NMVPNActRequest *req, DBusMessage *message) +{ + NMVPNConnection * vpn; + guint32 ip4_vpn_gateway; + char * tundev; + guint32 ip4_internal_address; + guint32 ip4_internal_netmask; + guint32 * ip4_internal_dns; + guint32 ip4_internal_dns_len; + guint32 * ip4_internal_nbns; + guint32 ip4_internal_nbns_len; + char * dns_domain; + char * login_banner; + gboolean success = FALSE; + + g_return_if_fail (service != NULL); + g_return_if_fail (message != NULL); + g_return_if_fail (req != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_info ("VPN Activation (%s) Stage 4 (IP Config Get) reply received.", nm_vpn_connection_get_name (vpn)); + + if (dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ip4_vpn_gateway, + DBUS_TYPE_STRING, &tundev, + DBUS_TYPE_UINT32, &ip4_internal_address, + DBUS_TYPE_UINT32, &ip4_internal_netmask, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_dns, &ip4_internal_dns_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_internal_nbns, &ip4_internal_nbns_len, + DBUS_TYPE_STRING, &dns_domain, + DBUS_TYPE_STRING, &login_banner, DBUS_TYPE_INVALID)) + { + NMIP4Config * config; + NMDevice * parent_dev; + guint32 i; + +#if 0 + print_vpn_config (ip4_vpn_gateway, tundev, ip4_internal_address, ip4_internal_netmask, + ip4_internal_dns, ip4_internal_dns_len, ip4_internal_nbns, ip4_internal_nbns_len, + dns_domain, login_banner); +#endif + + config = nm_ip4_config_new (); + + nm_ip4_config_set_address (config, ip4_internal_address); + + if (ip4_internal_netmask) + nm_ip4_config_set_netmask (config, ip4_internal_netmask); + else + nm_ip4_config_set_netmask (config, 0x00FF); /* Class C */ + + nm_ip4_config_set_gateway (config, ip4_vpn_gateway); + + if (strlen (dns_domain)) + nm_ip4_config_add_domain (config, dns_domain); + + for (i = 0; i < ip4_internal_dns_len; i++) + { + if (ip4_internal_dns[i] != 0) + nm_ip4_config_add_nameserver (config, ip4_internal_dns[i]); + } + + parent_dev = nm_vpn_act_request_get_parent_dev (req); + g_assert (parent_dev); + + if (nm_vpn_connection_set_config (vpn, tundev, parent_dev, config)) + { + if (login_banner && strlen (login_banner)) + nm_dbus_vpn_signal_vpn_login_banner (service->app_data->dbus_connection, vpn, login_banner); + success = TRUE; + } + } + + if (!success) + { + nm_warning ("nm_vpn_service_stage4_ip_config_get(%s): did not receive valid IP config information.", service->service); + nm_vpn_service_act_request_failed (service, req); + } + else + nm_vpn_service_activation_success (service, req); +} + + +static void nm_vpn_service_stop_connection_internal (NMVPNService *service) +{ + DBusMessage * message; + char * op; + + g_return_if_fail (service != NULL); + + /* Construct a new method call with the correct service and object path */ + op = construct_op_from_service_name (service->service); + if ((message = dbus_message_new_method_call (service->service, op, service->service, "stopConnection"))) + { + dbus_connection_send (service->app_data->dbus_connection, message, NULL); + dbus_message_unref (message); + } + else + nm_warning ("nm_vpn_service_stop_connection(): error, couldn't allocate dbus message."); + + g_free (op); +} + + +void nm_vpn_service_stop_connection (NMVPNService *service, NMVPNActRequest *req) +{ + NMVPNConnection *vpn; + + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + vpn = nm_vpn_act_request_get_connection (req); + g_assert (vpn); + + nm_vpn_service_cancel_callback (service, req); + nm_vpn_act_request_set_stage (req, NM_VPN_ACT_STAGE_DISCONNECTED); + + /* Ensure we can stop the connection in this state */ + if ((service->state != NM_VPN_STATE_STARTED) && (service->state != NM_VPN_STATE_STARTING)) + { + nm_info ("nm_vpn_service_start_connection(%s): could not stop connection '%s' because service was not STARTED.", + service->service, nm_vpn_connection_get_name (vpn)); + return; + } + + nm_vpn_service_stop_connection_internal (service); + nm_vpn_service_set_state (service, NM_VPN_STATE_STOPPED); +} + + +static void nm_vpn_service_add_watch (NMVPNService *service) +{ + char * match_string = NULL; + + g_return_if_fail (service != NULL); + + if (service->watch_active) + return; + + /* Add a dbus filter for this connection's service name so its signals + * get delivered to us. + */ + match_string = g_strdup_printf ("type='signal'," + "interface='%s'," + "sender='%s'", service->service, service->service); + dbus_bus_add_match (service->app_data->dbus_connection, match_string, NULL); + g_free (match_string); + service->watch_active = TRUE; +} + + +static void nm_vpn_service_remove_watch (NMVPNService *service) +{ + char * match_string = NULL; + + g_return_if_fail (service != NULL); + + if (!service->watch_active) + return; + + match_string = g_strdup_printf ("type='signal'," + "interface='%s'," + "sender='%s'", service->service, service->service); + dbus_bus_remove_match (service->app_data->dbus_connection, match_string, NULL); + g_free (match_string); + service->watch_active = FALSE; +} + + +static inline gboolean same_service_name (NMVPNService *service, NMVPNConnection *vpn) +{ + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (vpn != NULL, FALSE); + + return (!strcmp (nm_vpn_service_get_service_name (service), nm_vpn_connection_get_service_name (vpn))); +} + + +gboolean nm_vpn_service_name_owner_changed (NMVPNService *service, NMVPNActRequest *req, const char *old, const char *new) +{ + NMVPNConnection * vpn; + gboolean valid_vpn = FALSE; + gboolean old_owner_good = (old && strlen (old)); + gboolean new_owner_good = (new && strlen (new)); + + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (req != NULL, FALSE); + + if (req && (vpn = nm_vpn_act_request_get_connection (req))) + valid_vpn = same_service_name (service, vpn); + + if (!old_owner_good && new_owner_good) + { + /* VPN service started. */ + nm_vpn_service_add_watch (service); + nm_vpn_service_set_state (service, NM_VPN_STATE_INIT); + } + else if (old_owner_good && !new_owner_good) + { + /* VPN service went away. */ + nm_vpn_service_set_state (service, NM_VPN_STATE_SHUTDOWN); + nm_vpn_service_remove_watch (service); + + if (valid_vpn) + { + nm_vpn_act_request_unref (req); + nm_vpn_manager_schedule_vpn_connection_died (service->manager, req); + } + } return TRUE; } + +gboolean nm_vpn_service_process_signal (NMVPNService *service, NMVPNActRequest *req, DBusMessage *message) +{ + NMVPNConnection * vpn = NULL; + gboolean valid_vpn = FALSE; + + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (message != NULL, FALSE); + + if (req && (vpn = nm_vpn_act_request_get_connection (req))) + valid_vpn = same_service_name (service, vpn); + + if ( dbus_message_is_signal (message, service->service, NM_DBUS_VPN_SIGNAL_LOGIN_FAILED) + || dbus_message_is_signal (message, service->service, NM_DBUS_VPN_SIGNAL_LAUNCH_FAILED) + || dbus_message_is_signal (message, service->service, NM_DBUS_VPN_SIGNAL_CONNECT_FAILED) + || dbus_message_is_signal (message, service->service, NM_DBUS_VPN_SIGNAL_VPN_CONFIG_BAD) + || dbus_message_is_signal (message, service->service, NM_DBUS_VPN_SIGNAL_IP_CONFIG_BAD)) + { + const char * member = dbus_message_get_member (message); + char * error_msg; + + if (valid_vpn) + { + if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) + error_msg = (char *) ""; + nm_warning ("VPN failed for service '%s', signal '%s', with message '%s'.", service->service, member, error_msg); + nm_dbus_vpn_signal_vpn_failed (service->app_data->dbus_connection, member, vpn, error_msg); + /* Don't deal with VPN Connection stopping here, we'll do that when we get the STOPPED or STOPPING signal below */ + } + } + else if (dbus_message_is_signal (message, service->service, NM_DBUS_VPN_SIGNAL_STATE_CHANGE)) + { + dbus_uint32_t old_state_int; + dbus_uint32_t new_state_int; + + if (dbus_message_get_args (message, NULL, DBUS_TYPE_UINT32, &old_state_int, DBUS_TYPE_UINT32, &new_state_int, DBUS_TYPE_INVALID)) + { + NMVPNState old_state = (NMVPNState) old_state_int; + NMVPNState new_state = (NMVPNState) new_state_int; + + nm_info ("VPN service '%s' signaled new state %d, old state %d.", service->service, new_state, old_state); + nm_vpn_service_set_state (service, new_state); + + /* If the VPN daemon state is now stopped and it was starting, clear the active connection */ + if (((new_state == NM_VPN_STATE_STOPPED) || (new_state == NM_VPN_STATE_SHUTDOWN) || (new_state == NM_VPN_STATE_STOPPING)) + && ((old_state == NM_VPN_STATE_STARTED) || (old_state == NM_VPN_STATE_STARTING))) + { + nm_vpn_act_request_unref (req); + nm_vpn_manager_schedule_vpn_connection_died (service->manager, req); + } + } + } + else if (valid_vpn && dbus_message_is_signal (message, service->service, NM_DBUS_VPN_SIGNAL_IP4_CONFIG)) + nm_vpn_service_stage4_ip_config_get (service, req, message); + + return TRUE; +} + + +/* + * Prints config returned from the service daemo + */ +static void print_vpn_config (guint32 ip4_vpn_gateway, + const char *tundev, + guint32 ip4_internal_address, + gint32 ip4_internal_netmask, + guint32 *ip4_internal_dns, + guint32 ip4_internal_dns_len, + guint32 *ip4_internal_nbns, + guint32 ip4_internal_nbns_len, + const char *dns_domain, + const char *login_banner) +{ + struct in_addr temp_addr; + guint32 i; + + temp_addr.s_addr = ip4_vpn_gateway; + nm_info ("VPN Gateway: %s", inet_ntoa (temp_addr)); + nm_info ("Tunnel Device: %s", tundev); + temp_addr.s_addr = ip4_internal_address; + nm_info ("Internal IP4 Address: %s", inet_ntoa (temp_addr)); + temp_addr.s_addr = ip4_internal_netmask; + nm_info ("Internal IP4 Netmask: %s", inet_ntoa (temp_addr)); + + for (i = 0; i < ip4_internal_dns_len; i++) + { + if (ip4_internal_dns[i] != 0) + { + temp_addr.s_addr = ip4_internal_dns[i]; + nm_info ("Internal IP4 DNS: %s", inet_ntoa (temp_addr)); + } + } + + for (i = 0; i < ip4_internal_nbns_len; i++) + { + if (ip4_internal_nbns[i] != 0) + { + temp_addr.s_addr = ip4_internal_nbns[i]; + nm_info ("Internal IP4 NBNS: %s", inet_ntoa (temp_addr)); + } + } + + nm_info ("DNS Domain: '%s'", dns_domain); + nm_info ("Login Banner:"); + nm_info ("-----------------------------------------"); + nm_info ("%s", login_banner); + nm_info ("-----------------------------------------"); +} + diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h index 70a9b1605a..1a2bf2c22b 100644 --- a/src/vpn-manager/nm-vpn-service.h +++ b/src/vpn-manager/nm-vpn-service.h @@ -25,27 +25,32 @@ #include #include "NetworkManager.h" - +#include "NetworkManagerMain.h" +#include "nm-vpn-connection.h" typedef struct NMVPNService NMVPNService; -NMVPNService * nm_vpn_service_new (void); -void nm_vpn_service_ref (NMVPNService *service); -void nm_vpn_service_unref (NMVPNService *service); +NMVPNService * nm_vpn_service_new (NMVPNManager *manager, NMData *app_data); -const char * nm_vpn_service_get_name (NMVPNService *service); -void nm_vpn_service_set_name (NMVPNService *service, const char *name); +void nm_vpn_service_ref (NMVPNService *service); +void nm_vpn_service_unref (NMVPNService *service); -const char * nm_vpn_service_get_service_name (NMVPNService *service); -void nm_vpn_service_set_service_name (NMVPNService *service, const char *name); +const char * nm_vpn_service_get_name (NMVPNService *service); +void nm_vpn_service_set_name (NMVPNService *service, const char *name); -const char * nm_vpn_service_get_program (NMVPNService *service); -void nm_vpn_service_set_program (NMVPNService *service, const char *program); +const char * nm_vpn_service_get_service_name (NMVPNService *service); +void nm_vpn_service_set_service_name (NMVPNService *service, const char *name); -NMVPNState nm_vpn_service_get_state (NMVPNService *service); -void nm_vpn_service_set_state (NMVPNService *service, const NMVPNState state); +const char * nm_vpn_service_get_program (NMVPNService *service); +void nm_vpn_service_set_program (NMVPNService *service, const char *program); -gboolean nm_vpn_service_exec_daemon (NMVPNService *service); +NMVPNState nm_vpn_service_get_state (NMVPNService *service); + +gboolean nm_vpn_service_name_owner_changed (NMVPNService *service, NMVPNActRequest *req, const char *old, const char *new); +gboolean nm_vpn_service_process_signal (NMVPNService *service, NMVPNActRequest *req, DBusMessage *message); + +void nm_vpn_service_start_connection (NMVPNService *service, NMVPNActRequest *req); +void nm_vpn_service_stop_connection (NMVPNService *service, NMVPNActRequest *req); #endif diff --git a/vpn-daemons/vpnc/src/nm-vpnc-service.c b/vpn-daemons/vpnc/src/nm-vpnc-service.c index c4bc7ba423..635871fa22 100644 --- a/vpn-daemons/vpnc/src/nm-vpnc-service.c +++ b/vpn-daemons/vpnc/src/nm-vpnc-service.c @@ -1024,6 +1024,7 @@ static DBusHandlerResult nm_vpnc_dbus_filter (DBusConnection *con, DBusMessage * { /* If NM goes away, we don't stick around */ nm_vpnc_dbus_handle_stop_vpn (data); + g_main_loop_quit (data->loop); } } }