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 <selva.nair@gmail.com>
pull/608/head
Selva Nair 2023-01-10 17:29:44 -05:00
parent 141a687ddd
commit 2b1e5867f0
9 changed files with 78 additions and 24 deletions

9
main.c
View File

@ -376,13 +376,16 @@ StopAllOpenVPN()
} }
} }
/* Wait for all connections to terminate (Max 5 sec) */ /* Wait for all connections to terminate (Max 20 rounds of 250 msec = 5 sec) */
for (i = 0; i < 20; i++, Sleep(250)) for (i = 0; i < 20; i++)
{
if (CountConnState(disconnected) + CountConnState(detached) == o.num_configs
|| !OVPNMsgWait(250, NULL)) /* Quit received */
{ {
if (CountConnState(disconnected) + CountConnState(detached) == o.num_configs)
break; break;
} }
} }
}
static int static int

2
main.h
View File

@ -65,6 +65,8 @@
#define WM_OVPN_STATE (WM_APP + 23) #define WM_OVPN_STATE (WM_APP + 23)
#define WM_OVPN_DETACH (WM_APP + 24) #define WM_OVPN_DETACH (WM_APP + 24)
#define MSGF_OVPN_WAIT (MSGF_USER + 1)
/* bool definitions */ /* bool definitions */
#define bool int #define bool int
#define true 1 #define true 1

View File

@ -345,7 +345,7 @@ OnManagement(SOCKET sk, LPARAM lParam)
else if (strncmp(pos, "INFO:", 5) == 0) else if (strncmp(pos, "INFO:", 5) == 0)
{ {
/* delay until management interface accepts input */ /* delay until management interface accepts input */
Sleep(100); OVPNMsgWait(100, c->hwndStatus);
c->manage.connected = 2; c->manage.connected = 2;
if (rtmsg_handler[ready_]) if (rtmsg_handler[ready_])
rtmsg_handler[ready_](c, pos + 5); rtmsg_handler[ready_](c, pos + 5);

36
misc.c
View File

@ -1046,3 +1046,39 @@ RunAsAdmin(const WCHAR *cmd, const WCHAR *params)
} }
return status; 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;
}

9
misc.h
View File

@ -150,4 +150,13 @@ DWORD SetPLAPRegistration(BOOL action);
*/ */
DWORD RunAsAdmin(const WCHAR *cmd, const WCHAR *params); 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 #endif

View File

@ -2753,7 +2753,7 @@ ReadLineFromStdOut(HANDLE hStdOut, char *line, DWORD size)
if (read == size) if (read == size)
return FALSE; return FALSE;
Sleep(100); Sleep(100); /* called when no UI is yet initialized */
} }
if (!ReadFile(hStdOut, line, len, &read, NULL) || read != len) if (!ReadFile(hStdOut, line, len, &read, NULL) || read != len)

View File

@ -30,6 +30,8 @@
#include "resource.h" #include "resource.h"
#include "localization.h" #include "localization.h"
#include "openvpn-gui-res.h" #include "openvpn-gui-res.h"
#include "main.h"
#include "misc.h"
/* A "class" that implements IConnectableCredentialProviderCredential */ /* A "class" that implements IConnectableCredentialProviderCredential */
@ -607,7 +609,7 @@ again:
ConnectHelper(oc->c); ConnectHelper(oc->c);
Sleep(100); OVPNMsgWait(100, NULL);
/* if not immediately connected, show a progress dialog with /* if not immediately connected, show a progress dialog with
* service state changes and retry/cancel options. Progress dialog * service state changes and retry/cancel options. Progress dialog

View File

@ -405,7 +405,7 @@ DetachAllOpenVPN()
{ {
break; break;
} }
Sleep(100); OVPNMsgWait(100, NULL);
} }
for (connection_t *c = o.chead; c; c = c->next) for (connection_t *c = o.chead; c; c = c->next)
@ -481,7 +481,7 @@ DisconnectHelper(connection_t *c)
time_t timeout = time(NULL) + 5; time_t timeout = time(NULL) + 5;
while (timeout > time(NULL) && c->state != onhold && c->state != disconnected) while (timeout > time(NULL) && c->state != onhold && c->state != disconnected)
{ {
Sleep(100); OVPNMsgWait(100, NULL);
} }
ShowWindowAsync(GetDlgItem(c->hwndStatus, ID_DISCONNECT), SW_HIDE); ShowWindowAsync(GetDlgItem(c->hwndStatus, ID_DISCONNECT), SW_HIDE);

View File

@ -94,17 +94,17 @@ RunPreconnectScript(connection_t *c)
NULL, c->config_dir, &si, &pi)) NULL, c->config_dir, &si, &pi))
return; return;
/* Wait process without blocking msg pump */
for (i = 0; i <= (int) o.preconnectscript_timeout; i++) for (i = 0; i <= (int) o.preconnectscript_timeout; i++)
{ {
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) if (!GetExitCodeProcess(pi.hProcess, &exit_code)
goto out; || exit_code != STILL_ACTIVE
|| !OVPNMsgWait(1000, NULL))
if (exit_code != STILL_ACTIVE) {
goto out; break;
Sleep(1000);
} }
out: }
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
if (logfile_handle != NULL) if (logfile_handle != NULL)
@ -180,7 +180,7 @@ RunConnectScript(connection_t *c, int run_as_service)
{ {
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) 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; goto out;
} }
@ -191,7 +191,10 @@ RunConnectScript(connection_t *c, int run_as_service)
goto out; 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); 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++) 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; goto out;
}
if (exit_code != STILL_ACTIVE)
goto out;
Sleep(1000);
} }
out: out:
free(env); free(env);