From 2b1e5867f082c1d5d02a0744b2e93dd828a49c24 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 10 Jan 2023 17:29:44 -0500 Subject: [PATCH] Replace Sleep by a Wait function that pumps messages - The wait function optionally calls IsDialogMessage() if a dialog handle is specified. For other customizations the caller can install a WH_MSGFILTER hook. The hook will get called with nCode = MSGF_OVPN_WAIT and lParam = &msg. - Use this in place of Sleep in main.c, scripts.c and PLAP dll. Fixes #576 Signed-off-by: Selva Nair --- main.c | 9 ++++++--- main.h | 2 ++ manage.c | 2 +- misc.c | 36 ++++++++++++++++++++++++++++++++++++ misc.h | 9 +++++++++ openvpn.c | 2 +- plap/plap_connection.c | 4 +++- plap/ui_glue.c | 4 ++-- scripts.c | 34 ++++++++++++++++++---------------- 9 files changed, 78 insertions(+), 24 deletions(-) diff --git a/main.c b/main.c index 61e593d..0505855 100644 --- a/main.c +++ b/main.c @@ -376,11 +376,14 @@ StopAllOpenVPN() } } - /* Wait for all connections to terminate (Max 5 sec) */ - for (i = 0; i < 20; i++, Sleep(250)) + /* Wait for all connections to terminate (Max 20 rounds of 250 msec = 5 sec) */ + for (i = 0; i < 20; i++) { - if (CountConnState(disconnected) + CountConnState(detached) == o.num_configs) + if (CountConnState(disconnected) + CountConnState(detached) == o.num_configs + || !OVPNMsgWait(250, NULL)) /* Quit received */ + { break; + } } } diff --git a/main.h b/main.h index eda9bea..a5db2cd 100644 --- a/main.h +++ b/main.h @@ -65,6 +65,8 @@ #define WM_OVPN_STATE (WM_APP + 23) #define WM_OVPN_DETACH (WM_APP + 24) +#define MSGF_OVPN_WAIT (MSGF_USER + 1) + /* bool definitions */ #define bool int #define true 1 diff --git a/manage.c b/manage.c index 1830d03..a3e1896 100644 --- a/manage.c +++ b/manage.c @@ -345,7 +345,7 @@ OnManagement(SOCKET sk, LPARAM lParam) else if (strncmp(pos, "INFO:", 5) == 0) { /* delay until management interface accepts input */ - Sleep(100); + OVPNMsgWait(100, c->hwndStatus); c->manage.connected = 2; if (rtmsg_handler[ready_]) rtmsg_handler[ready_](c, pos + 5); diff --git a/misc.c b/misc.c index 2982a53..c1da1e8 100644 --- a/misc.c +++ b/misc.c @@ -1046,3 +1046,39 @@ RunAsAdmin(const WCHAR *cmd, const WCHAR *params) } return status; } + +/* Like sleep but service messages. If hdlg is not NULL + * dialog messages for it are checked. Also services + * MSG_FILTER hooks if caller wants further special processing. + * Returns false on if WM_QUIT received else returns true (on timeout). + */ +bool +OVPNMsgWait(DWORD timeout, HWND hdlg) +{ + ULONGLONG now = GetTickCount64(); + ULONGLONG end = now + timeout; + + while (end > now) + { + if (MsgWaitForMultipleObjectsEx(0, NULL, end - now, QS_ALLINPUT, MWMO_INPUTAVAILABLE) == WAIT_OBJECT_0) + { + MSG msg; + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + PostQuitMessage((int) msg.wParam); + return false; + } + else if (!CallMsgFilter(&msg, MSGF_OVPN_WAIT) + && (!hdlg || !IsDialogMessage(hdlg, &msg))) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + now = GetTickCount64(); + } + return true; +} diff --git a/misc.h b/misc.h index af8bb17..293ee16 100644 --- a/misc.h +++ b/misc.h @@ -150,4 +150,13 @@ DWORD SetPLAPRegistration(BOOL action); */ DWORD RunAsAdmin(const WCHAR *cmd, const WCHAR *params); +/** + * Wait for a timeout while pumping messages. If hdlg is not NULL + * IsDialogMessage(hdlg, ...) is checked before dispatching messages. + * caller can install a WH_MSGFILTER hook if any other special processing + * is necessary. The hook will get called with ncode = MSGF_OVPN_WAIT. + * @returns false if WM_QUIT was received, else returns true on timeout. + */ +bool OVPNMsgWait(DWORD timeout, HWND hdlg); + #endif diff --git a/openvpn.c b/openvpn.c index afdb121..2cbccae 100644 --- a/openvpn.c +++ b/openvpn.c @@ -2753,7 +2753,7 @@ ReadLineFromStdOut(HANDLE hStdOut, char *line, DWORD size) if (read == size) return FALSE; - Sleep(100); + Sleep(100); /* called when no UI is yet initialized */ } if (!ReadFile(hStdOut, line, len, &read, NULL) || read != len) diff --git a/plap/plap_connection.c b/plap/plap_connection.c index 52f790a..132947b 100644 --- a/plap/plap_connection.c +++ b/plap/plap_connection.c @@ -30,6 +30,8 @@ #include "resource.h" #include "localization.h" #include "openvpn-gui-res.h" +#include "main.h" +#include "misc.h" /* A "class" that implements IConnectableCredentialProviderCredential */ @@ -607,7 +609,7 @@ again: ConnectHelper(oc->c); - Sleep(100); + OVPNMsgWait(100, NULL); /* if not immediately connected, show a progress dialog with * service state changes and retry/cancel options. Progress dialog diff --git a/plap/ui_glue.c b/plap/ui_glue.c index 59e466f..3c66ca3 100644 --- a/plap/ui_glue.c +++ b/plap/ui_glue.c @@ -405,7 +405,7 @@ DetachAllOpenVPN() { break; } - Sleep(100); + OVPNMsgWait(100, NULL); } for (connection_t *c = o.chead; c; c = c->next) @@ -481,7 +481,7 @@ DisconnectHelper(connection_t *c) time_t timeout = time(NULL) + 5; while (timeout > time(NULL) && c->state != onhold && c->state != disconnected) { - Sleep(100); + OVPNMsgWait(100, NULL); } ShowWindowAsync(GetDlgItem(c->hwndStatus, ID_DISCONNECT), SW_HIDE); diff --git a/scripts.c b/scripts.c index c3a94d9..fc32c37 100644 --- a/scripts.c +++ b/scripts.c @@ -94,17 +94,17 @@ RunPreconnectScript(connection_t *c) NULL, c->config_dir, &si, &pi)) return; + /* Wait process without blocking msg pump */ for (i = 0; i <= (int) o.preconnectscript_timeout; i++) { - if (!GetExitCodeProcess(pi.hProcess, &exit_code)) - goto out; - - if (exit_code != STILL_ACTIVE) - goto out; - - Sleep(1000); + if (!GetExitCodeProcess(pi.hProcess, &exit_code) + || exit_code != STILL_ACTIVE + || !OVPNMsgWait(1000, NULL)) + { + break; + } } -out: + CloseHandle(pi.hThread); CloseHandle(pi.hProcess); if (logfile_handle != NULL) @@ -180,7 +180,7 @@ RunConnectScript(connection_t *c, int run_as_service) { if (!GetExitCodeProcess(pi.hProcess, &exit_code)) { - ShowLocalizedMsg(IDS_ERR_GET_EXIT_CODE, cmdline); + ShowLocalizedMsgEx(MB_OK|MB_ICONERROR, c->hwndStatus, TEXT(PACKAGE_NAME), IDS_ERR_GET_EXIT_CODE, cmdline); goto out; } @@ -191,7 +191,10 @@ RunConnectScript(connection_t *c, int run_as_service) goto out; } - Sleep(1000); + if (!OVPNMsgWait(1000, c->hwndStatus)) /* WM_QUIT -- do not popup error */ + { + goto out; + } } ShowLocalizedMsgEx(MB_OK|MB_ICONERROR, c->hwndStatus, TEXT(PACKAGE_NAME), IDS_ERR_RUN_CONN_SCRIPT_TIMEOUT, o.connectscript_timeout); @@ -266,13 +269,12 @@ RunDisconnectScript(connection_t *c, int run_as_service) for (i = 0; i <= (int) o.disconnectscript_timeout; i++) { - if (!GetExitCodeProcess(pi.hProcess, &exit_code)) + if (!GetExitCodeProcess(pi.hProcess, &exit_code) + || exit_code != STILL_ACTIVE + || !OVPNMsgWait(1000, c->hwndStatus)) /* WM_QUIT -- do not popup error */ + { goto out; - - if (exit_code != STILL_ACTIVE) - goto out; - - Sleep(1000); + } } out: free(env);