diff options
author | Tim Niemueller <tim@niemueller.de> | 2006-08-19 15:13:02 +0000 |
---|---|---|
committer | Tim Niemueller <tim@niemueller.de> | 2006-08-19 15:13:02 +0000 |
commit | 6a72c7ff0d988b40e031aa8ec2e655e51d2805d0 (patch) | |
tree | e07a04e6e2937eb0f6514bd341085b91d5268fa8 | |
parent | 160f524eab0e5c8ae49ca30bdc4befad10e19b68 (diff) | |
download | NetworkManager-6a72c7ff0d988b40e031aa8ec2e655e51d2805d0.tar.gz |
2006-08-19 Tim Niemueller <tim@niemueller.de>
* src/dialup/manager/*: Added new dialup manager, full ability to
start and control connections
git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/branches/SoC_2006@1972 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
-rw-r--r-- | src/dialup/manager/.cvsignore | 2 | ||||
-rw-r--r-- | src/dialup/manager/Makefile.am | 42 | ||||
-rw-r--r-- | src/dialup/manager/nm-dbus-dialup.c | 672 | ||||
-rw-r--r-- | src/dialup/manager/nm-dbus-dialup.h | 40 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-act-request.c | 245 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-act-request.h | 61 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-connection.c | 227 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-connection.h | 44 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-manager.c | 640 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-manager.h | 56 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-service.c | 1087 | ||||
-rw-r--r-- | src/dialup/manager/nm-dialup-service.h | 61 |
12 files changed, 3177 insertions, 0 deletions
diff --git a/src/dialup/manager/.cvsignore b/src/dialup/manager/.cvsignore new file mode 100644 index 0000000000..282522db03 --- /dev/null +++ b/src/dialup/manager/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/src/dialup/manager/Makefile.am b/src/dialup/manager/Makefile.am new file mode 100644 index 0000000000..d7295aaec4 --- /dev/null +++ b/src/dialup/manager/Makefile.am @@ -0,0 +1,42 @@ +INCLUDES = -I${top_srcdir} \ + -I${top_srcdir}/include \ + -I${top_srcdir}/utils \ + -I${top_srcdir}/src \ + -I${top_srcdir}/src/named-manager + + +noinst_LTLIBRARIES = libdialup-manager.la + +libdialup_manager_la_SOURCES = \ + nm-dialup-manager.h \ + nm-dialup-manager.c \ + nm-dialup-connection.h \ + nm-dialup-connection.c \ + nm-dbus-dialup.h \ + nm-dbus-dialup.c \ + nm-dialup-service.h \ + nm-dialup-service.c \ + nm-dialup-act-request.h \ + nm-dialup-act-request.c + +libdialup_manager_la_LIBADD = $(DBUS_LIBS) $(GTHREAD_LIBS) + +AM_CPPFLAGS = \ + $(DBUS_CFLAGS) \ + $(GTHREAD_CFLAGS) \ + $(HAL_CFLAGS) \ + -Wall \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DPREFIX=\""$(prefix)"\" \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DVERSION="\"$(VERSION)\"" \ + -DLIBDIR=\""$(libdir)"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -DLOCALSTATEDIR=\""$(localstatedir)"\" \ + -DDATADIR=\"$(datadir)\" \ + -fPIC + +CLEANFILES = *~ + diff --git a/src/dialup/manager/nm-dbus-dialup.c b/src/dialup/manager/nm-dbus-dialup.c new file mode 100644 index 0000000000..50c5c47aa0 --- /dev/null +++ b/src/dialup/manager/nm-dbus-dialup.c @@ -0,0 +1,672 @@ +/* NetworkManager -- Network link manager + * + * Tim Niemueller [www.niemueller.de] + * Dan Williams <dcbw@redhat.com> + * + * 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. + * (C) Copyright 2006 Tim Niemueller + */ + +#include <glib.h> +#include <dbus/dbus.h> +#include "NetworkManagerMain.h" +#include "nm-device.h" +#include "NetworkManagerDbus.h" +#include "NetworkManagerUtils.h" +#include "NetworkManagerDialup.h" +#include "nm-dbus-dialup.h" +#include "nm-dialup-manager.h" +#include "nm-dialup-connection.h" +#include "nm-dialup-service.h" +#include "nm-dialup-act-request.h" +#include "nm-utils.h" + + +/* + * nm_dbus_dialup_signal_dialup_connection_update + * + * Notifies the bus that a Dialup connection's properties have changed. + * + */ +void nm_dbus_dialup_signal_dialup_connection_update (DBusConnection *con, NMDialupConnection *dialup, const char *signal) +{ + DBusMessage *message; + const char *dialup_name; + + g_return_if_fail (con != NULL); + g_return_if_fail (dialup != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_DIALUP, NM_DBUS_INTERFACE_DIALUP, signal))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + dialup_name = nm_dialup_connection_get_name (dialup); + + dbus_message_append_args (message, DBUS_TYPE_STRING, &dialup_name, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("Could not raise the %s signal!", signal); + + dbus_message_unref (message); +} + +/* + * nm_dbus_dialup_signal_dialup_connection_state_change + * + * Notifies the bus that a dialup connection's state has changed. + */ +void nm_dbus_dialup_signal_dialup_connection_state_change (DBusConnection *con, NMDialupConnection *dialup, NMDialupActStage new_stage) +{ + DBusMessage * message; + const char * dialup_name; + dbus_uint32_t int_stage = (dbus_uint32_t) new_stage; + + g_return_if_fail (con != NULL); + g_return_if_fail (dialup != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_DIALUP, NM_DBUS_INTERFACE_DIALUP, "DialupConnectionStateChange"))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + dialup_name = nm_dialup_connection_get_name (dialup); + dbus_message_append_args (message, DBUS_TYPE_STRING, &dialup_name, DBUS_TYPE_UINT32, &int_stage, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("Could not raise the DialupConnectionStateChange signal!"); + + dbus_message_unref (message); +} + + +/* + * nnm_dbus_dialup_signal_dialup_failure + * + * Proxy a Dialup Failure message from the dialup daemon to the bus. + * + */ +void nm_dbus_dialup_signal_dialup_failed (DBusConnection *con, const char *signal, NMDialupConnection *dialup, const char *error_msg) +{ + DBusMessage *message; + const char *dialup_name; + + g_return_if_fail (con != NULL); + g_return_if_fail (signal != NULL); + g_return_if_fail (dialup != NULL); + g_return_if_fail (error_msg != NULL); + + if (!(message = dbus_message_new_signal (NM_DBUS_PATH_DIALUP, NM_DBUS_INTERFACE_DIALUP, signal))) + { + nm_warning ("Not enough memory for new dbus message!"); + return; + } + + dialup_name = nm_dialup_connection_get_name (dialup); + dbus_message_append_args (message, DBUS_TYPE_STRING, &dialup_name, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID); + if (!dbus_connection_send (con, message, NULL)) + nm_warning ("Could not raise the %s signal!", signal); + + dbus_message_unref (message); +} + + +/* + * nm_dbus_dialup_get_dialup_data + * + * Get dialup specific data from NMI for a dialup connection + * + * NOTE: caller MUST free returned value using g_strfreev() + * + */ +static char ** nm_dbus_dialup_get_dialup_data (DBusConnection *connection, NMDialupConnection *dialup, int *num_items) +{ + DBusMessage *message; + DBusError error; + DBusMessage *reply; + char **data_items = NULL; + const char *dialup_name; + + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (dialup != NULL, NULL); + g_return_val_if_fail (num_items != NULL, NULL); + + *num_items = -1; + + if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getDialupConnectionDialupData"))) + { + nm_warning ("nm_dbus_dialup_get_dialup_data(): Couldn't allocate the dbus message"); + return (NULL); + } + + dialup_name = nm_dialup_connection_get_name (dialup); + dbus_message_append_args (message, DBUS_TYPE_STRING, &dialup_name, DBUS_TYPE_INVALID); + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + dbus_message_unref (message); + if (dbus_error_is_set (&error)) + nm_warning ("nm_dbus_dialup_get_dialup_data(): %s raised %s", error.name, error.message); + else if (!reply) + nm_info ("nm_dbus_dialup_get_dialup_data(): reply was NULL."); + else + { + DBusMessageIter iter, array_iter; + GArray *buffer; + + dbus_message_iter_init (reply, &iter); + dbus_message_iter_recurse (&iter, &array_iter); + + buffer = g_array_new (TRUE, TRUE, sizeof (gchar *)); + + if (buffer == NULL) + return NULL; + + while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING) + { + const char *value; + char *str; + + dbus_message_iter_get_basic (&array_iter, &value); + str = g_strdup (value); + + if (str == NULL) + { + g_array_free (buffer, TRUE); + return NULL; + } + + g_array_append_val (buffer, str); + + dbus_message_iter_next (&array_iter); + } + data_items = (gchar **)(buffer->data); + *num_items = buffer->len; + g_array_free (buffer, FALSE); + } + + if (reply) + dbus_message_unref (reply); + + return (data_items); +} + + + +typedef struct UpdateOneDialupCBData +{ + NMData * data; + char * dialup; +} UpdateOneDialupCBData; + + +static void free_update_one_dialup_cb_data (UpdateOneDialupCBData *data) +{ + if (data) + g_free (data->dialup); + g_free (data); +} + +/* + * nm_dbus_dialup_update_one_connection_cb + * + * Retrieve and add to our dialup Manager one dialup connection from NMI. + * + */ +static void nm_dbus_dialup_update_one_connection_cb (DBusPendingCall *pcall, void *user_data) +{ + UpdateOneDialupCBData * cb_data = (UpdateOneDialupCBData *) user_data; + DBusMessage * reply; + const char * con_name = NULL; + const char * service_name = NULL; + const char * user_name = NULL; + + g_return_if_fail (pcall != NULL); + g_return_if_fail (cb_data != NULL); + g_return_if_fail (cb_data->data != NULL); + g_return_if_fail (cb_data->data->dialup_manager != NULL); + + dbus_pending_call_ref (pcall); + + if (!dbus_pending_call_get_completed (pcall)) + goto out; + + if (!(reply = dbus_pending_call_steal_reply (pcall))) + goto out; + + if (dbus_message_is_error (reply, "BadDialupConnectionData")) + { + NMDialupConnection *dialup; + + /* Bad dialup, remove it from our dialup connection list */ + if ((dialup = nm_dialup_manager_find_connection_by_name (cb_data->data->dialup_manager, cb_data->dialup))) + { + nm_dialup_connection_ref (dialup); + nm_dialup_manager_remove_connection (cb_data->data->dialup_manager, dialup); + nm_dbus_dialup_signal_dialup_connection_update (cb_data->data->dbus_connection, dialup, "DialupConnectionRemoved"); + nm_dialup_connection_unref (dialup); + } + goto out; + } + + if (dbus_message_get_args (reply, NULL, + DBUS_TYPE_STRING, &con_name, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_STRING, &user_name, + DBUS_TYPE_INVALID)) + { + NMDialupConnection * dialup; + gboolean new = TRUE; + + // nm_info ("Updating connectoin %s/%s/%s", con_name, service_name, user_name); + + if ((dialup = nm_dialup_manager_find_connection_by_name (cb_data->data->dialup_manager, con_name))) + { + const char *dialup_service_name = nm_dialup_connection_get_service_name (dialup); + + /* If all attributes of the existing connection are the same as the one we get from NMI, + * don't do anything. + */ + if (strcmp (dialup_service_name, service_name) || strcmp (nm_dialup_connection_get_user_name (dialup), user_name)) + nm_dialup_manager_remove_connection (cb_data->data->dialup_manager, dialup); + else + new = FALSE; + } + + if (new) + dialup = nm_dialup_manager_add_connection (cb_data->data->dialup_manager, con_name, service_name, user_name); + + if (dialup) + nm_dbus_dialup_signal_dialup_connection_update (cb_data->data->dbus_connection, dialup, new ? "DialupConnectionAdded" : "DialupConnectionUpdate"); + + } + dbus_message_unref (reply); + +out: + dbus_pending_call_unref (pcall); +} + + +/* + * nm_dbus_dialup_connections_update_cb + * + * Async callback from nnm_dbus_dialup_connections_update + * + */ +static void nm_dbus_dialup_connections_update_cb (DBusPendingCall *pcall, void *user_data) +{ + 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); + + dbus_pending_call_ref (pcall); + + if (!dbus_pending_call_get_completed (pcall)) + goto out; + + if (!(reply = dbus_pending_call_steal_reply (pcall))) + goto out; + + if (message_is_error (reply)) + goto out; + + remove_list = nm_dialup_manager_dialup_connection_list_copy (data->dialup_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 * con_name; + NMDialupConnection * dialup; + + dbus_message_iter_get_basic (&array_iter, &con_name); + + /* If the connection already exists, remove it from the remove list */ + if ((dialup = nm_dialup_manager_find_connection_by_name (data->dialup_manager, con_name))) + { + remove_list = g_slist_remove (remove_list, dialup); + } + + if ((message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getDialupConnectionProperties"))) + { + DBusPendingCall * dialup_pcall = NULL; + + dbus_message_append_args (message, DBUS_TYPE_STRING, &con_name, DBUS_TYPE_INVALID); + dbus_connection_send_with_reply (data->dbus_connection, message, &dialup_pcall, -1); + dbus_message_unref (message); + if (dialup_pcall) + { + UpdateOneDialupCBData * dialup_cb_data = g_malloc0 (sizeof (UpdateOneDialupCBData)); + + dialup_cb_data->data = data; + dialup_cb_data->dialup = g_strdup (con_name); + dbus_pending_call_set_notify (dialup_pcall, nm_dbus_dialup_update_one_connection_cb, dialup_cb_data, (DBusFreeFunction) free_update_one_dialup_cb_data); + } + } + dbus_message_iter_next (&array_iter); + } + dbus_message_unref (reply); + + /* dialup 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_dialup_manager_remove_connection (data->dialup_manager, elt->data); + nm_dialup_connection_unref (elt->data); + } + + g_slist_free (remove_list); + +out: + dbus_pending_call_unref (pcall); +} + + +/* + * nm_dbus_dialup_update_one_dialup_connection + * + * Update one dialup connection + * + */ +void nm_dbus_dialup_update_one_dialup_connection (DBusConnection *connection, const char *dialup, NMData *data) +{ + DBusMessage * message; + DBusPendingCall * pcall = NULL; + + g_return_if_fail (connection != NULL); + g_return_if_fail (dialup != NULL); + g_return_if_fail (data != NULL); + + if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getDialupConnectionProperties"))) + { + nm_warning ("nm_dbus_update_one_dialup_connection(): Couldn't allocate the dbus message"); + return; + } + + dbus_message_append_args (message, DBUS_TYPE_STRING, &dialup, DBUS_TYPE_INVALID); + dbus_connection_send_with_reply (connection, message, &pcall, -1); + dbus_message_unref (message); + if (pcall) + { + UpdateOneDialupCBData * cb_data = g_malloc0 (sizeof (UpdateOneDialupCBData)); + + cb_data->data = data; + cb_data->dialup = g_strdup (dialup); + dbus_pending_call_set_notify (pcall, nm_dbus_dialup_update_one_connection_cb, cb_data, (DBusFreeFunction) free_update_one_dialup_cb_data); + } +} + + +/* + * nm_dbus_dialup_connections_update_from_nmi + * + * Update dialup connections from NetworkManagerInfo. + * + */ +static gboolean nm_dbus_dialup_connections_update_from_nmi (NMData *data) +{ + DBusMessage * message; + DBusPendingCall * pcall; + + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data->dbus_connection != NULL, FALSE); + g_return_val_if_fail (data->dialup_manager != NULL, FALSE); + + if (!(message = dbus_message_new_method_call (NMI_DBUS_SERVICE, NMI_DBUS_PATH, NMI_DBUS_INTERFACE, "getDialupConnections"))) + { + nm_warning ("nm_dbus_dialup_connections_update (): Couldn't allocate the dbus message"); + return FALSE; + } + + dbus_connection_send_with_reply (data->dbus_connection, message, &pcall, -1); + dbus_message_unref (message); + if (pcall) + { + dbus_pending_call_set_notify (pcall, nm_dbus_dialup_connections_update_cb, data, NULL); + dbus_pending_call_block (pcall); + } + + return FALSE; +} + + +/* + * nm_dbus_dialup_schedule_dialup_connections_update + * + * Schedule an update of dialup connections in the main thread + * + */ +void nm_dbus_dialup_schedule_dialup_connections_update (NMData *app_data) +{ + GSource *source = NULL; + + g_return_if_fail (app_data != NULL); + g_return_if_fail (app_data->main_context != NULL); + + source = g_idle_source_new (); + /* We want this idle source to run before any other idle source */ + g_source_set_priority (source, G_PRIORITY_HIGH_IDLE); + g_source_set_callback (source, (GSourceFunc) nm_dbus_dialup_connections_update_from_nmi, app_data, NULL); + g_source_attach (source, app_data->main_context); + g_source_unref (source); +} + + +/* + * nm_dbus_dialup_get_dialup_connections + * + * Returns a string array of dialup connection names. + * + */ +static DBusMessage *nm_dbus_dialup_get_dialup_connections (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage *reply = NULL; + char **dialup_names = NULL; + int num_names; + + 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); + + if (!data->data->dialup_manager) + { + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_DIALUP, "NoDialupConnections", "There are no available dialup connections."); + goto out; + } + + dialup_names = nm_dialup_manager_get_connection_names (data->data->dialup_manager); + num_names = dialup_names ? g_strv_length (dialup_names) : 0; + if (num_names == 0) + { + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_DIALUP, "NoDialupConnections", "There are no available dialup connections."); + goto out; + } + + if (!(reply = dbus_message_new_method_return (message))) + goto out; + + dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &dialup_names, num_names, DBUS_TYPE_INVALID); + +out: + if (dialup_names) + g_strfreev (dialup_names); + + return (reply); +} + + +/* + * nm_dbus_dialup_get_dialup_connection_properties + * + * Grab properties of a dialup connection + * + */ +static DBusMessage *nm_dbus_dialup_get_dialup_connection_properties (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusMessage * reply = NULL; + DBusError error; + const char * name; + gboolean good = FALSE; + NMDialupManager * manager; + NMDialupConnection * dialup; + + 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); + + /* Check for no dialup Manager */ + if (!(manager = data->data->dialup_manager)) + return nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_DIALUP, "NoDialupConnections", "There are no available dialup connections."); + + if (!(reply = dbus_message_new_method_return (message))) + return NULL; + + dbus_error_init (&error); + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) + { + if ((dialup = nm_dialup_manager_find_connection_by_name (manager, name))) + { + const char * user_name; + const char * service_name; + NMDialupService * service; + + user_name = nm_dialup_connection_get_user_name (dialup); + service_name = nm_dialup_connection_get_service_name (dialup); + if ((service = nm_dialup_manager_find_service_by_name (data->data->dialup_manager, service_name))) + { + NMDialupActRequest * req = nm_dialup_manager_get_dialup_act_request (manager); + dbus_uint32_t stage = (dbus_uint32_t) NM_DIALUP_ACT_STAGE_DISCONNECTED; + + if (req && (nm_dialup_act_request_get_connection (req) == dialup)) + stage = nm_dialup_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; + } + } + } + + if (!good) + reply = nm_dbus_create_error_message (message, NM_DBUS_INTERFACE_DIALUP, "InvalidDialupConnection", "No dialup connection with that name was found."); + + return reply; +} + + +/* + * nm_dbus_dialup_activate_connection + * + * Activate a specific dialup connection. + * + */ +static DBusMessage *nm_dbus_dialup_activate_connection (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + DBusError error; + const char * name; + char ** passwords; + int num_passwords; + NMDialupConnection * dialup; + + 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); + + 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 ((dialup = nm_dialup_manager_find_connection_by_name (data->data->dialup_manager, name))) + { + int item_count = -1; + char **items; + if ((items = nm_dbus_dialup_get_dialup_data (connection, dialup, &item_count))) + { + char * joined_string = g_strjoinv (" :: ", items); + nm_info ("Will activate dialup connection '%s', service '%s', user_name '%s', dialup_data '%s'.", + name, nm_dialup_connection_get_service_name (dialup), nm_dialup_connection_get_user_name (dialup), joined_string); + nm_dialup_manager_activate_dialup_connection (data->data->dialup_manager, dialup, passwords, num_passwords, items, item_count); + + g_free (joined_string); + g_strfreev (items); + } + } else { + nm_warning ("nm_dbus_dialup_activate_connection(): cannot find dialup connection '%s'", name); + } + } else { + nm_warning ("nm_dbus_dialup_activate_connection(): syntax error in method arguments"); + } + + return NULL; +} + + +/* + * nm_dbus_dialup_deactivate_connection + * + * Deactivate the active dialup connection, if any. + * + */ +static DBusMessage *nm_dbus_dialup_deactivate_connection (DBusConnection *connection, DBusMessage *message, NMDbusCBData *data) +{ + NMDialupActRequest *req; + NMDialupConnection *dialup; + + 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); + + if (!(req = nm_dialup_manager_get_dialup_act_request (data->data->dialup_manager))) + return NULL; + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_info ("Will deactivate the dialup connection '%s', service '%s'.", nm_dialup_connection_get_name (dialup), + nm_dialup_connection_get_service_name (dialup)); + nm_dialup_manager_deactivate_dialup_connection (data->data->dialup_manager); + + return NULL; +} + + +/* + * nm_dbus_dialup_methods_setup + * + * Register handlers for dbus methods on the + * org.freedesktop.NetworkManager.DialupConnections object. + * + */ +NMDbusMethodList *nm_dbus_dialup_methods_setup (void) +{ + NMDbusMethodList *list = nm_dbus_method_list_new (NULL); + + nm_dbus_method_list_add_method (list, "getDialupConnections", nm_dbus_dialup_get_dialup_connections); + nm_dbus_method_list_add_method (list, "getDialupConnectionProperties", nm_dbus_dialup_get_dialup_connection_properties); + nm_dbus_method_list_add_method (list, "activateDialupConnection", nm_dbus_dialup_activate_connection); + nm_dbus_method_list_add_method (list, "deactivateDialupConnection", nm_dbus_dialup_deactivate_connection); + + return (list); +} diff --git a/src/dialup/manager/nm-dbus-dialup.h b/src/dialup/manager/nm-dbus-dialup.h new file mode 100644 index 0000000000..1d08b60ea9 --- /dev/null +++ b/src/dialup/manager/nm-dbus-dialup.h @@ -0,0 +1,40 @@ +/* NetworkManager -- Network link manager + * + * Tim Niemueller [www.niemueller.de] + * Dan Williams <dcbw@redhat.com> + * + * 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. + * (C) Copyright 2006 Tim Niemueller + */ + +#ifndef NM_DBUS_DIALUP_H +#define NM_DBUS_DIALUP_H + +#include "NetworkManagerDbusUtils.h" +#include "nm-dialup-manager.h" +#include "nm-dialup-connection.h" + +void nm_dbus_dialup_schedule_dialup_connections_update (NMData *app_data); +void nm_dbus_dialup_update_one_dialup_connection (DBusConnection *connection, const char *dialup, NMData *data); + +void nm_dbus_dialup_signal_dialup_connection_update (DBusConnection *con, NMDialupConnection *dialup, const char *signal); +void nm_dbus_dialup_signal_dialup_failed (DBusConnection *con, const char *signal, NMDialupConnection *dialup, const char *error_msg); +void nm_dbus_dialup_signal_dialup_connection_state_change (DBusConnection *con, NMDialupConnection *dialup, NMDialupActStage new_stage); + +NMDbusMethodList * nm_dbus_dialup_methods_setup (void); + +#endif diff --git a/src/dialup/manager/nm-dialup-act-request.c b/src/dialup/manager/nm-dialup-act-request.c new file mode 100644 index 0000000000..96a8416875 --- /dev/null +++ b/src/dialup/manager/nm-dialup-act-request.c @@ -0,0 +1,245 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams <dcbw@redhat.com> + * + * 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 <glib.h> +#include <string.h> +#include "nm-dialup-act-request.h" +#include "nm-dbus-dialup.h" + + +struct NMDialupActRequest +{ + guint refcount; + NMDialupActStage stage; + + NMDialupManager * manager; + NMDialupService * service; + NMDialupConnection * dialup; + + char ** password_items; + int password_count; + char ** data_items; + int data_count; + + guint daemon_wait_count; + guint callback_id; + gboolean canceled; +}; + + +NMDialupActRequest *nm_dialup_act_request_new (NMDialupManager *manager, NMDialupService *service, NMDialupConnection *dialup, + char **password_items, int password_count, + char **data_items, int data_count) +{ + NMDialupActRequest *req; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (service != NULL, NULL); + g_return_val_if_fail (dialup != NULL, NULL); + g_return_val_if_fail (password_items != NULL, NULL); + g_return_val_if_fail (data_items != NULL, NULL); + + req = g_malloc0 (sizeof (NMDialupActRequest)); + req->refcount = 1; + req->stage = NM_DIALUP_ACT_STAGE_PREPARE; + + req->manager = manager; + nm_dialup_service_ref (service); + req->service = service; + nm_dialup_connection_ref (dialup); + req->dialup = dialup; + + 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_dialup_act_request_ref (NMDialupActRequest *req) +{ + g_return_if_fail (req != NULL); + + req->refcount++; +} + + +void nm_dialup_act_request_unref (NMDialupActRequest *req) +{ + g_return_if_fail (req != NULL); + + req->refcount--; + if (req->refcount == 0) + { + nm_dialup_service_unref (req->service); + nm_dialup_connection_unref (req->dialup); + + g_strfreev (req->password_items); + g_strfreev (req->data_items); + + memset (req, 0, sizeof (NMDialupActRequest)); + g_free (req); + } +} + +gboolean nm_dialup_act_request_is_activating (NMDialupActRequest *req) +{ + gboolean activating = FALSE; + + g_return_val_if_fail (req != NULL, FALSE); + + switch (req->stage) + { + case NM_DIALUP_ACT_STAGE_PREPARE: + case NM_DIALUP_ACT_STAGE_CONNECT: + case NM_DIALUP_ACT_STAGE_IP_CONFIG_GET: + activating = TRUE; + break; + + default: + break; + } + + return activating; +} + +gboolean nm_dialup_act_request_is_activated (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, FALSE); + + return (req->stage == NM_DIALUP_ACT_STAGE_ACTIVATED) ? TRUE : FALSE; +} + +gboolean nm_dialup_act_request_is_failed (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, FALSE); + + return (req->stage == NM_DIALUP_ACT_STAGE_FAILED) ? TRUE : FALSE; +} + +NMDialupManager *nm_dialup_act_request_get_manager (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + + return req->manager; +} + +NMDialupService * nm_dialup_act_request_get_service (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + + return req->service; +} + + +NMDialupConnection * nm_dialup_act_request_get_connection (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, NULL); + + return req->dialup; +} + +const char ** nm_dialup_act_request_get_password_items (NMDialupActRequest *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_dialup_act_request_get_data_items (NMDialupActRequest *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_dialup_act_request_cancel (NMDialupActRequest *req) +{ + g_return_if_fail (req != NULL); + + req->canceled = TRUE; +} + +gboolean nm_dialup_act_request_should_cancel (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, FALSE); + + return req->canceled; +} + +NMDialupActStage nm_dialup_act_request_get_stage (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, NM_DIALUP_ACT_STAGE_UNKNOWN); + + return req->stage; +} + +void nm_dialup_act_request_set_stage (NMDialupActRequest *req, NMDialupActStage stage) +{ + NMDialupActStage old_stage; + + g_return_if_fail (req != NULL); + + old_stage = req->stage; + if (old_stage != stage) + { + DBusConnection *dbus_connection = nm_dialup_service_get_dbus_connection (req->service); + + req->stage = stage; + nm_dbus_dialup_signal_dialup_connection_state_change (dbus_connection, req->dialup, req->stage); + } +} + +guint nm_dialup_act_request_get_daemon_wait_count (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, 0); + + return req->daemon_wait_count; +} + +void nm_dialup_act_request_set_daemon_wait_count (NMDialupActRequest *req, guint count) +{ + g_return_if_fail (req != NULL); + + req->daemon_wait_count = count; +} + +guint nm_dialup_act_request_get_callback_id (NMDialupActRequest *req) +{ + g_return_val_if_fail (req != NULL, 0); + + return req->callback_id; +} + +void nm_dialup_act_request_set_callback_id (NMDialupActRequest *req, guint id) +{ + g_return_if_fail (req != NULL); + + req->callback_id = id; +} + diff --git a/src/dialup/manager/nm-dialup-act-request.h b/src/dialup/manager/nm-dialup-act-request.h new file mode 100644 index 0000000000..4396a67274 --- /dev/null +++ b/src/dialup/manager/nm-dialup-act-request.h @@ -0,0 +1,61 @@ +/* NetworkManager -- Network link manager + * + * Tim Niemueller [www.niemueller.de] + * Dan Williams <dcbw@redhat.com> + * + * 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. + * (C) Copyright 2006 Tim Niemueller + */ + +#ifndef NM_DIALUP_ACT_REQUEST_H +#define NM_DIALUP_ACT_REQUEST_H + +#include <glib.h> +#include "NetworkManager.h" +#include "NetworkManagerMain.h" +#include "nm-dialup-connection.h" +#include "nm-dialup-service.h" + +NMDialupActRequest * nm_dialup_act_request_new (NMDialupManager *manager, NMDialupService *service, NMDialupConnection *dialup, + char **password_items, int password_count, char **data_items, int data_count); +void nm_dialup_act_request_ref (NMDialupActRequest *req); +void nm_dialup_act_request_unref (NMDialupActRequest *req); + +gboolean nm_dialup_act_request_is_activating (NMDialupActRequest *req); +gboolean nm_dialup_act_request_is_activated (NMDialupActRequest *req); +gboolean nm_dialup_act_request_is_failed (NMDialupActRequest *req); + +NMDialupManager * nm_dialup_act_request_get_manager (NMDialupActRequest *req); +NMDialupService * nm_dialup_act_request_get_service (NMDialupActRequest *req); +NMDialupConnection * nm_dialup_act_request_get_connection (NMDialupActRequest *req); + +const char ** nm_dialup_act_request_get_password_items (NMDialupActRequest *req, guint *count); +const char ** nm_dialup_act_request_get_data_items (NMDialupActRequest *req, guint *count); + +void nm_dialup_act_request_cancel (NMDialupActRequest *req); +gboolean nm_dialup_act_request_should_cancel (NMDialupActRequest *req); + +NMDialupActStage nm_dialup_act_request_get_stage (NMDialupActRequest *req); +void nm_dialup_act_request_set_stage (NMDialupActRequest *req, NMDialupActStage stage); + +guint nm_dialup_act_request_get_daemon_wait_count (NMDialupActRequest *req); +void nm_dialup_act_request_set_daemon_wait_count (NMDialupActRequest *req, guint count); + +guint nm_dialup_act_request_get_callback_id (NMDialupActRequest *req); +void nm_dialup_act_request_set_callback_id (NMDialupActRequest *req, guint timeout); + +#endif diff --git a/src/dialup/manager/nm-dialup-connection.c b/src/dialup/manager/nm-dialup-connection.c new file mode 100644 index 0000000000..195744893d --- /dev/null +++ b/src/dialup/manager/nm-dialup-connection.c @@ -0,0 +1,227 @@ +/* nm-dialup-connection.c - handle a single dialup connection within NetworkManager's framework + * + * Copyright (C) 2006 Tim Niemueller + * based on work Copyright (C) 2005 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, 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. + */ + +#include "config.h" +#include <glib.h> +#include <string.h> +#include "nm-dialup-connection.h" +#include "nm-dbus-dialup.h" +#include "NetworkManagerSystem.h" + + +struct NMDialupConnection +{ + 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 */ + NMIP4Config * ip4_config; + char * dialup_iface; +}; + + +static void nm_dialup_connection_set_dialup_iface (NMDialupConnection *con, const char *dialup_iface); +static void nm_dialup_connection_set_ip4_config (NMDialupConnection *con, NMIP4Config *ip4_config); + +NMDialupConnection * +nm_dialup_connection_new (const char *name, const char *user_name, const char *service_name, + NMNamedManager *named_manager, DBusConnection *dbus_connection) +{ + NMDialupConnection *connection; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (user_name != 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 (NMDialupConnection)); + connection->refcount = 1; + + connection->name = g_strdup (name); + connection->user_name = g_strdup (user_name); + connection->service_name = g_strdup (service_name); + + g_object_ref (named_manager); + connection->named_manager = named_manager; + + connection->dbus_connection = dbus_connection; + + return connection; +} + + +void +nm_dialup_connection_ref (NMDialupConnection *connection) +{ + g_return_if_fail (connection != NULL); + + connection->refcount++; +} + + +void +nm_dialup_connection_unref (NMDialupConnection *connection) +{ + g_return_if_fail (connection != NULL); + + connection->refcount--; + if (connection->refcount <= 0) + { + g_free (connection->name); + g_free (connection->user_name); + g_free (connection->service_name); + + if (connection->ip4_config) + nm_ip4_config_unref (connection->ip4_config); + g_free (connection->dialup_iface); + + g_object_unref (connection->named_manager); + + memset (connection, 0, sizeof (NMDialupConnection)); + g_free (connection); + } +} + + +void +nm_dialup_connection_activate (NMDialupConnection *connection) +{ + g_return_if_fail (connection != NULL); + + /* Nothing done here yet */ +} + + +gboolean +nm_dialup_connection_set_config (NMDialupConnection *connection, const char *dialup_iface, NMIP4Config *ip4_config) +{ + gboolean success = FALSE; + + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (ip4_config != NULL, FALSE); + + if (dialup_iface != NULL && strlen (dialup_iface)) + nm_dialup_connection_set_dialup_iface (connection, dialup_iface); + nm_dialup_connection_set_ip4_config (connection, ip4_config); + + // m_system_dialup_device_set_from_ip4_config (connection->named_manager, + // connection->dialup_iface, connection->ip4_config); + success = TRUE; + + return success; +} + + +void +nm_dialup_connection_deactivate (NMDialupConnection *connection) +{ + g_return_if_fail (connection != NULL); + + if (connection->dialup_iface) + { + nm_system_device_set_up_down_with_iface (connection->dialup_iface, FALSE); + nm_system_device_flush_routes_with_iface (connection->dialup_iface); + nm_system_device_flush_addresses_with_iface (connection->dialup_iface); + } + + if (connection->ip4_config) + { + /* Remove attributes of the dialup's IP4 Config */ + //nm_system_dialup_device_unset_from_ip4_config (connection->named_manager, connection->parent_dev, + // connection->dialup_iface, connection->ip4_config); + + /* Reset routes, nameservers, and domains of the currently active device */ + //nm_system_device_set_from_ip4_config (connection->parent_dev); + } + + nm_dialup_connection_set_ip4_config (connection, NULL); + nm_dialup_connection_set_dialup_iface (connection, NULL); +} + + +const char * +nm_dialup_connection_get_name (NMDialupConnection *connection) +{ + g_return_val_if_fail (connection != NULL, NULL); + + return connection->name; +} + + +const char * +nm_dialup_connection_get_user_name (NMDialupConnection *connection) +{ + g_return_val_if_fail (connection != NULL, NULL); + + return connection->user_name; +} + + +const char * +nm_dialup_connection_get_service_name (NMDialupConnection *connection) +{ + g_return_val_if_fail (connection != NULL, NULL); + + return connection->service_name; +} + + +static void +nm_dialup_connection_set_dialup_iface (NMDialupConnection *con, const char *dialup_iface) +{ + g_return_if_fail (con != NULL); + + if (con->dialup_iface) + { + g_free (con->dialup_iface); + con->dialup_iface = NULL; + } + + if (dialup_iface) + con->dialup_iface = g_strdup (dialup_iface); +} + + +static void +nm_dialup_connection_set_ip4_config (NMDialupConnection *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; + } +} diff --git a/src/dialup/manager/nm-dialup-connection.h b/src/dialup/manager/nm-dialup-connection.h new file mode 100644 index 0000000000..cdf49d6c73 --- /dev/null +++ b/src/dialup/manager/nm-dialup-connection.h @@ -0,0 +1,44 @@ +/* nm-dialup-connection.h - handle a single dialup connection within NetworkManager's framework + * + * Copyright (C) 2006 Tim Niemueller + * base on work Copyright (C) 2005 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, 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. + */ +#ifndef NM_DIALUP_CONNECTION_H +#define NM_DIALUP_CONNECTION_H + +#include "nm-device.h" +#include "nm-named-manager.h" + +typedef struct NMDialupConnection NMDialupConnection; + + +NMDialupConnection * nm_dialup_connection_new (const char *name, const char *user_name, const char *service_name, + NMNamedManager *named_manager, DBusConnection *dbus_connection); +void nm_dialup_connection_ref (NMDialupConnection *con); +void nm_dialup_connection_unref (NMDialupConnection *con); + +const char * nm_dialup_connection_get_name (NMDialupConnection *con); +const char * nm_dialup_connection_get_user_name (NMDialupConnection *con); +const char * nm_dialup_connection_get_service_name (NMDialupConnection *con); + +void nm_dialup_connection_activate (NMDialupConnection *con); +void nm_dialup_connection_deactivate (NMDialupConnection *con); + +gboolean nm_dialup_connection_set_config (NMDialupConnection *con, const char *dialup_iface, NMIP4Config *ip4_config); + +#endif /* NM_DIALUP_CONNECTION_H */ diff --git a/src/dialup/manager/nm-dialup-manager.c b/src/dialup/manager/nm-dialup-manager.c new file mode 100644 index 0000000000..39afc598c2 --- /dev/null +++ b/src/dialup/manager/nm-dialup-manager.c @@ -0,0 +1,640 @@ +/* nm-dialup-manager.c - handle dialup connections within NetworkManager's framework + * + * Copyright (C) 2006 Tim Niemueller + * based on work Copyright (C) 2005 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, 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. + */ + +#include <glib.h> +#include <stdio.h> +#include <string.h> +#include <dbus/dbus.h> +#include "nm-dialup-manager.h" +#include "NetworkManager.h" +#include "NetworkManagerMain.h" +#include "NetworkManagerDbus.h" +#include "NetworkManagerSystem.h" +#include "nm-dialup-act-request.h" +#include "nm-dialup-connection.h" +#include "nm-dbus-dialup.h" +#include "nm-utils.h" + +#define DIALUP_SERVICE_FILE_PATH SYSCONFDIR"/NetworkManager/dialup" + + + +struct NMDialupManager +{ + NMData * app_data; + GHashTable * service_table; + GSList * connections; + + NMDialupActRequest * act_req; +}; + +static void nm_dialup_manager_load_services (NMDialupManager *manager, GHashTable *table); + +/* + * nm_dialup_manager_new + * + * Create a new dialup manager instance. + * + */ +NMDialupManager * +nm_dialup_manager_new (NMData *app_data) +{ + NMDialupManager * manager; + + g_return_val_if_fail (app_data != NULL, NULL); + + manager = g_malloc0 (sizeof (NMDialupManager)); + manager->app_data = app_data; + + manager->service_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) nm_dialup_service_unref); + nm_dialup_manager_load_services (manager, manager->service_table); + + return manager; +} + + +/* + * nm_dialup_manager_dispose + * + * Release the dialup manager and all its data. + * + */ +void +nm_dialup_manager_dispose (NMDialupManager *manager) +{ + g_return_if_fail (manager != NULL); + + if (manager->act_req) + nm_dialup_manager_deactivate_dialup_connection (manager); + + g_slist_foreach (manager->connections, (GFunc) nm_dialup_connection_unref, NULL); + g_slist_free (manager->connections); + + g_hash_table_destroy (manager->service_table); + + memset (manager, 0, sizeof (NMDialupManager)); + g_free (manager); +} + + +/* + * nm_dialup_manager_find_connection_by_name + * + * Return the NMDialupConnection object associated with a particular name. + * + */ +NMDialupConnection * +nm_dialup_manager_find_connection_by_name (NMDialupManager *manager, const char *con_name) +{ + NMDialupConnection *con = NULL; + GSList *elt; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (con_name != NULL, NULL); + + for (elt = manager->connections; elt; elt = g_slist_next (elt)) + { + if ((con = (NMDialupConnection *)(elt->data))) + { + const char *search_name = nm_dialup_connection_get_name (con); + if (search_name && (strcmp (con_name, search_name) == 0)) + break; + } + con = NULL; + } + + return con; +} + + +NMDialupService * +nm_dialup_manager_find_service_by_name (NMDialupManager *manager, const char *service_name) +{ + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (service_name != NULL, NULL); + + return (NMDialupService *) g_hash_table_lookup (manager->service_table, service_name); +} + + +/* + * nm_dialup_manager_dialup_connection_list_copy + * + * Make a shallow copy of the Dialup connection list, should + * only be used by nm-dbus-dialup.c + * + */ +GSList * +nm_dialup_manager_dialup_connection_list_copy (NMDialupManager *manager) +{ + GSList * list; + GSList * elt; + + g_return_val_if_fail (manager != NULL, NULL); + + list = g_slist_copy (manager->connections); + for (elt = list; elt; elt = g_slist_next (elt)) + nm_dialup_connection_ref (elt->data); + + return list; +} + + +/* + * nm_dialup_manager_add_connection + * + * Add a new dialup connection if none already exits, otherwise update the existing one. + * + */ +NMDialupConnection * +nm_dialup_manager_add_connection (NMDialupManager *manager, const char *name, const char *service_name, const char *user_name) +{ + NMDialupConnection * connection = NULL; + NMDialupService * service; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (user_name != NULL, NULL); + + /* Verify that the service name we are adding is in our allowed list */ + if (!(service = nm_dialup_manager_find_service_by_name (manager, service_name))) + { + nm_info ("Could not find service %s by name", service_name); + return NULL; + } + + if ((connection = nm_dialup_connection_new (name, user_name, service_name, manager->app_data->named_manager, + manager->app_data->dbus_connection))) + { + GSList *elt; + + /* Remove the existing connection if found */ + for (elt = manager->connections; elt; elt = g_slist_next (elt)) + { + NMDialupConnection *con = (NMDialupConnection *)(elt->data); + + if (con && nm_dialup_connection_get_name (con) && (strcmp (nm_dialup_connection_get_name (con), name) == 0)) + { + manager->connections = g_slist_remove_link (manager->connections, elt); + nm_dialup_connection_unref (con); + g_slist_free (elt); + } + } + + /* Add in the updated connection */ + manager->connections = g_slist_append (manager->connections, connection); + } + else + { + nm_info ("Could not create new connection, constructor failed"); + } + + return connection; +} + + +/* + * nm_dialup_manager_remove_connection + * + * Remove a dialup connection. + * + */ +void +nm_dialup_manager_remove_connection (NMDialupManager *manager, NMDialupConnection *dialup) +{ + g_return_if_fail (manager != NULL); + g_return_if_fail (dialup != NULL); + + /* If this Dialup is currently active, kill it */ + if (manager->act_req && (nm_dialup_act_request_get_connection (manager->act_req) == dialup)) + { + NMDialupService * service = nm_dialup_act_request_get_service (manager->act_req); + NMDialupConnection * v = nm_dialup_act_request_get_connection (manager->act_req); + + nm_dialup_connection_deactivate (v); + nm_dialup_service_stop_connection (service, manager->act_req); + + nm_dialup_act_request_unref (manager->act_req); + manager->act_req = NULL; + } + + manager->connections = g_slist_remove (manager->connections, dialup); + nm_dialup_connection_unref (dialup); +} + + +/* + * nm_dialup_manager_get_connection_names + * + * Return an array of strings of all the dialup Connection names + * we know about. + * + */ +char ** +nm_dialup_manager_get_connection_names (NMDialupManager *manager) +{ + char **names = NULL; + GSList *elt; + int i; + + g_return_val_if_fail (manager != NULL, NULL); + + names = g_malloc0 ((g_slist_length (manager->connections) + 1) * sizeof (char *)); + for (elt = manager->connections, i = 0; elt; elt = g_slist_next (elt), i++) + { + NMDialupConnection *dialup_con = (NMDialupConnection *)(elt->data); + if (dialup_con) + names[i] = g_strdup (nm_dialup_connection_get_name (dialup_con)); + } + + return names; +} + + +/* + * nm_dialup_manager_get_dialup_act_request + * + * Return the dialup activation request, if any. + * + */ +NMDialupActRequest * +nm_dialup_manager_get_dialup_act_request (NMDialupManager *manager) +{ + g_return_val_if_fail (manager != NULL, NULL); + + return manager->act_req; +} + + +static inline gboolean +same_service_name (NMDialupService *service, NMDialupConnection *dialup) +{ + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (dialup != NULL, FALSE); + + return (!strcmp (nm_dialup_service_get_service_name (service), nm_dialup_connection_get_service_name (dialup))); +} + + +/* + * nm_dialup_manager_process_signal + * + * Possibly process a signal from the bus, if it comes from the currently + * active dialup daemon, if any. Return TRUE if processed, FALSE if not. + * + */ +gboolean +nm_dialup_manager_process_signal (NMDialupManager *manager, DBusMessage *message) +{ + const char * service_name; + NMDialupService * service; + gboolean handled = FALSE; + + g_return_val_if_fail (manager != NULL, FALSE); + g_return_val_if_fail (message != NULL, FALSE); + + service_name = dbus_message_get_interface (message); + if ((service = nm_dialup_manager_find_service_by_name (manager, service_name))) + { + nm_dialup_service_process_signal (service, manager->act_req, message); + handled = TRUE; + } + + return handled; +} + + +/* + * nm_dialup_manager_process_name_owner_changed + * + * Respond to "service created"/"service deleted" signals from dbus for our active dialup daemon. + * + */ +gboolean +nm_dialup_manager_process_name_owner_changed (NMDialupManager *manager, + const char *changed_service_name, + const char *old_owner, const char *new_owner) +{ + NMDialupService * service; + gboolean handled = FALSE; + + g_return_val_if_fail (manager != NULL, FALSE); + g_return_val_if_fail (changed_service_name != NULL, FALSE); + + if ((service = nm_dialup_manager_find_service_by_name (manager, changed_service_name))) + { + nm_dialup_service_name_owner_changed (service, manager->act_req, old_owner, new_owner); + handled = TRUE; + } + + return handled; +} + + +/* + * nm_dialup_manager_activate_dialup_connection + * + * Signal the dialup service daemon to activate a particular dialup connection, + * launching that daemon if necessary. + * + */ +void +nm_dialup_manager_activate_dialup_connection (NMDialupManager *manager, + NMDialupConnection *dialup, + char **password_items, int password_count, + char **data_items, int data_count) +{ + NMDevice * old_dev; + NMDialupActRequest * req; + NMDialupService * service; + const char * service_name; + + g_return_if_fail (manager != NULL); + g_return_if_fail (dialup != NULL); + g_return_if_fail (password_items != NULL); + g_return_if_fail (data_items != NULL); + + if (nm_dialup_manager_get_dialup_act_request (manager)) + nm_dialup_manager_deactivate_dialup_connection (manager); + + service_name = nm_dialup_connection_get_service_name (dialup); + if (!(service = nm_dialup_manager_find_service_by_name (manager, service_name))) + return; + + req = nm_dialup_act_request_new (manager, service, dialup, password_items, password_count, data_items, data_count); + manager->act_req = req; + + if ((old_dev = nm_get_active_device (manager->app_data))) + nm_device_deactivate (old_dev); + + nm_dialup_service_start_connection (service, req); +} + + +/* + * nm_dialup_manager_deactivate_dialup_connection + * + * Signal the dialup service daemon to deactivate a particular dialup connection. + * + */ +void +nm_dialup_manager_deactivate_dialup_connection (NMDialupManager *manager) +{ + NMDialupService * service; + NMDialupConnection * dialup; + + g_return_if_fail (manager != NULL); + + if (!manager->act_req) + return; + + if (nm_dialup_act_request_is_activating (manager->act_req) + || nm_dialup_act_request_is_activated (manager->act_req) + || nm_dialup_act_request_is_failed (manager->act_req)) + { + if (nm_dialup_act_request_is_activated (manager->act_req)) + { + dialup = nm_dialup_act_request_get_connection (manager->act_req); + g_assert (dialup); + nm_dialup_connection_deactivate (dialup); + } + + service = nm_dialup_act_request_get_service (manager->act_req); + g_assert (service); + nm_dialup_service_stop_connection (service, manager->act_req); + } + + nm_dialup_act_request_unref (manager->act_req); + manager->act_req = NULL; + + // Signal that we are disconnected + nm_schedule_state_change_signal_broadcast (manager->app_data); +} + + +static gboolean +nm_dialup_manager_dialup_activation_failed (gpointer user_data) +{ + NMDialupActRequest * req = (NMDialupActRequest *) user_data; + NMDialupManager * manager; + + g_assert (req); + + manager = nm_dialup_act_request_get_manager (req); + g_assert (manager); + + if (manager->act_req == req) + nm_dialup_manager_deactivate_dialup_connection (manager); + + return FALSE; +} + + +void +nm_dialup_manager_schedule_dialup_activation_failed (NMDialupManager *manager, NMDialupActRequest *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_dialup_manager_dialup_activation_failed, req, NULL); + g_source_attach (source, manager->app_data->main_context); + g_source_unref (source); +} + + +static gboolean +nm_dialup_manager_dialup_connection_died (gpointer user_data) +{ + NMDialupActRequest * req = (NMDialupActRequest *) user_data; + NMDialupManager * manager; + + g_assert (req); + + manager = nm_dialup_act_request_get_manager (req); + g_assert (manager); + + if (manager->act_req == req) + nm_dialup_manager_deactivate_dialup_connection (manager); + + return FALSE; +} + + +void +nm_dialup_manager_schedule_dialup_connection_died (NMDialupManager *manager, NMDialupActRequest *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_dialup_manager_dialup_connection_died, req, NULL); + g_source_attach (source, manager->app_data->main_context); + g_source_unref (source); +} + +gboolean +nm_dialup_manager_is_connecting (NMDialupManager *manager) +{ + if (!manager->act_req) + return FALSE; + else + return nm_dialup_act_request_is_activating (manager->act_req); +} + + +gboolean +nm_dialup_manager_is_connected (NMDialupManager *manager) +{ + if (!manager->act_req) + return FALSE; + else + return nm_dialup_act_request_is_activated (manager->act_req); +} + + +/*********************************************************************/ + +static void +nm_dialup_manager_load_services (NMDialupManager *manager, GHashTable *table) +{ + GSList *list = NULL; + GDir *dialup_dir; + + g_return_if_fail (manager != NULL); + g_return_if_fail (table != NULL); + + /* Load allowed service names */ + if ((dialup_dir = g_dir_open (DIALUP_SERVICE_FILE_PATH, 0, NULL))) + { + const char *file_name; + + while ((file_name = g_dir_read_name (dialup_dir))) + { + char *file_path = g_strdup_printf (DIALUP_SERVICE_FILE_PATH"/%s", file_name); + char *contents; + + if (g_file_get_contents (file_path, &contents, NULL, NULL) && (contents != NULL)) + { + char **split_contents = g_strsplit (contents, "\n", 0); + + if (split_contents) + { + int i, len; + NMDialupService * service = nm_dialup_service_new (manager, manager->app_data); + gboolean have_name = FALSE; + gboolean have_service = FALSE; + gboolean have_program = FALSE; + + len = g_strv_length (split_contents); + for (i = 0; i < len; i++) + { + char *line = split_contents[i]; + +#define NAME_TAG "name=" +#define SERVICE_TAG "service=" +#define PROGRAM_TAG "program=" + + if (!line || !strlen (line)) continue; + + /* Comment lines begin with # */ + if (line[0] == '#') continue; + + if ((strncmp (line, NAME_TAG, strlen (NAME_TAG)) == 0) && !have_name) + { + char * name = g_strdup (line+strlen (NAME_TAG)); + GSList * dup_elt; + gboolean found = FALSE; + + for (dup_elt = list; dup_elt; dup_elt = g_slist_next (dup_elt)) + { + NMDialupService *dup_svc = (NMDialupService *)(dup_elt->data); + if (dup_svc && nm_dialup_service_get_name (dup_svc) && !strcmp (nm_dialup_service_get_name (dup_svc), name)) + { + found = TRUE; + break; + } + } + if (!found) + nm_dialup_service_set_name (service, (const char *)name); + g_free (name); + have_name = TRUE; + } + else if ((strncmp (line, SERVICE_TAG, strlen (SERVICE_TAG)) == 0) && !have_service) + { + char *service_name = g_strdup (line+strlen (SERVICE_TAG)); + + /* Deny the load if the service name is NetworkManager or NetworkManagerInfo. */ + if (strcmp (service_name, NM_DBUS_SERVICE) && strcmp (service_name, NM_DBUS_SERVICE)) + nm_dialup_service_set_service_name (service, (const char *)service_name); + else + nm_warning ("dialup service name matched NetworkManager or NetworkManagerInfo service names, " + "which is not allowed and might be malicious."); + g_free (service_name); + have_service = TRUE; + } + else if ((strncmp (line, PROGRAM_TAG, strlen (PROGRAM_TAG)) == 0) && !have_program) + { + gboolean program_ok = FALSE; + if ((strlen (line) >= strlen (PROGRAM_TAG) + 1)) + { + if ((*(line+strlen (PROGRAM_TAG)) == '/') && (*(line+strlen (line)-1) != '/')) + { + nm_dialup_service_set_program (service, (const char *)(line+strlen (PROGRAM_TAG))); + program_ok = TRUE; + } + } + if (!program_ok) + nm_warning ("WARNING: dialup program '%s' invalid in file '%s'", line, file_path); + have_program = TRUE; + } + } + g_strfreev (split_contents); + + if (nm_dialup_service_get_name (service) && + nm_dialup_service_get_service_name (service) && + nm_dialup_service_get_program (service) && + ! g_hash_table_lookup(table, (char *) nm_dialup_service_get_service_name (service)) + ) + + { + nm_info ("Adding dialup service '%s' with name '%s' and program '%s'", + nm_dialup_service_get_service_name (service), + nm_dialup_service_get_name (service), + nm_dialup_service_get_program (service)); + g_hash_table_insert (table, (char *) nm_dialup_service_get_service_name (service), service); + } + else + nm_dialup_service_unref (service); + } + g_free (contents); + } + g_free (file_path); + } + + g_dir_close (dialup_dir); + } +} diff --git a/src/dialup/manager/nm-dialup-manager.h b/src/dialup/manager/nm-dialup-manager.h new file mode 100644 index 0000000000..fceb1ebbd1 --- /dev/null +++ b/src/dialup/manager/nm-dialup-manager.h @@ -0,0 +1,56 @@ +/* nm-dialup-manager.h - handle dialup connections within NetworkManager's framework + * + * Copyright (C) 2006 Tim Niemueller + * based on work Copyright (C) 2005 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, 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. + */ +#ifndef NM_DIALUP_MANAGER_H +#define NM_DIALUP_MANAGER_H + +#include <dbus/dbus.h> +#include "NetworkManagerMain.h" +#include "nm-dialup-connection.h" +#include "nm-dialup-service.h" + + +NMDialupManager * nm_dialup_manager_new (NMData *app_data); +NMDialupConnection * nm_dialup_manager_add_connection (NMDialupManager *manager, const char *name, const char *service_name, const char *user_name); +void nm_dialup_manager_remove_connection (NMDialupManager *manager, NMDialupConnection *dialup); +char ** nm_dialup_manager_get_connection_names (NMDialupManager *manager); +void nm_dialup_manager_dispose (NMDialupManager *manager); + +NMDialupActRequest * nm_dialup_manager_get_dialup_act_request (NMDialupManager *manager); + +GSList * nm_dialup_manager_dialup_connection_list_copy (NMDialupManager *manager); + +void nm_dialup_manager_activate_dialup_connection (NMDialupManager *manager, NMDialupConnection *dialup, char **password_items, + int password_count, char **data_items, int data_count ); +void nm_dialup_manager_deactivate_dialup_connection (NMDialupManager *manager); + +NMDialupConnection * nm_dialup_manager_find_connection_by_name (NMDialupManager *manager, const char *con_name); +NMDialupService * nm_dialup_manager_find_service_by_name (NMDialupManager *manager, const char *service_name); + +gboolean nm_dialup_manager_process_signal (NMDialupManager *manager, DBusMessage *signal); +gboolean nm_dialup_manager_process_name_owner_changed (NMDialupManager *manager, const char *service, const char *old_owner, const char *new_owner); + +void nm_dialup_manager_schedule_dialup_activation_failed(NMDialupManager *manager, NMDialupActRequest *req); +void nm_dialup_manager_schedule_dialup_connection_died (NMDialupManager *manager, NMDialupActRequest *req); + +gboolean nm_dialup_manager_is_connecting (NMDialupManager *manager); +gboolean nm_dialup_manager_is_connected (NMDialupManager *manager); + +#endif /* NM_DIALUP_MANAGER_H */ diff --git a/src/dialup/manager/nm-dialup-service.c b/src/dialup/manager/nm-dialup-service.c new file mode 100644 index 0000000000..fd81b38420 --- /dev/null +++ b/src/dialup/manager/nm-dialup-service.c @@ -0,0 +1,1087 @@ +/* NetworkManager -- Network link manager + * + * Tim Niemueller [www.niemueller.de] + * based on work by Dan Williams <dcbw@redhat.com> + * + * 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. + * (C) Copyright 2006 Tim Niemueller + */ + +#include <glib.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <dbus/dbus.h> +#include "NetworkManagerDbus.h" +#include "NetworkManagerMain.h" +#include "nm-dbus-dialup.h" +#include "nm-dialup-service.h" +#include "nm-dialup-act-request.h" +#include "nm-utils.h" + +/* define this for getting dialup debug messages */ +#undef NM_DEBUG_DIALUP_CONFIG + +struct NMDialupService +{ + int refcount; + NMDialupManager * manager; + NMData * app_data; + gboolean watch_active; + + char * name; + char * service; + char * program; + NMDialupState state; +}; + + +static void nm_dialup_service_add_watch (NMDialupService *service); +static void nm_dialup_service_remove_watch (NMDialupService *service); +static void nm_dialup_service_stop_connection_internal (NMDialupService *service); +#ifdef NM_DEBUG_DIALUP_CONFIG +static void print_dialup_config (guint32 ip4_dialup_gateway, + const char *dev, + guint32 ip4_address, + guint32 ip4_ptp_address, + gint32 ip4_netmask, + guint32 *ip4_dns, + guint32 ip4_dns_len, + guint32 *ip4_nbns); +#endif + +static void nm_dialup_service_schedule_stage1_daemon_exec (NMDialupService *service, NMDialupActRequest *req); +static void nm_dialup_service_schedule_stage3_connect (NMDialupService *service, NMDialupActRequest *req); +static void nm_dialup_service_schedule_stage2_daemon_wait (NMDialupService *service, NMDialupActRequest *req); +static void nm_dialup_service_schedule_stage4_ip_config_get_timeout (NMDialupService *service, NMDialupActRequest *req); +static void nm_dialup_service_cancel_callback (NMDialupService *service, NMDialupActRequest *req); + + +/* + * nm_dialup_service_new + * + * Create a new DialupService object + * + */ +NMDialupService *nm_dialup_service_new (NMDialupManager *manager, NMData *app_data) +{ + NMDialupService *service = g_malloc0 (sizeof (NMDialupService)); + + service->refcount = 1; + service->state = NM_DIALUP_STATE_SHUTDOWN; + service->app_data = app_data; + service->manager = manager; + + return service; +} + +void nm_dialup_service_ref (NMDialupService *service) +{ + g_return_if_fail (service != NULL); + + service->refcount++; +} + + +void nm_dialup_service_unref (NMDialupService *service) +{ + g_return_if_fail (service != NULL); + + service->refcount--; + if (service->refcount <= 0) + { + g_free (service->name); + g_free (service->service); + g_free (service->program); + memset (service, 0, sizeof (NMDialupService)); + g_free (service); + } +} + + +const char *nm_dialup_service_get_name (NMDialupService *service) +{ + g_return_val_if_fail (service != NULL, NULL); + + return service->name; +} + + +void nm_dialup_service_set_name (NMDialupService *service, const char *name) +{ + g_return_if_fail (service != NULL); + + if (service->name) + g_free (service->name); + service->name = g_strdup (name); +} + + +const char *nm_dialup_service_get_service_name (NMDialupService *service) +{ + g_return_val_if_fail (service != NULL, NULL); + + return service->service; +} + + +void nm_dialup_service_set_service_name (NMDialupService *service, const char *name) +{ + g_return_if_fail (service != NULL); + + if (service->service) + g_free (service->service); + service->service = g_strdup (name); + + /* If the Dialup daemon is currently running, tell it to stop */ + if (!dbus_bus_name_has_owner (service->app_data->dbus_connection, service->service, NULL)) + nm_dialup_service_stop_connection_internal (service); +} + + +const char *nm_dialup_service_get_program (NMDialupService *service) +{ + g_return_val_if_fail (service != NULL, NULL); + + return service->program; +} + + +void nm_dialup_service_set_program (NMDialupService *service, const char *program) +{ + g_return_if_fail (service != NULL); + + if (service->program) + g_free (service->program); + service->program = g_strdup (program); +} + + +NMDialupState nm_dialup_service_get_state (NMDialupService *service) +{ + g_return_val_if_fail (service != NULL, NM_DIALUP_STATE_UNKNOWN); + + return service->state; +} + + +static void nm_dialup_service_set_state (NMDialupService *service, const NMDialupState state) +{ + g_return_if_fail (service != NULL); + + service->state = state; +} + + +DBusConnection *nm_dialup_service_get_dbus_connection (NMDialupService *service) +{ + g_return_val_if_fail (service != NULL, NULL); + + return service->app_data->dbus_connection; +} + + +/* + * 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_dialup_service_act_request_failed + * + * Clean up after an activation request and tell the dialup manager that it + * has failed. + * + */ +static void nm_dialup_service_act_request_failed (NMDialupService *service, + NMDialupActRequest *req) +{ + NMDialupConnection *dialup; + + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + /* Sanity checks */ + if (nm_dialup_act_request_get_service (req) != service) + return; + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_service_cancel_callback (service, req); + + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_FAILED); + nm_info ("Dialup Activation (%s) failed.", nm_dialup_connection_get_name (dialup)); + + nm_dialup_act_request_unref (req); + nm_dialup_manager_schedule_dialup_activation_failed (service->manager, req); + + // Signal that we are not connected + nm_schedule_state_change_signal_broadcast (service->app_data); +} + + +static void nm_dialup_service_activation_success (NMDialupService *service, NMDialupActRequest *req) +{ + NMDialupConnection * dialup = NULL; + + g_assert (service != NULL); + g_assert (req != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_service_cancel_callback (service, req); + + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_ACTIVATED); + nm_info ("Dialup Activation (%s) successful.", nm_dialup_connection_get_name (dialup)); + + // Signal that we are connected + nm_schedule_state_change_signal_broadcast (service->app_data); +} + + +/* + * nm_dialup_service_start_connection + * + * Kick off the dialup connection process. + * + */ +void nm_dialup_service_start_connection (NMDialupService *service, NMDialupActRequest *req) +{ + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_PREPARE); + nm_dialup_service_add_watch (service); + + /* Start the daemon if it's not already running */ + nm_dialup_act_request_ref (req); + + // Signal that we are connecting + nm_schedule_state_change_signal_broadcast (service->app_data); + + if (!dbus_bus_name_has_owner (service->app_data->dbus_connection, service->service, NULL)) + nm_dialup_service_schedule_stage1_daemon_exec (service, req); + else + nm_dialup_service_schedule_stage2_daemon_wait (service, req); +} + + +/* + * nm_dialup_service_stage_1_daemon_exec + * + * Execute the dialup service daemon. + * + */ +static gboolean nm_dialup_service_stage1_daemon_exec (gpointer user_data) +{ + NMDialupActRequest * req = (NMDialupActRequest *) user_data; + NMDialupService * service; + NMDialupConnection * dialup = NULL; + GPtrArray * dialup_argv; + GError * error = NULL; + GPid pid; + + g_assert (req != NULL); + + service = nm_dialup_act_request_get_service (req); + g_assert (service != NULL); + g_assert (service->program != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_act_request_set_callback_id (req, 0); + + dialup_argv = g_ptr_array_new (); + g_ptr_array_add (dialup_argv, service->program); + g_ptr_array_add (dialup_argv, NULL); + + if (!g_spawn_async (NULL, (char **) dialup_argv->pdata, NULL, 0, NULL, NULL, &pid, &error)) + { + g_ptr_array_free (dialup_argv, TRUE); + nm_warning ("(Dialup Service %s): could not launch the dialup service. error: '%s'.", service->service, error->message); + g_error_free (error); + nm_dialup_service_act_request_failed (service, req); + goto out; + } + g_ptr_array_free (dialup_argv, TRUE); + nm_info ("Dialup Activation (%s) Stage 1 of 4 (Connection Prepare) ran dialup service daemon %s (PID %d)", + nm_dialup_connection_get_name (dialup), service->service, pid); + nm_info ("Dialup Activation (%s) Stage 1 of 4 (Connection Prepare) complete.", + nm_dialup_connection_get_name (dialup)); + + nm_dialup_service_schedule_stage2_daemon_wait (service, req); + +out: + return FALSE; +} + + +static void nm_dialup_service_schedule_stage1_daemon_exec (NMDialupService *service, NMDialupActRequest *req) +{ + GSource * source = NULL; + NMDialupConnection * dialup = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_PREPARE); + nm_dialup_service_set_state (service, NM_DIALUP_STATE_SHUTDOWN); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_dialup_service_stage1_daemon_exec, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_dialup_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("Dialup Activation (%s) Stage 1 of 4 (Connection Prepare) scheduled...", nm_dialup_connection_get_name (dialup)); +} + + +/* + * nm_dialup_service_stage2_daemon_wait + * + * Wait until the dialup daemon has become active. + * + */ +static gboolean nm_dialup_service_stage2_daemon_wait (gpointer user_data) +{ + NMDialupActRequest * req = (NMDialupActRequest *) user_data; + NMDialupService * service; + NMDialupConnection * dialup = NULL; + gboolean service_exists = FALSE; + + g_assert (req != NULL); + + service = nm_dialup_act_request_get_service (req); + g_assert (service != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_act_request_set_callback_id (req, 0); + + nm_info ("Dialup Activation (%s) Stage 2 of 4 (Connection Prepare Wait) " + "waiting...", nm_dialup_connection_get_name (dialup)); + + service_exists = dbus_bus_name_has_owner (service->app_data->dbus_connection, + service->service, NULL); + if (service_exists && (service->state == NM_DIALUP_STATE_STOPPED)) + { + nm_info ("Dialup Activation (%s) Stage 2 of 4 (Connection Prepare Wait) " + "complete.", nm_dialup_connection_get_name (dialup)); + nm_dialup_service_schedule_stage3_connect (service, req); + } + else if (nm_dialup_act_request_get_daemon_wait_count (req) > 10) + { + /* We only wait 2s (10 * 200 milliseconds) for the service to + * become available. + */ + nm_dialup_service_act_request_failed (service, req); + } + else + nm_dialup_service_schedule_stage2_daemon_wait (service, req); + + return FALSE; +} + + +static void nm_dialup_service_schedule_stage2_daemon_wait (NMDialupService *service, NMDialupActRequest *req) +{ + GSource * source = NULL; + NMDialupConnection * dialup = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_PREPARE); + + nm_dialup_act_request_set_daemon_wait_count (req, nm_dialup_act_request_get_daemon_wait_count (req) + 1); + + source = g_timeout_source_new (200); + g_source_set_callback (source, (GSourceFunc) nm_dialup_service_stage2_daemon_wait, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_dialup_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("Dialup Activation (%s) Stage 2 of 4 (Connection Prepare Wait) scheduled...", nm_dialup_connection_get_name (dialup)); +} + + +static void nm_dialup_service_stage3_connect_cb (DBusPendingCall *pcall, void *user_data) +{ + DBusMessage * reply; + NMDialupActRequest * req = (NMDialupActRequest *) user_data; + NMDialupService * service; + NMDialupConnection * dialup; + + g_assert (pcall != NULL); + g_assert (req != NULL); + + service = nm_dialup_act_request_get_service (req); + g_assert (service != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_info ("Dialup Activation (%s) Stage 3 of 4 (Connect) reply received.", + nm_dialup_connection_get_name (dialup)); + + if (!(reply = dbus_pending_call_steal_reply (pcall))) + { + nm_warning ("(Dialup Service %s): could not obtain dialup service's reply.", + service->service); + nm_dialup_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 ("(Dialup Service %s): could not start the dialup '%s'. dbus says: '%s' '%s'.", + service->service, nm_dialup_connection_get_name (dialup), member, message); + nm_dialup_service_act_request_failed (service, req); + } + else + { + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_IP_CONFIG_GET); + nm_dialup_service_schedule_stage4_ip_config_get_timeout (service, req); + nm_info ("Dialup Activation (%s) Stage 3 of 4 (Connect) complete, " + "waiting for IP configuration...", nm_dialup_connection_get_name (dialup)); + } + + dbus_message_unref (reply); + +out: + dbus_pending_call_unref (pcall); +} + + +static char ** +sanitize_dbus_string_array (char **in_array, dbus_uint32_t *in_num) +{ + char ** out_array; + + g_return_val_if_fail (in_num != NULL, NULL); + + if (in_array) + return in_array; + + out_array = g_malloc0 (sizeof (char *)); + out_array[0] = g_strdup (""); + *in_num = 1; + return out_array; +} + + +static gboolean nm_dialup_service_stage3_connect (gpointer user_data) +{ + NMDialupActRequest * req = (NMDialupActRequest *) user_data; + NMDialupService * service; + NMDialupConnection * dialup; + 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; + DBusMessage * message; + DBusPendingCall * pcall = NULL; + + g_assert (req != NULL); + + service = nm_dialup_act_request_get_service (req); + g_assert (service != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup != NULL); + + nm_dialup_act_request_set_callback_id (req, 0); + + /* Send the start dialup 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 ("(Dialup Service %s): couldn't allocate dbus message.", service->service); + nm_dialup_service_act_request_failed (service, req); + return FALSE; + } + + name = nm_dialup_connection_get_name (dialup); + user_name = nm_dialup_connection_get_user_name (dialup); + password_items = (char **) nm_dialup_act_request_get_password_items (req, &password_count); + data_items = (char **) nm_dialup_act_request_get_data_items (req, &data_count); + + /* Ensure that data_items are safe to put through dbus */ + data_items = sanitize_dbus_string_array (data_items, &data_count); + + nm_info ("Dialup Activation (%s) Stage 3 of 4 (Connect) sending connect request.", + nm_dialup_connection_get_name (dialup)); + dbus_message_append_args (message, + DBUS_TYPE_STRING, &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_dialup_service_stage3_connect_cb, req, NULL); + nm_info ("Dialup Activation (%s) Stage 3 of 4 (Connect) request sent," + " waiting for reply...", nm_dialup_connection_get_name (dialup)); + } + else + nm_dialup_service_act_request_failed (service, req); + dbus_message_unref (message); + + return FALSE; +} + + +static void nm_dialup_service_schedule_stage3_connect (NMDialupService *service, NMDialupActRequest *req) +{ + GSource * source = NULL; + NMDialupConnection * dialup = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_CONNECT); + + source = g_idle_source_new (); + g_source_set_callback (source, (GSourceFunc) nm_dialup_service_stage3_connect, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_dialup_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("Dialup Activation (%s) Stage 3 of 4 (Connect) scheduled...", nm_dialup_connection_get_name (dialup)); +} + + +static gboolean nm_dialup_service_stage4_ip_config_get_timeout (gpointer *user_data) +{ + NMDialupActRequest * req = (NMDialupActRequest *) user_data; + NMDialupService * service; + NMDialupConnection * dialup; + + g_assert (req != NULL); + + service = nm_dialup_act_request_get_service (req); + g_assert (service != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup != NULL); + + nm_dialup_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_dialup_act_request_get_stage (req) == NM_DIALUP_ACT_STAGE_IP_CONFIG_GET) + { + nm_info ("Dialup Activation (%s) Stage 4 of 4 (IP Config Get) timeout exceeded.", nm_dialup_connection_get_name (dialup)); + nm_dialup_service_act_request_failed (service, req); + } + + return FALSE; +} + + +static void nm_dialup_service_schedule_stage4_ip_config_get_timeout (NMDialupService *service, NMDialupActRequest *req) +{ + GSource * source = NULL; + NMDialupConnection * dialup = NULL; + guint id; + + g_assert (service != NULL); + g_assert (req != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_IP_CONFIG_GET); + + /* 20 second timeout waiting for IP config signal from dialup service */ + source = g_timeout_source_new (20000); + g_source_set_callback (source, (GSourceFunc) nm_dialup_service_stage4_ip_config_get_timeout, req, NULL); + id = g_source_attach (source, service->app_data->main_context); + nm_dialup_act_request_set_callback_id (req, id); + g_source_unref (source); + nm_info ("Dialup Activation (%s) Stage 4 of 4 (IP Config Get) timeout scheduled...", nm_dialup_connection_get_name (dialup)); +} + + +static void nm_dialup_service_cancel_callback (NMDialupService *service, NMDialupActRequest *req) +{ + guint id; + + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + if ((id = nm_dialup_act_request_get_callback_id (req)) != 0) + { + g_source_destroy (g_main_context_find_source_by_id (service->app_data->main_context, id)); + nm_dialup_act_request_set_callback_id (req, 0); + } +} + + +static gboolean +get_dbus_guint32_helper (DBusMessageIter *iter, + guint32 *num, + char *desc) +{ + if (!dbus_message_iter_next (iter) + || (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_UINT32)) + { + nm_warning ("Error: couldn't get %s from dialup IP Config message.", desc); + return FALSE; + } + dbus_message_iter_get_basic (iter, num); + return TRUE; +} + +/* +static gboolean +get_dbus_string_helper (DBusMessageIter *iter, + char **str, + char *desc) +{ + if (!dbus_message_iter_next (iter) + || (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_STRING)) + { + nm_warning ("Error: couldn't get %s from dialup IP Config message.", desc); + return FALSE; + } + dbus_message_iter_get_basic (iter, str); + return TRUE; +} +*/ + +/* + * nm_dialup_service_stage4_ip_config_get + * + * Configure a device with IPv4 config info in response the the dialup daemon. + * + */ +static void +nm_dialup_service_stage4_ip_config_get (NMDialupService *service, + NMDialupActRequest *req, + DBusMessage *message) +{ + NMDialupConnection * dialup; + guint32 num; + char * dev; + gboolean success = FALSE; + DBusMessageIter iter; + DBusMessageIter subiter; + NMIP4Config * config; + + g_return_if_fail (service != NULL); + g_return_if_fail (message != NULL); + g_return_if_fail (req != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_info ("Dialup Activation (%s) Stage 4 of 4 (IP Config Get) reply received.", + nm_dialup_connection_get_name (dialup)); + + config = nm_ip4_config_new (); + nm_ip4_config_set_secondary (config, TRUE); + + dbus_message_iter_init (message, &iter); + + /* First arg: device (STRING) */ + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) + { + nm_warning ("Error: couldn't get dialup device from dialup IP config message."); + goto out; + } + dbus_message_iter_get_basic (&iter, &dev); + + /* Second arg: IP4 dialup gateway address (UINT32) */ + if (!get_dbus_guint32_helper (&iter, &num, "IP4 gateway")) + goto out; + nm_ip4_config_set_gateway (config, num); + + /* Third arg: IP4 dialup Local Address (UINT32) */ + if (!get_dbus_guint32_helper (&iter, &num, "IP4 dialup Local Address")) + goto out; + nm_ip4_config_set_address (config, num); + + /* Fourth arg: IP4 dialup Point-to-Point Address (UINT32) */ + if (!get_dbus_guint32_helper (&iter, &num, "IP4 dialup PtP Address")) + goto out; + nm_ip4_config_set_ptp_address (config, num); + + /* Fifth arg: IP4 dialup Local Netmask (UINT32) */ + if (!get_dbus_guint32_helper (&iter, &num, "IP4 dialup Local Netmask")) + goto out; + /* If no netmask, default to Class C address */ + nm_ip4_config_set_netmask (config, num ? num : 0x00FF); + + /* Sixth arg: IP4 DNS Server Addresses (ARRAY, UINT32) */ + if ( !dbus_message_iter_next (&iter) + || (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)) + { + nm_warning ("Error: couldn't get IP4 DNS Server Addresses" + " from dialup IP Config message."); + goto out; + } + dbus_message_iter_recurse (&iter, &subiter); + while (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_UINT32) + { + dbus_message_iter_get_basic (&subiter, &num); + if (num) + nm_ip4_config_add_nameserver (config, num); + dbus_message_iter_next (&subiter); + } + + /* Seventh arg: IP4 NBNS Server Addresses (ARRAY, UINT32) */ + if ( !dbus_message_iter_next (&iter) + || (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY)) + { + nm_warning ("Error: couldn't get IP4 NBNS Server Addresses" + " from dialup IP Config message."); + goto out; + } + dbus_message_iter_recurse (&iter, &subiter); + while (dbus_message_iter_get_arg_type (&subiter) == DBUS_TYPE_UINT32) + { + dbus_message_iter_get_basic (&subiter, &num); + /* We don't do anything with these yet */ + dbus_message_iter_next (&subiter); + } + + /* Ninth arg: DNS Domain (STRING) + if (!get_dbus_string_helper (&iter, &str, "DNS Domain")) + goto out; + if (strlen (str)) + nm_ip4_config_add_domain (config, str); + */ + + +#ifdef NM_DEBUG_DIALUP_CONFIG + print_dialup_config (ip4_dialup_gateway, + dev, + ip4_address, + ip4_ptp_address, + ip4_netmask, + ip4_dns, + ip4_dns_len, + ip4_nbns, + ip4_nbns_len); +#endif + + if (nm_dialup_connection_set_config (dialup, dev, config)) + { + nm_info ("Dialup Activation (%s) Stage 4 of 4 (IP Config Get) complete.", + nm_dialup_connection_get_name (dialup)); + success = TRUE; + nm_dialup_service_activation_success (service, req); + } + +out: + if (!success) + { + nm_ip4_config_unref (config); + nm_warning ("(Dialup Service %s): did not receive valid IP config information.", service->service); + nm_dialup_service_act_request_failed (service, req); + } +} + + +static void nm_dialup_service_stop_connection_internal (NMDialupService *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 ("(Dialup Service %s): couldn't allocate dbus message.", service->service); + + g_free (op); +} + + +void nm_dialup_service_stop_connection (NMDialupService *service, NMDialupActRequest *req) +{ + NMDialupConnection *dialup; + + g_return_if_fail (service != NULL); + g_return_if_fail (req != NULL); + + dialup = nm_dialup_act_request_get_connection (req); + g_assert (dialup); + + nm_dialup_service_cancel_callback (service, req); + nm_dialup_act_request_set_stage (req, NM_DIALUP_ACT_STAGE_DISCONNECTED); + + /* Ensure we can stop the connection in this state */ + if ((service->state != NM_DIALUP_STATE_STARTED) && (service->state != NM_DIALUP_STATE_STARTING)) + { + nm_warning ("(Dialup Service %s): could not stop connection '%s' because service was %d.", + service->service, nm_dialup_connection_get_name (dialup), service->state); + return; + } + + nm_dialup_service_stop_connection_internal (service); + nm_dialup_service_set_state (service, NM_DIALUP_STATE_STOPPED); +} + + +static void nm_dialup_service_add_watch (NMDialupService *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_dialup_service_remove_watch (NMDialupService *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 (NMDialupService *service, NMDialupConnection *dialup) +{ + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (dialup != NULL, FALSE); + + return (!strcmp (nm_dialup_service_get_service_name (service), nm_dialup_connection_get_service_name (dialup))); +} + + +gboolean nm_dialup_service_name_owner_changed (NMDialupService *service, NMDialupActRequest *req, const char *old, const char *new) +{ + NMDialupConnection * dialup; + gboolean valid_dialup = FALSE; + gboolean old_owner_good = (old && strlen (old)); + gboolean new_owner_good = (new && strlen (new)); + + g_return_val_if_fail (service != NULL, FALSE); + + if (req && (dialup = nm_dialup_act_request_get_connection (req))) + valid_dialup = same_service_name (service, dialup); + + if (!old_owner_good && new_owner_good) + { + /* dialup service started. */ + nm_dialup_service_add_watch (service); + nm_dialup_service_set_state (service, NM_DIALUP_STATE_INIT); + } + else if (old_owner_good && !new_owner_good) + { + /* dialup service went away. */ + nm_dialup_service_set_state (service, NM_DIALUP_STATE_SHUTDOWN); + nm_dialup_service_remove_watch (service); + + if (valid_dialup) + { + nm_dialup_act_request_unref (req); + nm_dialup_manager_schedule_dialup_connection_died (service->manager, req); + } + } + + return TRUE; +} + + +gboolean nm_dialup_service_process_signal (NMDialupService *service, NMDialupActRequest *req, DBusMessage *message) +{ + NMDialupConnection * dialup = NULL; + gboolean valid_dialup = FALSE; + + g_return_val_if_fail (service != NULL, FALSE); + g_return_val_if_fail (message != NULL, FALSE); + + if (req && (dialup = nm_dialup_act_request_get_connection (req))) + valid_dialup = same_service_name (service, dialup); + + if ( dbus_message_is_signal (message, service->service, NM_DBUS_DIALUP_SIGNAL_LOGIN_FAILED) + || dbus_message_is_signal (message, service->service, NM_DBUS_DIALUP_SIGNAL_LAUNCH_FAILED) + || dbus_message_is_signal (message, service->service, NM_DBUS_DIALUP_SIGNAL_CONNECT_FAILED) + || dbus_message_is_signal (message, service->service, NM_DBUS_DIALUP_SIGNAL_DIALUP_CONFIG_BAD) + || dbus_message_is_signal (message, service->service, NM_DBUS_DIALUP_SIGNAL_IP_CONFIG_BAD)) + { + const char * member = dbus_message_get_member (message); + char * error_msg; + + if (valid_dialup) + { + if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) + error_msg = (char *) ""; + nm_warning ("Dialup failed for service '%s', signal '%s', with message '%s'.", service->service, member, error_msg); + nm_dbus_dialup_signal_dialup_failed (service->app_data->dbus_connection, member, dialup, error_msg); + /* Don't deal with dialup 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_DIALUP_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)) + { + NMDialupState old_state = (NMDialupState) old_state_int; + NMDialupState new_state = (NMDialupState) new_state_int; + + nm_info ("Dialup service '%s' signaled state change %d -> %d.", service->service, old_state, new_state); + nm_dialup_service_set_state (service, new_state); + + /* If the dialup daemon state is now stopped and it was starting, clear the active connection */ + if (((new_state == NM_DIALUP_STATE_STOPPED) || (new_state == NM_DIALUP_STATE_SHUTDOWN) || (new_state == NM_DIALUP_STATE_STOPPING)) + && ((old_state == NM_DIALUP_STATE_STARTED) || (old_state == NM_DIALUP_STATE_STARTING)) + && valid_dialup) + { + nm_dialup_act_request_unref (req); + nm_dialup_manager_schedule_dialup_connection_died (service->manager, req); + } + } + } + else if (valid_dialup && dbus_message_is_signal (message, service->service, NM_DBUS_DIALUP_SIGNAL_IP4_CONFIG)) + nm_dialup_service_stage4_ip_config_get (service, req, message); + + return TRUE; +} + +#ifdef NM_DEBUG_DIALUP_CONFIG +/* + * Prints config returned from the service daemo + */ +static void print_dialup_config (guint32 ip4_dialup_gateway, + const char *dev, + guint32 ip4_address, + guint32 ip4_ptp_address, + guint32 ip4_netmask, + guint32 *ip4_dns, + guint32 ip4_dns_len, + guint32 *ip4_nbns, + guint32 ip4_nbns_len) +{ + struct in_addr temp_addr; + guint32 i; + + temp_addr.s_addr = ip4_dialup_gateway; + nm_info ("Dialup Gateway: %s", inet_ntoa (temp_addr)); + nm_info ("Device: %s", dev); + temp_addr.s_addr = ip4_address; + nm_info ("Internal IP4 Address: %s", inet_ntoa (temp_addr)); + temp_addr.s_addr = ip4_netmask; + nm_info ("Internal IP4 Netmask: %s", inet_ntoa (temp_addr)); + temp_addr.s_addr = ip4_ptp_address; + nm_info ("Internal IP4 Point-to-Point Address: %s", inet_ntoa (temp_addr)); + nm_info ("Maximum Segment Size (MSS): %d", mss); + + for (i = 0; i < ip4_dns_len; i++) + { + if (ip4_dns[i] != 0) + { + temp_addr.s_addr = ip4_dns[i]; + nm_info ("Internal IP4 DNS: %s", inet_ntoa (temp_addr)); + } + } + + for (i = 0; i < ip4_nbns_len; i++) + { + if (ip4_nbns[i] != 0) + { + temp_addr.s_addr = ip4_nbns[i]; + nm_info ("Internal IP4 NBNS: %s", inet_ntoa (temp_addr)); + } + } +} + +#endif diff --git a/src/dialup/manager/nm-dialup-service.h b/src/dialup/manager/nm-dialup-service.h new file mode 100644 index 0000000000..b3e723019b --- /dev/null +++ b/src/dialup/manager/nm-dialup-service.h @@ -0,0 +1,61 @@ +/* NetworkManager -- Network link manager + * + * Tim Niemueller [www.niemueller.de] + * based on work by Dan Williams <dcbw@redhat.com> + * + * 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. + * (C) Copyright 2006 Tim Niemueller + */ + +#ifndef NM_DIALUP_SERVICE_H +#define NM_DIALUP_SERVICE_H + + +#include <dbus/dbus.h> +#include "NetworkManager.h" +#include "NetworkManagerDialup.h" +#include "NetworkManagerMain.h" +#include "nm-dialup-connection.h" + +typedef struct NMDialupService NMDialupService; + + +NMDialupService * nm_dialup_service_new (NMDialupManager *manager, NMData *app_data); + +void nm_dialup_service_ref (NMDialupService *service); +void nm_dialup_service_unref (NMDialupService *service); + +const char * nm_dialup_service_get_name (NMDialupService *service); +void nm_dialup_service_set_name (NMDialupService *service, const char *name); + +const char * nm_dialup_service_get_service_name (NMDialupService *service); +void nm_dialup_service_set_service_name (NMDialupService *service, const char *name); + +const char * nm_dialup_service_get_program (NMDialupService *service); +void nm_dialup_service_set_program (NMDialupService *service, const char *program); + +DBusConnection* nm_dialup_service_get_dbus_connection (NMDialupService *service); + +NMDialupState nm_dialup_service_get_state (NMDialupService *service); + +gboolean nm_dialup_service_name_owner_changed (NMDialupService *service, NMDialupActRequest *req, const char *old, const char *new); +gboolean nm_dialup_service_process_signal (NMDialupService *service, NMDialupActRequest *req, DBusMessage *message); + +void nm_dialup_service_start_connection (NMDialupService *service, NMDialupActRequest *req); +void nm_dialup_service_stop_connection (NMDialupService *service, NMDialupActRequest *req); + +#endif |