Terminate any openvpn processes that fail to stop

Sometimes gracefully stopping openvpn fails leaving the
process running in background. This causes restarting of
connections to fail until those processes are manually killed.

- Read process ID from interactive service to get process
  handle when openvpn is started by the service.
- Add a last resort method to forcefully terminate openvpn
  process that fails to exit aftier sending stop signal. Terminate
  is triggered after a 3 second timeout following Stop.

Signed-off-by: Selva Nair <selva.nair@gmail.com>
pull/86/head
Selva Nair 9 years ago
parent 9892d5813f
commit fcd0efa479

@ -296,4 +296,7 @@
/* Save password related messages */ /* Save password related messages */
#define IDS_NFO_DELETE_PASS 2001 #define IDS_NFO_DELETE_PASS 2001
/* Timer IDs */
#define IDT_STOP_TIMER 2500 /* Timer used to trigger force termination */
#endif #endif

@ -54,6 +54,9 @@
extern options_t o; extern options_t o;
static BOOL
TerminateOpenVPN(connection_t *c);
const TCHAR *cfgProp = _T("conn"); const TCHAR *cfgProp = _T("conn");
typedef struct { typedef struct {
@ -719,6 +722,7 @@ static void
OnService(connection_t *c, UNUSED char *msg) OnService(connection_t *c, UNUSED char *msg)
{ {
DWORD err = 0; DWORD err = 0;
DWORD pid = 0;
WCHAR *p, *buf, *next; WCHAR *p, *buf, *next;
DWORD len; DWORD len;
const WCHAR *prefix = L"IService> "; const WCHAR *prefix = L"IService> ";
@ -735,6 +739,17 @@ OnService(connection_t *c, UNUSED char *msg)
} }
p = buf + 11; p = buf + 11;
if (!err && swscanf (p, L"0x%08x\nProcess ID", &pid) == 1 && pid != 0)
{
PrintDebug (L"Process ID of openvpn started by IService: %d", pid);
c->hProcess = OpenProcess (PROCESS_TERMINATE|PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!c->hProcess)
PrintDebug (L"Failed to get process handle from pid of openvpn: error = %lu",
GetLastError());
free (buf);
return;
}
while (iswspace(*p)) ++p; while (iswspace(*p)) ++p;
while (p && *p) while (p && *p)
@ -796,10 +811,11 @@ Cleanup (connection_t *c)
if (c->hProcess) if (c->hProcess)
CloseHandle (c->hProcess); CloseHandle (c->hProcess);
else
CloseServiceIO (&c->iserv);
c->hProcess = NULL; c->hProcess = NULL;
if (c->iserv.hEvent)
CloseServiceIO (&c->iserv);
if (c->exit_event) if (c->exit_event)
CloseHandle (c->exit_event); CloseHandle (c->exit_event);
c->exit_event = NULL; c->exit_event = NULL;
@ -931,6 +947,7 @@ StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
SetMenuStatus(c, disconnecting); SetMenuStatus(c, disconnecting);
SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM)); SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
SetEvent(c->exit_event); SetEvent(c->exit_event);
SetTimer(hwndDlg, IDT_STOP_TIMER, 3000, NULL);
break; break;
case WM_OVPN_SUSPEND: case WM_OVPN_SUSPEND:
@ -941,6 +958,18 @@ StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
SetMenuStatus(c, disconnecting); SetMenuStatus(c, disconnecting);
SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM)); SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
SetEvent(c->exit_event); SetEvent(c->exit_event);
SetTimer(hwndDlg, IDT_STOP_TIMER, 3000, NULL);
break;
case WM_TIMER:
PrintDebug(L"WM_TIMER message with wParam = %lu", wParam);
c = (connection_t *) GetProp(hwndDlg, cfgProp);
if (wParam == IDT_STOP_TIMER)
{
/* openvpn failed to respond to stop signal -- terminate */
TerminateOpenVPN(c);
KillTimer (hwndDlg, IDT_STOP_TIMER);
}
break; break;
} }
return FALSE; return FALSE;
@ -979,7 +1008,7 @@ ThreadOpenVPNStatus(void *p)
PostMessage(c->hwndStatus, WM_CLOSE, 0, 0); PostMessage(c->hwndStatus, WM_CLOSE, 0, 0);
/* Start the async read loop for service and set it as the wait event */ /* Start the async read loop for service and set it as the wait event */
if (!c->hProcess) if (c->iserv.hEvent)
{ {
HandleServiceIO (0, 0, (LPOVERLAPPED) &c->iserv); HandleServiceIO (0, 0, (LPOVERLAPPED) &c->iserv);
wait_event = c->iserv.hEvent; wait_event = c->iserv.hEvent;
@ -999,9 +1028,9 @@ ThreadOpenVPNStatus(void *p)
if ((res = MsgWaitForMultipleObjectsEx (1, &wait_event, INFINITE, QS_ALLINPUT, if ((res = MsgWaitForMultipleObjectsEx (1, &wait_event, INFINITE, QS_ALLINPUT,
MWMO_ALERTABLE)) == WAIT_OBJECT_0) MWMO_ALERTABLE)) == WAIT_OBJECT_0)
{ {
if (c->hProcess) if (wait_event == c->hProcess)
OnProcess (c, NULL); OnProcess (c, NULL);
else else if (wait_event == c->iserv.hEvent)
OnService (c, NULL); OnService (c, NULL);
} }
continue; continue;
@ -1224,6 +1253,33 @@ StopOpenVPN(connection_t *c)
PostMessage(c->hwndStatus, WM_OVPN_STOP, 0, 0); PostMessage(c->hwndStatus, WM_OVPN_STOP, 0, 0);
} }
/* force-kill as a last resort */
static BOOL
TerminateOpenVPN (connection_t *c)
{
DWORD exit_code = 0;
BOOL retval = TRUE;
if (!c->hProcess)
return retval;
if (!GetExitCodeProcess (c->hProcess, &exit_code))
{
PrintDebug (L"In TerminateOpenVPN: failed to get process status: error = %lu", GetLastError());
return FALSE;
}
if (exit_code == STILL_ACTIVE)
{
retval = TerminateProcess (c->hProcess, 1);
if (retval)
PrintDebug (L"Openvpn Process for config '%s' terminated", c->config_name);
else
PrintDebug (L"Failed to terminate openvpn Process for config '%s'", c->config_name);
}
else
PrintDebug(L"In TerminateOpenVPN: Process is not active");
return retval;
}
void void
SuspendOpenVPN(int config) SuspendOpenVPN(int config)

Loading…
Cancel
Save