cli: show progress in --pretty mode for 'nmcli con up'
We need to use a workaround for VPN connection state. There is a bug somewhere causing that vpn-state-changed signal is not issued on active VPN connection. Debugging showed that D-Bus PropertiesChanged and VpnStateChanged signals are not processed properly. That's why libnm-glib's VPN connection object is not updated. The issue may lie in libnm-glib or even in dbus-glib. I wasn't able to get VpnStateChanged signal via dbus-glib (dbus_g_proxy_add_signal() and dbus_g_proxy_connect_signal()), however received the signal successfully using GDBus. Until the issue is analyzed and fixed, we need to ask for VPN state of active VPN connection every second in order to show progress and exit correctly.
This commit is contained in:
@@ -178,6 +178,7 @@ typedef struct {
|
||||
extern GMainLoop *loop;
|
||||
|
||||
static ArgsInfo args_info;
|
||||
static guint progress_id = 0; /* ID of event source for displaying progress */
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
@@ -210,6 +211,11 @@ static const char *real_con_commands[] = {
|
||||
static void
|
||||
quit (void)
|
||||
{
|
||||
if (progress_id) {
|
||||
g_source_remove (progress_id);
|
||||
nmc_terminal_erase_line ();
|
||||
}
|
||||
|
||||
g_main_loop_quit (loop); /* quit main loop */
|
||||
}
|
||||
|
||||
@@ -1336,10 +1342,12 @@ active_connection_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpoin
|
||||
|
||||
state = nm_active_connection_get_state (active);
|
||||
|
||||
printf (_("state: %s\n"), active_connection_state_to_string (state));
|
||||
|
||||
if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
|
||||
printf (_("Connection activated\n"));
|
||||
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
||||
nmc_terminal_erase_line ();
|
||||
printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
|
||||
nm_object_get_path (NM_OBJECT (active)));
|
||||
}
|
||||
quit ();
|
||||
} else if (state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
|
||||
g_string_printf (nmc->return_text, _("Error: Connection activation failed."));
|
||||
@@ -1361,17 +1369,22 @@ vpn_connection_state_cb (NMVPNConnection *vpn,
|
||||
case NM_VPN_CONNECTION_STATE_NEED_AUTH:
|
||||
case NM_VPN_CONNECTION_STATE_CONNECT:
|
||||
case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
|
||||
printf (_("state: %s (%d)\n"), vpn_connection_state_to_string (state), state);
|
||||
/* no operation */
|
||||
break;
|
||||
|
||||
case NM_VPN_CONNECTION_STATE_ACTIVATED:
|
||||
printf (_("Connection activated\n"));
|
||||
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
||||
nmc_terminal_erase_line ();
|
||||
printf (_("VPN connection successfully activated (D-Bus active path: %s)\n"),
|
||||
nm_object_get_path (NM_OBJECT (vpn)));
|
||||
}
|
||||
quit ();
|
||||
break;
|
||||
|
||||
case NM_VPN_CONNECTION_STATE_FAILED:
|
||||
case NM_VPN_CONNECTION_STATE_DISCONNECTED:
|
||||
g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s."), vpn_connection_state_reason_to_string (reason));
|
||||
g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s."),
|
||||
vpn_connection_state_reason_to_string (reason));
|
||||
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
|
||||
quit ();
|
||||
break;
|
||||
@@ -1381,6 +1394,85 @@ vpn_connection_state_cb (NMVPNConnection *vpn,
|
||||
}
|
||||
}
|
||||
|
||||
/* --- VPN state workaround BEGIN --- */
|
||||
static NMVPNConnectionState
|
||||
dbus_get_vpn_state (const char *path)
|
||||
{
|
||||
DBusGConnection *connection;
|
||||
DBusGProxy *proxy;
|
||||
GError *error = NULL;
|
||||
GValue value = {0,};
|
||||
NMVPNConnectionState state = NM_VPN_CONNECTION_STATE_UNKNOWN;
|
||||
|
||||
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
|
||||
proxy = dbus_g_proxy_new_for_name (connection,
|
||||
NM_DBUS_SERVICE,
|
||||
path,
|
||||
"org.freedesktop.DBus.Properties");
|
||||
if (!proxy) {
|
||||
g_warning ("%s: couldn't create D-Bus object proxy.", __func__);
|
||||
dbus_g_connection_unref (connection);
|
||||
return NM_VPN_CONNECTION_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Get VpnState property for object 'path' through D-Bus Get() call. */
|
||||
if (dbus_g_proxy_call (proxy,
|
||||
"Get", &error,
|
||||
G_TYPE_STRING, NM_DBUS_INTERFACE_VPN_CONNECTION,
|
||||
G_TYPE_STRING, "VpnState",
|
||||
G_TYPE_INVALID,
|
||||
G_TYPE_VALUE, &value, G_TYPE_INVALID)) {
|
||||
|
||||
state = g_value_get_uint (&value);
|
||||
} else {
|
||||
g_warning ("Error in getting active connection 'Vpn' property: (%d) %s",
|
||||
error->code, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (proxy);
|
||||
dbus_g_connection_unref (connection);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
NmCli *nmc;
|
||||
NMVPNConnection *vpn;
|
||||
} VpnGetStateInfo;
|
||||
|
||||
static gboolean
|
||||
get_vpn_state_cb (gpointer user_data)
|
||||
{
|
||||
VpnGetStateInfo *info = (VpnGetStateInfo *) user_data;
|
||||
NmCli *nmc = info->nmc;
|
||||
NMVPNConnection *vpn = info->vpn;
|
||||
NMVPNConnectionState state;
|
||||
|
||||
if (!NM_IS_OBJECT (vpn)) {
|
||||
/* Active connection failed and dissapeared, quit. */
|
||||
g_string_printf (nmc->return_text, _("Error: Connection activation failed."));
|
||||
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
|
||||
quit ();
|
||||
g_free (info);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
state = dbus_get_vpn_state (nm_object_get_path (NM_OBJECT (vpn)));
|
||||
|
||||
vpn_connection_state_cb (vpn, state, NM_VPN_CONNECTION_STATE_REASON_UNKNOWN, nmc);
|
||||
|
||||
if ( state == NM_VPN_CONNECTION_STATE_ACTIVATED
|
||||
|| state == NM_VPN_CONNECTION_STATE_FAILED
|
||||
|| state == NM_VPN_CONNECTION_STATE_DISCONNECTED) {
|
||||
|
||||
g_free (info);
|
||||
return FALSE;
|
||||
} else
|
||||
return TRUE;
|
||||
}
|
||||
/* --- VPN state workaround END --- */
|
||||
|
||||
static gboolean
|
||||
timeout_cb (gpointer user_data)
|
||||
{
|
||||
@@ -1394,10 +1486,58 @@ timeout_cb (gpointer user_data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
progress_cb (gpointer user_data)
|
||||
{
|
||||
const char *str = (const char *) user_data;
|
||||
|
||||
nmc_terminal_show_progress (str);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
progress_device_cb (gpointer user_data)
|
||||
{
|
||||
NMDevice *device = (NMDevice *) user_data;
|
||||
|
||||
nmc_terminal_show_progress (device ? nmc_device_state_to_string (nm_device_get_state (device)) : "");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
progress_vpn_cb (gpointer user_data)
|
||||
{
|
||||
NMVPNConnection *vpn = (NMVPNConnection *) user_data;
|
||||
const char *str;
|
||||
|
||||
/* VPN state workaround */
|
||||
#if 0
|
||||
str = NM_IS_VPN_CONNECTION (vpn) ?
|
||||
vpn_connection_state_to_string (nm_vpn_connection_get_vpn_state (vpn)) :
|
||||
"";
|
||||
#endif
|
||||
str = NM_IS_OBJECT (vpn) ?
|
||||
vpn_connection_state_to_string (dbus_get_vpn_state (nm_object_get_path (NM_OBJECT (vpn)))) :
|
||||
"";
|
||||
|
||||
nmc_terminal_show_progress (str);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
NmCli *nmc;
|
||||
NMDevice *device;
|
||||
} ActivateConnectionInfo;
|
||||
|
||||
static void
|
||||
activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *error, gpointer user_data)
|
||||
{
|
||||
NmCli *nmc = (NmCli *) user_data;
|
||||
ActivateConnectionInfo *info = (ActivateConnectionInfo *) user_data;
|
||||
NmCli *nmc = info->nmc;
|
||||
NMDevice *device = info->device;
|
||||
NMActiveConnectionState state;
|
||||
|
||||
if (error) {
|
||||
@@ -1407,27 +1547,61 @@ activate_connection_cb (NMClient *client, NMActiveConnection *active, GError *er
|
||||
} else {
|
||||
state = nm_active_connection_get_state (active);
|
||||
|
||||
printf (_("Active connection state: %s\n"), active_connection_state_to_string (state));
|
||||
printf (_("Active connection path: %s\n"), nm_object_get_path (NM_OBJECT (active)));
|
||||
|
||||
if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
|
||||
/* don't want to wait or already activated */
|
||||
/* User doesn't want to wait or already activated */
|
||||
if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED && nmc->print_output == NMC_PRINT_PRETTY) {
|
||||
printf (_("Connection successfully activated (D-Bus active path: %s)\n"),
|
||||
nm_object_get_path (NM_OBJECT (active)));
|
||||
}
|
||||
quit ();
|
||||
} else {
|
||||
if (NM_IS_VPN_CONNECTION (active))
|
||||
g_signal_connect (NM_VPN_CONNECTION (active), "vpn-state-changed", G_CALLBACK (vpn_connection_state_cb), nmc);
|
||||
else
|
||||
if (NM_IS_VPN_CONNECTION (active)) {
|
||||
VpnGetStateInfo *vpn_info;
|
||||
|
||||
/* Monitor VPN state */
|
||||
g_signal_connect (G_OBJECT (active), "vpn-state-changed", G_CALLBACK (vpn_connection_state_cb), nmc);
|
||||
|
||||
/* Start progress indication showing VPN states */
|
||||
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
||||
if (progress_id)
|
||||
g_source_remove (progress_id);
|
||||
progress_id = g_timeout_add (120, progress_vpn_cb, NM_VPN_CONNECTION (active));
|
||||
}
|
||||
|
||||
/* --- workaround BEGIN --- */
|
||||
/* There is a bug in libnm-glib or dbus-glib - 'vpn-state-changed' signal
|
||||
* is never issued. After inspection it appears that PropertiesChanged and
|
||||
* VpnStateChanged D-Bus signals are not processed, even if they are seen
|
||||
* on D-Bus (checked via dbus-monitor). Until the bug is identified and
|
||||
* fixed, we check the VPN state every second.
|
||||
*/
|
||||
vpn_info = g_malloc0 (sizeof (VpnGetStateInfo));
|
||||
vpn_info->nmc = nmc;
|
||||
vpn_info->vpn = NM_VPN_CONNECTION (active);
|
||||
g_timeout_add_seconds (1, get_vpn_state_cb, vpn_info);
|
||||
/* --- workaround END --- */
|
||||
} else {
|
||||
g_signal_connect (active, "notify::state", G_CALLBACK (active_connection_state_cb), nmc);
|
||||
|
||||
/* Start progress indication showing device states */
|
||||
if (nmc->print_output == NMC_PRINT_PRETTY) {
|
||||
if (progress_id)
|
||||
g_source_remove (progress_id);
|
||||
progress_id = g_timeout_add (120, progress_device_cb, device);
|
||||
}
|
||||
}
|
||||
|
||||
/* Start timer not to loop forever when signals are not emitted */
|
||||
g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
|
||||
}
|
||||
}
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
static NMCResultCode
|
||||
do_connection_up (NmCli *nmc, int argc, char **argv)
|
||||
{
|
||||
ActivateConnectionInfo *info;
|
||||
NMDevice *device = NULL;
|
||||
const char *spec_object = NULL;
|
||||
gboolean device_found;
|
||||
@@ -1566,12 +1740,21 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
|
||||
*/
|
||||
nmc->nowait_flag = !wait;
|
||||
nmc->should_wait = TRUE;
|
||||
|
||||
info = g_malloc0 (sizeof (ActivateConnectionInfo));
|
||||
info->nmc = nmc;
|
||||
info->device = device;
|
||||
|
||||
nm_client_activate_connection (nmc->client,
|
||||
connection,
|
||||
device,
|
||||
spec_object,
|
||||
activate_connection_cb,
|
||||
nmc);
|
||||
info);
|
||||
|
||||
/* Start progress indication */
|
||||
if (nmc->print_output == NMC_PRINT_PRETTY)
|
||||
progress_id = g_timeout_add (120, progress_cb, "preparing");
|
||||
|
||||
return nmc->return_value;
|
||||
error:
|
||||
|
Reference in New Issue
Block a user