Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support sending multiple commands to a running instance #502

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ it using the command line interface using the following syntax::

openvpn-gui.exe --command *cmd* [*args*]

Or::

openvpn-gui.exe --cmd [*args*]

Currently supported *cmds* are

connect ``config-name``
Expand All @@ -163,6 +167,10 @@ reconnect ``config-name``
Disconnect and then reconnect the configuration named *config-name*
if connected.

status ``config-name``
Show the status window of the configuration named *config-name*
if connected or is in the process of connecting.

disconnect\_all
Disconnect all active connections.

Expand All @@ -178,9 +186,10 @@ rescan
import ``path``
Import the config file pointed to by ``path``.

If no running instance of the GUI is found, these commands do nothing
except for *--command connect config-name* which gets interpreted
as *--connect config-name*
If no running instance of the GUI is found, these commands have no
effect except for *connect*, *import*, and *silent_connection* which
get interpreted resepctively as *--connect*, *--import*, and
*--silent_connection*.

Registry Values affecting the OpenVPN GUI operation
***************************************************
Expand Down
72 changes: 43 additions & 29 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ VerifyAutoConnections()
* to the running instance and return success or error.
*/
static int
NotifyRunningInstance()
NotifyRunningInstance(int action_type, wchar_t *action_arg)
{
/* Check if a previous instance has a window initialized
* Even if we are not the first instance this may return null
Expand All @@ -110,22 +110,16 @@ NotifyRunningInstance()
int exit_code = 0;
if (hwnd_master)
{
/* GUI up and running -- send a message if any action is pecified,
else show the balloon */
/* GUI up and running -- send a message for the specified action */
COPYDATASTRUCT config_data = {0};
int timeout = 30*1000; /* 30 seconds */
if (!o.action)
config_data.dwData = action_type;
if (action_arg)
{
o.action = WM_OVPN_NOTIFY;
o.action_arg = LoadLocalizedString(IDS_NFO_CLICK_HERE_TO_START);
config_data.cbData = (wcslen(action_arg)+1)*sizeof(action_arg[0]);
config_data.lpData = (void *) action_arg;
}
config_data.dwData = o.action;
if (o.action_arg)
{
config_data.cbData = (wcslen(o.action_arg)+1)*sizeof(o.action_arg[0]);
config_data.lpData = (void *) o.action_arg;
}
PrintDebug(L"Instance 2: called with action %d : %ls", o.action, o.action_arg);
PrintDebug(L"Instance 2: called with action %d : %ls", action_type, action_arg);
if (!SendMessageTimeout (hwnd_master, WM_COPYDATA, 0,
(LPARAM) &config_data, 0, timeout, NULL))
{
Expand Down Expand Up @@ -245,23 +239,40 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance,

if (!first_instance)
{
int res = NotifyRunningInstance();
exit(res);
}
else if (o.action == WM_OVPN_START)
{
PrintDebug(L"Instance 1: Called with --command connect xxx. Treating it as --connect xxx");
}
else if (o.action == WM_OVPN_IMPORT)
{
; /* pass -- import is handled after Window initialization */
int exit_code = 0;
struct action *a = o.action_list.head;
if (!a) /* no actions -- send a balloon notification */
{
exit_code = NotifyRunningInstance(WM_OVPN_NOTIFY,
LoadLocalizedString(IDS_NFO_CLICK_HERE_TO_START));
}
else while (a)
{
int res = NotifyRunningInstance(a->type, a->arg);
exit_code = res > exit_code ? res : exit_code;
a = a->next;
}
exit(exit_code);
}
else if (o.action)
else
{
MsgToEventLog(EVENTLOG_ERROR_TYPE, L"Called with --command when no previous instance available");
exit(OVPN_EXITCODE_ERROR);
for (struct action *a = o.action_list.head; a; a = a->next)
{
if (a->type == WM_OVPN_START || a->type == WM_OVPN_SILENT)
{
; /* pass these could get set by --connect or --silent_connection */
}
else if (a->type == WM_OVPN_IMPORT)
{
; /* pass -- import is handled after Window initialization */
}
else
{
/* log an error, but do not treat as fatal */
MsgToEventLog(EVENTLOG_ERROR_TYPE, L"Called with options relevant only when a previous instance is available (action type = %d arg = %s", a->type, a->arg ? a->arg : L"");
}
}
}

if (!CheckVersion()) {
exit(1);
}
Expand Down Expand Up @@ -528,9 +539,12 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
CheckServiceStatus(); // Check if service is running or not

/* if '--import' was specified, do it now */
if (o.action == WM_OVPN_IMPORT && o.action_arg)
for (struct action *a = o.action_list.head; a ; a = a->next)
{
ImportConfigFile(o.action_arg, true); /* prompt user */
if (a->type == WM_OVPN_IMPORT && a->arg)
{
ImportConfigFile(a->arg, true); /* prompt user */
}
}

if (!AutoStartConnections()) {
Expand Down
142 changes: 84 additions & 58 deletions options.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <shlobj.h>
#include <shlwapi.h>
#include <combaseapi.h>
#include <assert.h>

#include "options.h"
#include "main.h"
Expand Down Expand Up @@ -81,9 +82,48 @@ ExpandOptions (void)
ExpandString (o.install_path, _countof(o.install_path));
}

static void
add_action(struct action_list *al, DWORD type, wchar_t *arg)
{
struct action *a = calloc(sizeof(*a), 1);
if (!a)
{
ErrorExit(1, L"Out of memory while parsing command line");
}
a->type = type;
a->arg = arg;
if (!al->head) /* first entry */
{
al->head = a;
}
else
{
assert(al->tail);
al->tail->next = a;
}
al->tail = a;
}

/* action commands that could be sent to a running instance */
static const wchar_t *valid_cmds[] =
{
L"connect",
L"disconnect",
L"reconnect",
L"disconnect_all",
L"status",
L"exit",
L"import",
L"silent_connection",
L"rescan",

NULL /* last entry */
};

static int
add_option(options_t *options, int i, TCHAR **p)
{
struct action_list *al = &options->action_list;
if (streq(p[0], _T("help")))
{
TCHAR caption[200];
Expand Down Expand Up @@ -112,23 +152,18 @@ add_option(options_t *options, int i, TCHAR **p)
options->auto_connect = tmp;
}
options->auto_connect[options->num_auto_connect++] = p[1];
/* Treat the first connect option to also mean --command connect profile.
/* Treat connect option to also mean --command connect profile.
* This gets used if we are not the first instance.
*/
if (options->num_auto_connect == 1)
{
options->action = WM_OVPN_START;
options->action_arg = p[1];
}
add_action(al, WM_OVPN_START, p[1]);
}
else if (streq(p[0], L"import") && p[1])
{
++i;
/* This is interpreted directly or as a command depending
* on we are the first instance or not. So, set as an action.
*/
options->action = WM_OVPN_IMPORT;
options->action_arg = p[1];
add_action(al, WM_OVPN_IMPORT, p[1]);
}
else if (streq(p[0], _T("exe_path")) && p[1])
{
Expand Down Expand Up @@ -215,6 +250,8 @@ add_option(options_t *options, int i, TCHAR **p)
{
++i;
options->silent_connection = _ttoi(p[1]) ? 1 : 0;
/* also interpreted by a second instance */
add_action(al, WM_OVPN_SILENT, p[1]);
}
else if (streq(p[0], _T("passphrase_attempts")) && p[1])
{
Expand Down Expand Up @@ -243,63 +280,52 @@ add_option(options_t *options, int i, TCHAR **p)
}
else if (streq(p[0], _T("command")) && p[1])
{
++i;
/* command to be sent to a running instance */
if (streq(p[1], _T("connect")) && p[2])
{
/* Treat this as "--connect profile" in case this is the first instance */
add_option(options, i, &p[1]);
++i;
options->action = WM_OVPN_START;
options->action_arg = p[2];
}
else if (streq(p[1], _T("disconnect")) && p[2])
{
++i;
options->action = WM_OVPN_STOP;
options->action_arg = p[2];
}
else if (streq(p[1], _T("reconnect")) && p[2])
{
++i;
options->action = WM_OVPN_RESTART;
options->action_arg = p[2];
}
else if (streq(p[1], _T("status")) && p[2])
int found = 0;
for (int k = 0; valid_cmds[k] && !found; k++)
{
++i;
options->action = WM_OVPN_SHOWSTATUS;
options->action_arg = p[2];
found = streq(valid_cmds[k], p[1]);
}
else if (streq(p[1], L"import") && p[2])
{
++i;
options->action = WM_OVPN_IMPORT;
options->action_arg = p[2];
}
else if (streq(p[1], _T("silent_connection")))
{
++i;
options->action = WM_OVPN_SILENT;
options->action_arg = p[2] ? p[2] : _T("1");
}
else if (streq(p[1], _T("disconnect_all")))
{
options->action = WM_OVPN_STOPALL;
}
else if (streq(p[1], _T("exit")))
{
options->action = WM_OVPN_EXIT;
}
else if (streq(p[1], _T("rescan")))
{
options->action = WM_OVPN_RESCAN;
}
else
if (!found)
{
ShowLocalizedMsg(IDS_ERR_BAD_OPTION, p[0]);
exit(1);
}
++i;
i = add_option(options, i, &p[1]);
}
else if (streq(p[0], _T("disconnect")) && p[1])
{
++i;
/* this option is handled only as an action passed by a second instance */
add_action(al, WM_OVPN_STOP, p[1]);
}
else if (streq(p[0], _T("reconnect")) && p[1])
{
++i;
/* this option is handled only as an action passed by a second instance */
add_action(al, WM_OVPN_RESTART, p[1]);
}
else if (streq(p[0], _T("status")) && p[1])
{
++i;
/* this option is handled only as an action passed by a second instance */
add_action(al, WM_OVPN_SHOWSTATUS, p[1]);
}
else if (streq(p[0], _T("disconnect_all")))
{
/* this option is handled only as an action passed by a second instance */
add_action(al, WM_OVPN_STOPALL, NULL);
}
else if (streq(p[0], _T("exit")))
{
/* this option is handled only as an action passed by a second instance */
add_action(al, WM_OVPN_EXIT, NULL);
}
else if (streq(p[0], _T("rescan")))
{
/* this option is handled only as an action passed by a second instance */
add_action(al, WM_OVPN_RESCAN, NULL);
}
else if (streq(p[0], _T("popup_mute_interval")) && p[1])
{
Expand Down
14 changes: 12 additions & 2 deletions options.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ struct connection {
struct echo_msg echo_msg; /* Message echo-ed from server or client config and related data */
};

/* Command actions to be send to running instance */
struct action {
int type;
wchar_t *arg;
struct action *next;
};

struct action_list {
struct action *head, *tail;
};

/* All options used within OpenVPN GUI */
typedef struct {
/* Array of configs to autostart */
Expand Down Expand Up @@ -223,8 +234,7 @@ typedef struct {
unsigned int dpi_scale;
COLORREF clr_warning;
COLORREF clr_error;
int action; /* action to send to a running instance */
TCHAR *action_arg;
struct action_list action_list; /* list of actions to send to a running instance */
HANDLE session_semaphore;
HANDLE event_log;
} options_t;
Expand Down
3 changes: 3 additions & 0 deletions res/openvpn-gui-res-cs.rc
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,10 @@ Supported commands:\n\
status cnn \t\t: show the status window of config ""cnn"" if connected\n\
silent_connection [0|1]\t: set the silent_connection flag on (1) or off (0)\n\
import path \t\t: Import the config file pointed to by path\n\
rescan \t\t: Rescan config directories for config files\n\
\t\t\tExample: openvpn-gui.exe --command disconnect myconfig\n\
As a shortcut, --command cmd may be simplified to --cmd\n\
e.g., --exit is the same as --command exit.\n\
\n\
Volby k použití explicitního nastavení namísto výchozího z registru:\n\
--exe_path\t\t: Cesta k openvpn.exe.\n\
Expand Down
3 changes: 3 additions & 0 deletions res/openvpn-gui-res-de.rc
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,10 @@ Unterstützte Befehle:\n\
status cnn \t\t: Zeige das Satusfenster der Konfiguration ""cnn"", falls verbunden\n\
silent_connection [0|1]\t: Schalte die silent_connection-Option ein (1) oder aus (0)\n\
import path \t\t: Import the config file pointed to by path\n\
rescan \t\t: Rescan config directories for config files\n\
\t\t\tExample: openvpn-gui.exe --command disconnect myconfig\n\
As a shortcut, --command cmd may be simplified to --cmd\n\
e.g., --exit is the same as --command exit.\n\
\n\
Option zum Überschreiben der Registry Einstellungen:\n\
--exe_path\t\t: Pfad zu openvpn.exe.\n\
Expand Down
Loading